summaryrefslogtreecommitdiff
path: root/drivers/tty/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r--drivers/tty/serial/8250/8250.h9
-rw-r--r--drivers/tty/serial/8250/8250_core.c4
-rw-r--r--drivers/tty/serial/8250/8250_dw.c4
-rw-r--r--drivers/tty/serial/8250/8250_exar.c4
-rw-r--r--drivers/tty/serial/8250/8250_keba.c280
-rw-r--r--drivers/tty/serial/8250/8250_loongson.c238
-rw-r--r--drivers/tty/serial/8250/8250_of.c2
-rw-r--r--drivers/tty/serial/8250/8250_pci.c48
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.c7
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.h2
-rw-r--r--drivers/tty/serial/8250/8250_platform.c55
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c24
-rw-r--r--drivers/tty/serial/8250/Kconfig40
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/ar933x_uart.c62
-rw-r--r--drivers/tty/serial/fsl_lpuart.c8
-rw-r--r--drivers/tty/serial/icom.c9
-rw-r--r--drivers/tty/serial/imx.c24
-rw-r--r--drivers/tty/serial/jsm/jsm_driver.c1
-rw-r--r--drivers/tty/serial/kgdboc.c1
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c178
-rw-r--r--drivers/tty/serial/samsung_tty.c2
-rw-r--r--drivers/tty/serial/sc16is7xx.c413
-rw-r--r--drivers/tty/serial/sc16is7xx.h1
-rw-r--r--drivers/tty/serial/sc16is7xx_i2c.c4
-rw-r--r--drivers/tty/serial/sc16is7xx_spi.c4
-rw-r--r--drivers/tty/serial/serial_core.c168
-rw-r--r--drivers/tty/serial/sh-sci.c196
-rw-r--r--drivers/tty/serial/sh-sci.h178
-rw-r--r--drivers/tty/serial/sprd_serial.c6
-rw-r--r--drivers/tty/serial/xilinx_uartps.c15
34 files changed, 1336 insertions, 667 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index e99f5193d8f1..8caecfc85d93 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -98,15 +98,6 @@ struct serial8250_config {
extern unsigned int nr_uarts;
-#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
-#define SERIAL8250_SHARE_IRQS 1
-#else
-#define SERIAL8250_SHARE_IRQS 0
-#endif
-
-extern unsigned int share_irqs;
-extern unsigned int skip_txen_test;
-
#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
{ \
.iobase = _base, \
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index bfa421ab3253..0e81f78c6063 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -52,6 +52,10 @@ struct irq_info {
static DEFINE_HASHTABLE(irq_lists, IRQ_HASH_BITS);
static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */
+static bool skip_txen_test;
+module_param(skip_txen_test, bool, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
/*
* This is the serial driver's interrupt routine.
*
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 710ae4d40aec..27af83f0ff46 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -361,7 +361,7 @@ static int dw8250_clk_notifier_cb(struct notifier_block *nb,
* deferred event handling complication.
*/
if (event == POST_RATE_CHANGE) {
- queue_work(system_unbound_wq, &d->clk_work);
+ queue_work(system_dfl_wq, &d->clk_work);
return NOTIFY_OK;
}
@@ -680,7 +680,7 @@ static int dw8250_probe(struct platform_device *pdev)
err = clk_notifier_register(data->clk, &data->clk_notifier);
if (err)
return dev_err_probe(dev, err, "Failed to set the clock notifier\n");
- queue_work(system_unbound_wq, &data->clk_work);
+ queue_work(system_dfl_wq, &data->clk_work);
}
platform_set_drvdata(pdev, data);
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index b9cc0b786ca6..c682c0d0dffa 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -505,7 +505,7 @@ static int default_setup(struct exar8250 *priv, struct pci_dev *pcidev,
unsigned char status;
int err;
- err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift);
+ err = serial8250_pci_setup_port(pcidev, port, 0, offset, board->reg_shift, priv->virt);
if (err)
return err;
@@ -833,7 +833,7 @@ static int cti_port_setup_common(struct exar8250 *priv,
port->port.port_id = idx;
port->port.uartclk = priv->osc_freq;
- ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0);
+ ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0, priv->virt);
if (ret)
return ret;
diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c
new file mode 100644
index 000000000000..c05b89551b12
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_keba.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 KEBA Industrial Automation GmbH
+ *
+ * Driver for KEBA UART FPGA IP core
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/misc/keba.h>
+#include <linux/module.h>
+
+#include "8250.h"
+
+#define KUART "kuart"
+
+/* flags */
+#define KUART_RS485 BIT(0)
+#define KUART_USE_CAPABILITY BIT(1)
+
+/* registers */
+#define KUART_VERSION 0x0000
+#define KUART_REVISION 0x0001
+#define KUART_CAPABILITY 0x0002
+#define KUART_CONTROL 0x0004
+#define KUART_BASE 0x000C
+#define KUART_REGSHIFT 2
+#define KUART_CLK 1843200
+
+/* mode flags */
+enum kuart_mode {
+ KUART_MODE_NONE = 0,
+ KUART_MODE_RS485,
+ KUART_MODE_RS422,
+ KUART_MODE_RS232
+};
+
+/* capability flags */
+#define KUART_CAPABILITY_NONE BIT(KUART_MODE_NONE)
+#define KUART_CAPABILITY_RS485 BIT(KUART_MODE_RS485)
+#define KUART_CAPABILITY_RS422 BIT(KUART_MODE_RS422)
+#define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232)
+#define KUART_CAPABILITY_MASK GENMASK(3, 0)
+
+/* Additional Control Register DTR line configuration */
+#define UART_ACR_DTRLC_MASK 0x18
+#define UART_ACR_DTRLC_COMPAT 0x00
+#define UART_ACR_DTRLC_ENABLE_LOW 0x10
+
+struct kuart {
+ struct keba_uart_auxdev *auxdev;
+ void __iomem *base;
+ unsigned int line;
+
+ unsigned int flags;
+ u8 capability;
+ enum kuart_mode mode;
+};
+
+static void kuart_set_phy_mode(struct kuart *kuart, enum kuart_mode mode)
+{
+ iowrite8(mode, kuart->base + KUART_CONTROL);
+}
+
+static void kuart_enhanced_mode(struct uart_8250_port *up, bool enable)
+{
+ u8 lcr, efr;
+
+ /* backup LCR register */
+ lcr = serial_in(up, UART_LCR);
+
+ /* enable 650 compatible register set (EFR, ...) */
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ /* enable/disable enhanced mode with indexed control registers */
+ efr = serial_in(up, UART_EFR);
+ if (enable)
+ efr |= UART_EFR_ECB;
+ else
+ efr &= ~UART_EFR_ECB;
+ serial_out(up, UART_EFR, efr);
+
+ /* disable 650 compatible register set, restore LCR */
+ serial_out(up, UART_LCR, lcr);
+}
+
+static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc)
+{
+ u8 acr;
+
+ /* set index register to 0 to access ACR register */
+ serial_out(up, UART_SCR, UART_ACR);
+
+ /* set value register to 0x10 writing DTR mode (1,0) */
+ acr = serial_in(up, UART_LSR);
+ acr &= ~UART_ACR_DTRLC_MASK;
+ acr |= dtrlc;
+ serial_out(up, UART_LSR, acr);
+}
+
+static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct kuart *kuart = port->private_data;
+ enum kuart_mode mode;
+ u8 dtrlc;
+
+ if (rs485->flags & SER_RS485_ENABLED) {
+ if (rs485->flags & SER_RS485_MODE_RS422)
+ mode = KUART_MODE_RS422;
+ else
+ mode = KUART_MODE_RS485;
+ } else {
+ mode = KUART_MODE_RS232;
+ }
+
+ if (mode == kuart->mode)
+ return 0;
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* deactivate physical interface, break before make */
+ kuart_set_phy_mode(kuart, KUART_MODE_NONE);
+ }
+
+ if (mode == KUART_MODE_RS485) {
+ /*
+ * Set DTR line configuration of 95x UART to DTR mode (1,0).
+ * In this mode the DTR pin drives the active-low enable pin of
+ * an external RS485 buffer. The DTR pin will be forced low
+ * whenever the transmitter is not empty, otherwise DTR pin is
+ * high.
+ */
+ dtrlc = UART_ACR_DTRLC_ENABLE_LOW;
+ } else {
+ /*
+ * Set DTR line configuration of 95x UART to DTR mode (0,0).
+ * In this mode the DTR pin is compatible with 16C450, 16C550,
+ * 16C650 and 16c670 (i.e. normal).
+ */
+ dtrlc = UART_ACR_DTRLC_COMPAT;
+ }
+
+ kuart_enhanced_mode(up, true);
+ kuart_dtr_line_config(up, dtrlc);
+ kuart_enhanced_mode(up, false);
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* activate selected physical interface */
+ kuart_set_phy_mode(kuart, mode);
+ }
+
+ kuart->mode = mode;
+
+ return 0;
+}
+
+static int kuart_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &auxdev->dev;
+ struct uart_8250_port uart = {};
+ struct resource res;
+ struct kuart *kuart;
+ int retval;
+
+ kuart = devm_kzalloc(dev, sizeof(*kuart), GFP_KERNEL);
+ if (!kuart)
+ return -ENOMEM;
+ kuart->auxdev = container_of(auxdev, struct keba_uart_auxdev, auxdev);
+ kuart->flags = id->driver_data;
+ auxiliary_set_drvdata(auxdev, kuart);
+
+ /*
+ * map only memory in front of UART registers, UART registers will be
+ * mapped by serial port
+ */
+ res = kuart->auxdev->io;
+ res.end = res.start + KUART_BASE - 1;
+ kuart->base = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(kuart->base))
+ return PTR_ERR(kuart->base);
+
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /*
+ * supported modes are read from capability register, at least
+ * one mode other than none must be supported
+ */
+ kuart->capability = ioread8(kuart->base + KUART_CAPABILITY) &
+ KUART_CAPABILITY_MASK;
+ if ((kuart->capability & ~KUART_CAPABILITY_NONE) == 0)
+ return -EIO;
+ }
+
+ spin_lock_init(&uart.port.lock);
+ uart.port.dev = dev;
+ uart.port.mapbase = kuart->auxdev->io.start + KUART_BASE;
+ uart.port.irq = kuart->auxdev->irq;
+ uart.port.uartclk = KUART_CLK;
+ uart.port.private_data = kuart;
+
+ /* 8 bit registers are 32 bit aligned => shift register offset */
+ uart.port.iotype = UPIO_MEM32;
+ uart.port.regshift = KUART_REGSHIFT;
+
+ /*
+ * UART mixes 16550, 16750 and 16C950 (for RS485) standard => auto
+ * configuration works best
+ */
+ uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_IOREMAP;
+
+ /*
+ * UART supports RS485, RS422 and RS232 with switching of physical
+ * interface
+ */
+ uart.port.rs485_config = kuart_rs485_config;
+ if (kuart->flags & KUART_RS485) {
+ uart.port.rs485_supported.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ }
+ if (kuart->flags & KUART_USE_CAPABILITY) {
+ /* default mode priority is RS485 > RS422 > RS232 */
+ if (kuart->capability & KUART_CAPABILITY_RS422) {
+ uart.port.rs485_supported.flags |= SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND |
+ SER_RS485_MODE_RS422;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND |
+ SER_RS485_MODE_RS422;
+ }
+ if (kuart->capability & KUART_CAPABILITY_RS485) {
+ uart.port.rs485_supported.flags |= SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ uart.port.rs485.flags = SER_RS485_ENABLED |
+ SER_RS485_RTS_ON_SEND;
+ }
+ }
+
+ retval = serial8250_register_8250_port(&uart);
+ if (retval < 0) {
+ dev_err(&auxdev->dev, "UART registration failed!\n");
+ return retval;
+ }
+ kuart->line = retval;
+
+ return 0;
+}
+
+static void kuart_remove(struct auxiliary_device *auxdev)
+{
+ struct kuart *kuart = auxiliary_get_drvdata(auxdev);
+
+ if (kuart->flags & KUART_USE_CAPABILITY)
+ kuart_set_phy_mode(kuart, KUART_MODE_NONE);
+
+ serial8250_unregister_port(kuart->line);
+}
+
+static const struct auxiliary_device_id kuart_devtype_aux[] = {
+ { .name = "keba.rs485-uart", .driver_data = KUART_RS485 },
+ { .name = "keba.rs232-uart", .driver_data = 0 },
+ { .name = "keba.uart", .driver_data = KUART_USE_CAPABILITY },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, kuart_devtype_aux);
+
+static struct auxiliary_driver kuart_driver_aux = {
+ .name = KUART,
+ .id_table = kuart_devtype_aux,
+ .probe = kuart_probe,
+ .remove = kuart_remove,
+};
+module_auxiliary_driver(kuart_driver_aux);
+
+MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>");
+MODULE_DESCRIPTION("KEBA 8250 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
new file mode 100644
index 000000000000..53153a116c01
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -0,0 +1,238 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Serial Port driver for Loongson family chips
+ *
+ * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/property.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/reset.h>
+
+#include "8250.h"
+
+/* Divisor Latch Fraction Register */
+#define LOONGSON_UART_DLF 0x2
+
+#define LOONGSON_QUOT_FRAC_MASK GENMASK(7, 0)
+#define LOONGSON_QUOT_DIV_MASK GENMASK(15, 8)
+
+struct loongson_uart_ddata {
+ bool has_frac;
+ u8 mcr_invert;
+ u8 msr_invert;
+};
+
+static const struct loongson_uart_ddata ls2k0500_uart_data = {
+ .has_frac = false,
+ .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
+ .msr_invert = UART_MSR_CTS | UART_MSR_DSR,
+};
+
+static const struct loongson_uart_ddata ls2k1500_uart_data = {
+ .has_frac = true,
+ .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
+ .msr_invert = 0,
+};
+
+struct loongson_uart_priv {
+ int line;
+ struct clk *clk;
+ struct resource *res;
+ struct reset_control *rst;
+ const struct loongson_uart_ddata *ddata;
+};
+
+static u8 serial_fixup(struct uart_port *p, unsigned int offset, u8 val)
+{
+ struct loongson_uart_priv *priv = p->private_data;
+
+ switch (offset) {
+ case UART_MCR:
+ return val ^ priv->ddata->mcr_invert;
+ case UART_MSR:
+ return val ^ priv->ddata->msr_invert;
+ default:
+ return val;
+ }
+}
+
+static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
+{
+ u8 val;
+
+ val = readb(p->membase + (offset << p->regshift));
+
+ return serial_fixup(p, offset, val);
+}
+
+static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
+{
+ u8 val;
+
+ offset <<= p->regshift;
+ val = serial_fixup(p, offset, value);
+ writeb(val, p->membase + offset);
+}
+
+static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int *frac)
+{
+ unsigned int quot;
+
+ quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);
+ *frac = FIELD_GET(LOONGSON_QUOT_FRAC_MASK, quot);
+
+ return FIELD_GET(LOONGSON_QUOT_DIV_MASK, quot);
+}
+
+static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+ serial_dl_write(up, quot);
+ serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
+}
+
+static int loongson_uart_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = {};
+ struct loongson_uart_priv *priv;
+ struct uart_port *port;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ddata = device_get_match_data(dev);
+
+ port = &uart.port;
+ spin_lock_init(&port->lock);
+ port->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
+ port->iotype = UPIO_MEM;
+ port->regshift = 0;
+ port->dev = dev;
+ port->type = PORT_16550A;
+ port->private_data = priv;
+
+ port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res);
+ if (!port->membase)
+ return -ENOMEM;
+
+ port->mapbase = priv->res->start;
+ port->mapsize = resource_size(priv->res);
+ port->serial_in = loongson_serial_in;
+ port->serial_out = loongson_serial_out;
+
+ if (priv->ddata->has_frac) {
+ port->get_divisor = loongson_frac_get_divisor;
+ port->set_divisor = loongson_frac_set_divisor;
+ }
+
+ ret = uart_read_port_properties(port);
+ if (ret)
+ return ret;
+
+ if (!port->uartclk) {
+ priv->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk),
+ "Unable to determine clock frequency!\n");
+ port->uartclk = clk_get_rate(priv->clk);
+ }
+
+ priv->rst = devm_reset_control_get_optional_shared(dev, NULL);
+ if (IS_ERR(priv->rst))
+ return PTR_ERR(priv->rst);
+
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ return ret;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+ reset_control_assert(priv->rst);
+ return ret;
+ }
+
+ priv->line = ret;
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static void loongson_uart_remove(struct platform_device *pdev)
+{
+ struct loongson_uart_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ reset_control_assert(priv->rst);
+}
+
+static int loongson_uart_suspend(struct device *dev)
+{
+ struct loongson_uart_priv *priv = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(priv->line);
+
+ serial8250_suspend_port(priv->line);
+
+ if (!uart_console(&up->port) || console_suspend_enabled)
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static int loongson_uart_resume(struct device *dev)
+{
+ struct loongson_uart_priv *priv = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(priv->line);
+ int ret;
+
+ if (!uart_console(&up->port) || console_suspend_enabled) {
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+ }
+
+ serial8250_resume_port(priv->line);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend,
+ loongson_uart_resume);
+
+static const struct of_device_id loongson_uart_of_ids[] = {
+ { .compatible = "loongson,ls2k0500-uart", .data = &ls2k0500_uart_data },
+ { .compatible = "loongson,ls2k1500-uart", .data = &ls2k1500_uart_data },
+ { },
+};
+MODULE_DEVICE_TABLE(of, loongson_uart_of_ids);
+
+static struct platform_driver loongson_uart_driver = {
+ .probe = loongson_uart_probe,
+ .remove = loongson_uart_remove,
+ .driver = {
+ .name = "loongson-uart",
+ .pm = pm_ptr(&loongson_uart_pm_ops),
+ .of_match_table = loongson_uart_of_ids,
+ },
+};
+
+module_platform_driver(loongson_uart_driver);
+
+MODULE_DESCRIPTION("Loongson UART driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index d178b6c54ea1..9799356b65f7 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -95,7 +95,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
u32 spd;
int ret;
- memset(port, 0, sizeof *port);
+ memset(port, 0, sizeof(*port));
pm_runtime_enable(&ofdev->dev);
pm_runtime_get_sync(&ofdev->dev);
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 152f914c599d..c5a932f48f74 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -95,6 +95,11 @@
#define PCI_DEVICE_ID_MOXA_CP138E_A 0x1381
#define PCI_DEVICE_ID_MOXA_CP168EL_A 0x1683
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7500 0x7003
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG 0x7024
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG 0x7025
+#define PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG 0x7026
+
/* 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
@@ -165,7 +170,15 @@ static int
setup_port(struct serial_private *priv, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
- return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift);
+ void __iomem *iomem = NULL;
+
+ if (pci_resource_flags(priv->dev, bar) & IORESOURCE_MEM) {
+ iomem = pcim_iomap(priv->dev, bar, 0);
+ if (!iomem)
+ return -ENOMEM;
+ }
+
+ return serial8250_pci_setup_port(priv->dev, port, bar, offset, regshift, iomem);
}
/*
@@ -5996,6 +6009,38 @@ static const struct pci_device_id serial_pci_tbl[] = {
0,
pbn_ADDIDATA_PCIe_8_3906250 },
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7500,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7500_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_4_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7420_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_2_115200 },
+
+ { PCI_VENDOR_ID_ADDIDATA,
+ PCI_DEVICE_ID_ADDIDATA_CPCI7300_NG,
+ PCI_ANY_ID,
+ PCI_ANY_ID,
+ 0,
+ 0,
+ pbn_b0_1_115200 },
+
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9835,
PCI_VENDOR_ID_IBM, 0x0299,
0, 0, pbn_b0_bt_2_115200 },
@@ -6178,7 +6223,6 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev)
return PCI_ERS_RESULT_DISCONNECT;
pci_restore_state(dev);
- pci_save_state(dev);
return PCI_ERS_RESULT_RECOVERED;
}
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index 4c149db84692..feeede164886 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -671,7 +671,7 @@ static int pci1xxxx_resume(struct device *dev)
}
static int pci1xxxx_setup(struct pci_dev *pdev,
- struct uart_8250_port *port, int port_idx, int rev)
+ struct uart_8250_port *port, int port_idx, struct pci1xxxx_8250 *priv)
{
int ret;
@@ -698,12 +698,12 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
* C0 and later revisions support Burst operation.
* RTS workaround in mctrl is applicable only to B0.
*/
- if (rev >= 0xC0)
+ if (priv->dev_rev >= 0xC0)
port->port.handle_irq = pci1xxxx_handle_irq;
- else if (rev == 0xB0)
+ else if (priv->dev_rev == 0xB0)
port->port.set_mctrl = pci1xxxx_set_mctrl;
- ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
+ ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0, priv->membase);
if (ret < 0)
return ret;
@@ -821,7 +821,7 @@ static int pci1xxxx_serial_probe(struct pci_dev *pdev,
else
uart.port.irq = pci_irq_vector(pdev, 0);
- rc = pci1xxxx_setup(pdev, &uart, port_idx, priv->dev_rev);
+ rc = pci1xxxx_setup(pdev, &uart, port_idx, priv);
if (rc) {
dev_warn(dev, "Failed to setup port %u\n", i);
continue;
diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c
index d8d0ae0d7238..9d5d2531a33b 100644
--- a/drivers/tty/serial/8250/8250_pcilib.c
+++ b/drivers/tty/serial/8250/8250_pcilib.c
@@ -22,19 +22,16 @@ int serial_8250_warn_need_ioport(struct pci_dev *dev)
EXPORT_SYMBOL_NS_GPL(serial_8250_warn_need_ioport, "SERIAL_8250_PCI");
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
- u8 bar, unsigned int offset, int regshift)
+ u8 bar, unsigned int offset, int regshift, void __iomem *iomem)
{
if (bar >= PCI_STD_NUM_BARS)
return -EINVAL;
if (pci_resource_flags(dev, bar) & IORESOURCE_MEM) {
- 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 = pcim_iomap_table(dev)[bar] + offset;
+ port->port.membase = iomem + offset;
port->port.regshift = regshift;
} else if (IS_ENABLED(CONFIG_HAS_IOPORT)) {
port->port.iotype = UPIO_PORT;
diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h
index 16a274574cde..ab18de8d1355 100644
--- a/drivers/tty/serial/8250/8250_pcilib.h
+++ b/drivers/tty/serial/8250/8250_pcilib.h
@@ -12,6 +12,6 @@ struct pci_dev;
struct uart_8250_port;
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
- unsigned int offset, int regshift);
+ unsigned int offset, int regshift, void __iomem *iomem);
int serial_8250_warn_need_ioport(struct pci_dev *dev);
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index fe7ec440ffa5..86d12d2b5907 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -29,10 +29,8 @@
* Configuration:
* share_irqs: Whether we pass IRQF_SHARED to request_irq().
* This option is unsafe when used on edge-triggered interrupts.
- * skip_txen_test: Force skip of txen test at init time.
*/
-unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
-unsigned int skip_txen_test;
+static bool share_irqs = IS_ENABLED(CONFIG_SERIAL_8250_SHARE_IRQ);
unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
@@ -60,7 +58,7 @@ EXPORT_SYMBOL(serial8250_set_isa_configurator);
static void __init __serial8250_isa_init_ports(void)
{
- int i, irqflag = 0;
+ int i;
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
@@ -77,9 +75,6 @@ static void __init __serial8250_isa_init_ports(void)
univ8250_port_ops = *univ8250_port_base_ops;
univ8250_rsa_support(&univ8250_port_ops, univ8250_port_base_ops);
- if (share_irqs)
- irqflag = IRQF_SHARED;
-
for (i = 0; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++) {
struct uart_8250_port *up = serial8250_get_port(i);
struct uart_port *port = &up->port;
@@ -94,7 +89,9 @@ static void __init __serial8250_isa_init_ports(void)
port->iotype = old_serial_port[i].io_type;
port->regshift = old_serial_port[i].iomem_reg_shift;
- port->irqflags |= irqflag;
+ if (share_irqs)
+ port->irqflags |= IRQF_SHARED;
+
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
}
@@ -157,15 +154,12 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
{
- int ret, i, irqflag = 0;
+ int ret, i;
struct uart_8250_port *uart __free(kfree) = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart)
return -ENOMEM;
- if (share_irqs)
- irqflag = IRQF_SHARED;
-
for (i = 0; p && p->flags != 0; p++, i++) {
uart->port.iobase = p->iobase;
uart->port.membase = p->membase;
@@ -193,7 +187,10 @@ static int serial8250_probe_platform(struct platform_device *dev, struct plat_se
uart->port.get_mctrl = p->get_mctrl;
uart->port.pm = p->pm;
uart->port.dev = &dev->dev;
- uart->port.irqflags |= irqflag;
+
+ if (share_irqs)
+ uart->port.irqflags |= IRQF_SHARED;
+
ret = serial8250_register_8250_port(uart);
if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d "
@@ -380,40 +377,10 @@ module_exit(serial8250_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial platform driver");
-module_param_hw(share_irqs, uint, other, 0644);
+module_param_hw(share_irqs, bool, other, 0644);
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) ")");
-module_param(skip_txen_test, uint, 0644);
-MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
-
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
-#ifndef MODULE
-/*
- * This module was renamed to 8250_core in 3.7. Keep the old "8250" name
- * working as well for the module options so we don't break people. We
- * need to keep the names identical and the convenient macros will happily
- * refuse to let us do that by failing the build with redefinition errors
- * of global variables. So we stick them inside a dummy function to avoid
- * those conflicts. The options still get parsed, and the redefined
- * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
- *
- * This is hacky. I'm sorry.
- */
-static void __used s8250_options(void)
-{
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250_core."
-
- module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
- module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
- module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
-}
-#else
-MODULE_ALIAS("8250_core");
-#endif
-#endif
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index 1f182f165525..fff9395948e3 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -209,27 +209,3 @@ void rsa_reset(struct uart_8250_port *up)
serial_out(up, UART_RSA_FRR, 0);
}
-
-#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
-#ifndef MODULE
-/*
- * Keep the old "8250" name working as well for the module options so we don't
- * break people. We need to keep the names identical and the convenient macros
- * will happily refuse to let us do that by failing the build with redefinition
- * errors of global variables. So we stick them inside a dummy function to
- * avoid those conflicts. The options still get parsed, and the redefined
- * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
- *
- * This is hacky. I'm sorry.
- */
-static void __used rsa8250_options(void)
-{
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250_core."
-
- __module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
- &param_array_ops, .arr = &__param_arr_probe_rsa,
- 0444, -1, 0);
-}
-#endif
-#endif
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f64ef0819cd4..c488ff6f2865 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -34,23 +34,6 @@ config SERIAL_8250
Most people will say Y or M here, so that they can use serial mice,
modems and similar devices connecting to the standard serial ports.
-config SERIAL_8250_DEPRECATED_OPTIONS
- bool "Support 8250_core.* kernel options (DEPRECATED)"
- depends on SERIAL_8250
- default y
- help
- In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to
- accept kernel parameters in both forms like 8250_core.nr_uarts=4 and
- 8250.nr_uarts=4. We now renamed the module back to 8250, but if
- anybody noticed in 3.7 and changed their userspace we still have to
- keep the 8250_core.* options around until they revert the changes
- they already did.
-
- If 8250 is built as a module, this adds 8250_core alias instead.
-
- If you did not notice yet and/or you have userspace from pre-3.7, it
- is safe (and recommended) to say N here.
-
config SERIAL_8250_PNP
bool "8250/16550 PNP device support" if EXPERT
depends on SERIAL_8250 && PNP
@@ -430,6 +413,19 @@ config SERIAL_8250_IOC3
behind the IOC3 device on those systems. Maximum baud speed is
38400bps using this driver.
+config SERIAL_8250_KEBA
+ tristate "Support for KEBA 8250 UART"
+ depends on SERIAL_8250
+ depends on KEBA_CP500
+ help
+ Selecting this option will add support for KEBA UARTs. These UARTs
+ are used for the serial interfaces of KEBA PLCs.
+
+ This driver can also be built as a module. If so, the module will
+ be called 8250_keba.
+
+ If unsure, say N.
+
config SERIAL_8250_RT288X
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
depends on SERIAL_8250
@@ -468,6 +464,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
not booting kernel because the serial console remains silent in case
they forgot to update the command line.
+config SERIAL_8250_LOONGSON
+ tristate "Loongson 8250 based serial port"
+ depends on SERIAL_8250
+ depends on LOONGARCH || COMPILE_TEST
+ help
+ If you have a machine based on LoongArch CPU you can enable
+ its onboard serial ports by enabling this option. The option
+ is applicable to both devicetree and ACPI, say Y to this option.
+ If unsure, say N.
+
config SERIAL_8250_LPC18XX
tristate "NXP LPC18xx/43xx serial port support"
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 9ec4d5fe64de..6d21402b4435 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -38,6 +38,8 @@ obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
obj-$(CONFIG_SERIAL_8250_IOC3) += 8250_ioc3.o
+obj-$(CONFIG_SERIAL_8250_KEBA) += 8250_keba.o
+obj-$(CONFIG_SERIAL_8250_LOONGSON) += 8250_loongson.o
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 282116765e64..59221cce0028 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1044,7 +1044,7 @@ config SERIAL_SCCNXP_CONSOLE
config SERIAL_SC16IS7XX
tristate "NXP SC16IS7xx UART support"
- depends on SPI_MASTER || I2C
+ depends on SPI_MASTER || I2C || COMPILE_TEST
select SERIAL_CORE
select SERIAL_SC16IS7XX_SPI if SPI_MASTER
select SERIAL_SC16IS7XX_I2C if I2C
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 8bb33556b312..5b491db9d2fc 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -560,6 +560,64 @@ static int ar933x_uart_verify_port(struct uart_port *port,
return 0;
}
+#ifdef CONFIG_CONSOLE_POLL
+static int ar933x_poll_get_char(struct uart_port *port)
+{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+ unsigned int rdata;
+ unsigned char ch;
+ u32 imr;
+
+ /* Disable all interrupts */
+ imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
+
+ rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
+ if ((rdata & AR933X_UART_DATA_RX_CSR) == 0) {
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+ return NO_POLL_CHAR;
+ }
+
+ /* remove the character from the FIFO */
+ ar933x_uart_write(up, AR933X_UART_DATA_REG,
+ AR933X_UART_DATA_RX_CSR);
+
+ ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
+
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+
+ return ch;
+}
+
+static void ar933x_poll_put_char(struct uart_port *port, unsigned char c)
+{
+ struct ar933x_uart_port *up =
+ container_of(port, struct ar933x_uart_port, port);
+ u32 imr;
+
+ /* Disable all interrupts */
+ imr = ar933x_uart_read(up, AR933X_UART_INT_EN_REG);
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, 0);
+
+ /* Wait until FIFO is empty */
+ while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR))
+ cpu_relax();
+
+ /* Write a character */
+ ar933x_uart_putc(up, c);
+
+ /* Wait until FIFO is empty */
+ while (!(ar933x_uart_read(up, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR))
+ cpu_relax();
+
+ /* Enable interrupts */
+ ar933x_uart_write(up, AR933X_UART_INT_EN_REG, imr);
+}
+#endif
+
static const struct uart_ops ar933x_uart_ops = {
.tx_empty = ar933x_uart_tx_empty,
.set_mctrl = ar933x_uart_set_mctrl,
@@ -576,6 +634,10 @@ static const struct uart_ops ar933x_uart_ops = {
.request_port = ar933x_uart_request_port,
.config_port = ar933x_uart_config_port,
.verify_port = ar933x_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = ar933x_poll_get_char,
+ .poll_put_char = ar933x_poll_put_char,
+#endif
};
static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios,
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index c9519e649e82..1bd7ec9c81ea 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -3087,6 +3087,8 @@ static int lpuart_suspend_noirq(struct device *dev)
static int lpuart_resume_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
+ struct tty_port *port = &sport->port.state->port;
+ bool wake_active;
u32 stat;
pinctrl_pm_select_default_state(dev);
@@ -3098,6 +3100,12 @@ static int lpuart_resume_noirq(struct device *dev)
if (lpuart_is_32(sport)) {
stat = lpuart32_read(&sport->port, UARTSTAT);
lpuart32_write(&sport->port, stat, UARTSTAT);
+
+ /* check whether lpuart wakeup was triggered */
+ wake_active = stat & (UARTSTAT_RDRF | UARTSTAT_RXEDGIF);
+
+ if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)))
+ pm_wakeup_event(tty_port_tty_get(port)->dev, 0);
}
}
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 7fb995a8490e..b7e33a896589 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -760,7 +760,7 @@ static void load_code(struct icom_port *icom_port)
dma_free_coherent(&dev->dev, 4096, new_page, temp_pci);
}
-static int startup(struct icom_port *icom_port)
+static int icom_startup(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cable_id, raw_cable_id;
@@ -832,7 +832,7 @@ unlock:
return 0;
}
-static void shutdown(struct icom_port *icom_port)
+static void icom_shutdown(struct icom_port *icom_port)
{
unsigned long temp;
unsigned char cmdReg;
@@ -1311,7 +1311,7 @@ static int icom_open(struct uart_port *port)
int retval;
kref_get(&icom_port->adapter->kref);
- retval = startup(icom_port);
+ retval = icom_startup(icom_port);
if (retval) {
kref_put(&icom_port->adapter->kref, icom_kref_release);
@@ -1333,7 +1333,7 @@ static void icom_close(struct uart_port *port)
cmdReg = readb(&icom_port->dram->CmdReg);
writeb(cmdReg & ~CMD_RCV_ENABLE, &icom_port->dram->CmdReg);
- shutdown(icom_port);
+ icom_shutdown(icom_port);
kref_put(&icom_port->adapter->kref, icom_kref_release);
}
@@ -1723,6 +1723,7 @@ static int icom_probe(struct pci_dev *dev,
retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
if (retval) {
dev_err(&dev->dev, "PCI Config read FAILED\n");
+ retval = pcibios_err_to_errno(retval);
goto probe_exit0;
}
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 500dfc009d03..c488e5d372ff 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -30,7 +30,7 @@
#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <linux/dma/imx-dma.h>
#include "serial_mctrl_gpio.h"
@@ -2697,16 +2697,32 @@ static void imx_uart_save_context(struct imx_port *sport)
/* called with irq off */
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
{
- u32 ucr3;
+ struct tty_port *port = &sport->port.state->port;
+ struct device *tty_dev;
+ bool may_wake = false, wake_active = false;
+ u32 ucr3, usr1;
+
+ scoped_guard(tty_port_tty, port) {
+ struct tty_struct *tty = scoped_tty();
+
+ tty_dev = tty->dev;
+ may_wake = tty_dev && device_may_wakeup(tty_dev);
+ }
+
+ /* only configure the wake register when device set as wakeup source */
+ if (!may_wake)
+ return;
uart_port_lock_irq(&sport->port);
+ usr1 = imx_uart_readl(sport, USR1);
ucr3 = imx_uart_readl(sport, UCR3);
if (on) {
imx_uart_writel(sport, USR1_AWAKE, USR1);
ucr3 |= UCR3_AWAKEN;
} else {
ucr3 &= ~UCR3_AWAKEN;
+ wake_active = usr1 & USR1_AWAKE;
}
imx_uart_writel(sport, ucr3, UCR3);
@@ -2717,10 +2733,14 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
ucr1 |= UCR1_RTSDEN;
} else {
ucr1 &= ~UCR1_RTSDEN;
+ wake_active = wake_active || (usr1 & USR1_RTSD);
}
imx_uart_writel(sport, ucr1, UCR1);
}
+ if (wake_active && irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)))
+ pm_wakeup_event(tty_port_tty_get(port)->dev, 0);
+
uart_port_unlock_irq(&sport->port);
}
diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c
index 417a5b6bffc3..8d21373cae57 100644
--- a/drivers/tty/serial/jsm/jsm_driver.c
+++ b/drivers/tty/serial/jsm/jsm_driver.c
@@ -355,7 +355,6 @@ static void jsm_io_resume(struct pci_dev *pdev)
struct jsm_board *brd = pci_get_drvdata(pdev);
pci_restore_state(pdev);
- pci_save_state(pdev);
jsm_uart_port_init(brd);
}
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 85f6c5a76e0f..5a955c80a853 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -577,7 +577,6 @@ static int __init kgdboc_earlycon_init(char *opt)
console_list_lock();
for_each_console(con) {
if (con->write && con->read &&
- (con->flags & (CON_BOOT | CON_ENABLED)) &&
(!opt || !opt[0] || strcmp(con->name, opt) == 0))
break;
}
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index b417faead20f..3a77a7e5c7bc 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -343,7 +343,7 @@ static int mux_verify_port(struct uart_port *port, struct serial_struct *ser)
}
/**
- * mux_drv_poll - Mux poll function.
+ * mux_poll - Mux poll function.
* @unused: Unused variable
*
* This function periodically polls the Serial MUX to check for new data.
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index 8058b839b26c..6ce6528f5c10 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -14,6 +14,7 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
@@ -101,10 +102,16 @@
#define DMA_RX_BUF_SIZE 2048
static DEFINE_IDA(port_ida);
+#define DOMAIN_IDX_POWER 0
+#define DOMAIN_IDX_PERF 1
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
+ struct dev_pm_domain_attach_data pd_data;
+ int (*resources_init)(struct uart_port *uport);
+ int (*set_rate)(struct uart_port *uport, unsigned int baud);
+ int (*power_state)(struct uart_port *uport, bool state);
};
struct qcom_geni_private_data {
@@ -142,6 +149,7 @@ struct qcom_geni_serial_port {
struct qcom_geni_private_data private_data;
const struct qcom_geni_device_data *dev_data;
+ struct dev_pm_domain_list *pd_list;
};
static const struct uart_ops qcom_geni_console_pops;
@@ -1299,6 +1307,42 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud)
return 0;
}
+static int geni_serial_set_level(struct uart_port *uport, unsigned int baud)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ struct device *perf_dev = port->pd_list->pd_devs[DOMAIN_IDX_PERF];
+
+ /*
+ * The performance protocol sets UART communication
+ * speeds by selecting different performance levels
+ * through the OPP framework.
+ *
+ * Supported perf levels for baudrates in firmware are below
+ * +---------------------+--------------------+
+ * | Perf level value | Baudrate values |
+ * +---------------------+--------------------+
+ * | 300 | 300 |
+ * | 1200 | 1200 |
+ * | 2400 | 2400 |
+ * | 4800 | 4800 |
+ * | 9600 | 9600 |
+ * | 19200 | 19200 |
+ * | 38400 | 38400 |
+ * | 57600 | 57600 |
+ * | 115200 | 115200 |
+ * | 230400 | 230400 |
+ * | 460800 | 460800 |
+ * | 921600 | 921600 |
+ * | 2000000 | 2000000 |
+ * | 3000000 | 3000000 |
+ * | 3200000 | 3200000 |
+ * | 4000000 | 4000000 |
+ * +---------------------+--------------------+
+ */
+
+ return dev_pm_opp_set_level(perf_dev, baud);
+}
+
static void qcom_geni_serial_set_termios(struct uart_port *uport,
struct ktermios *termios,
const struct ktermios *old)
@@ -1317,7 +1361,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 8000000);
- ret = geni_serial_set_rate(uport, baud);
+ ret = port->dev_data->set_rate(uport, baud);
if (ret)
return;
@@ -1604,8 +1648,27 @@ static int geni_serial_resources_off(struct uart_port *uport)
return 0;
}
-static int geni_serial_resource_init(struct qcom_geni_serial_port *port)
+static int geni_serial_resource_state(struct uart_port *uport, bool power_on)
+{
+ return power_on ? geni_serial_resources_on(uport) : geni_serial_resources_off(uport);
+}
+
+static int geni_serial_pwr_init(struct uart_port *uport)
{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ ret = dev_pm_domain_attach_list(port->se.dev,
+ &port->dev_data->pd_data, &port->pd_list);
+ if (ret <= 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int geni_serial_resource_init(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
int ret;
port->se.clk = devm_clk_get(port->se.dev, "se");
@@ -1650,10 +1713,10 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
old_state = UART_PM_STATE_OFF;
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
- geni_serial_resources_on(uport);
+ pm_runtime_resume_and_get(uport->dev);
else if (new_state == UART_PM_STATE_OFF &&
old_state == UART_PM_STATE_ON)
- geni_serial_resources_off(uport);
+ pm_runtime_put_sync(uport->dev);
}
@@ -1756,13 +1819,16 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->se.dev = &pdev->dev;
port->se.wrapper = dev_get_drvdata(pdev->dev.parent);
- ret = geni_serial_resource_init(port);
+ ret = port->dev_data->resources_init(uport);
if (ret)
return ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -EINVAL;
+ if (!res) {
+ ret = -EINVAL;
+ goto error;
+ }
+
uport->mapbase = res->start;
uport->rs485_config = qcom_geni_rs485_config;
@@ -1774,19 +1840,26 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (!data->console) {
port->rx_buf = devm_kzalloc(uport->dev,
DMA_RX_BUF_SIZE, GFP_KERNEL);
- if (!port->rx_buf)
- return -ENOMEM;
+ if (!port->rx_buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
}
port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
"qcom_geni_serial_%s%d",
uart_console(uport) ? "console" : "uart", uport->line);
- if (!port->name)
- return -ENOMEM;
+ if (!port->name) {
+ ret = -ENOMEM;
+ goto error;
+ }
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ goto error;
+ }
+
uport->irq = irq;
uport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE);
@@ -1808,16 +1881,18 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH, port->name, uport);
if (ret) {
dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
- return ret;
+ goto error;
}
ret = uart_get_rs485_mode(uport);
if (ret)
- return ret;
+ goto error;
+
+ devm_pm_runtime_enable(port->se.dev);
ret = uart_add_one_port(drv, uport);
if (ret)
- return ret;
+ goto error;
if (port->wakeup_irq > 0) {
device_init_wakeup(&pdev->dev, true);
@@ -1827,11 +1902,15 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
- return ret;
+ goto error;
}
}
return 0;
+
+error:
+ dev_pm_domain_detach_list(port->pd_list);
+ return ret;
}
static void qcom_geni_serial_remove(struct platform_device *pdev)
@@ -1844,6 +1923,31 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, false);
ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
+ dev_pm_domain_detach_list(port->pd_list);
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_suspend(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, false);
+
+ return ret;
+}
+
+static int __maybe_unused qcom_geni_serial_runtime_resume(struct device *dev)
+{
+ struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
+ struct uart_port *uport = &port->uport;
+ int ret = 0;
+
+ if (port->dev_data->power_state)
+ ret = port->dev_data->power_state(uport, true);
+
+ return ret;
}
static int qcom_geni_serial_suspend(struct device *dev)
@@ -1881,14 +1985,46 @@ static int qcom_geni_serial_resume(struct device *dev)
static const struct qcom_geni_device_data qcom_geni_console_data = {
.console = true,
.mode = GENI_SE_FIFO,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
};
static const struct qcom_geni_device_data qcom_geni_uart_data = {
.console = false,
.mode = GENI_SE_DMA,
+ .resources_init = geni_serial_resource_init,
+ .set_rate = geni_serial_set_rate,
+ .power_state = geni_serial_resource_state,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_console_data = {
+ .console = true,
+ .mode = GENI_SE_FIFO,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
+};
+
+static const struct qcom_geni_device_data sa8255p_qcom_geni_uart_data = {
+ .console = false,
+ .mode = GENI_SE_DMA,
+ .pd_data = {
+ .pd_flags = PD_FLAG_DEV_LINK_ON,
+ .pd_names = (const char*[]) { "power", "perf" },
+ .num_pd_names = 2,
+ },
+ .resources_init = geni_serial_pwr_init,
+ .set_rate = geni_serial_set_level,
};
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
+ SET_RUNTIME_PM_OPS(qcom_geni_serial_runtime_suspend,
+ qcom_geni_serial_runtime_resume, NULL)
SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
};
@@ -1898,9 +2034,17 @@ static const struct of_device_id qcom_geni_serial_match_table[] = {
.data = &qcom_geni_console_data,
},
{
+ .compatible = "qcom,sa8255p-geni-debug-uart",
+ .data = &sa8255p_qcom_geni_console_data,
+ },
+ {
.compatible = "qcom,geni-uart",
.data = &qcom_geni_uart_data,
},
+ {
+ .compatible = "qcom,sa8255p-geni-uart",
+ .data = &sa8255p_qcom_geni_uart_data,
+ },
{}
};
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 2fb58c626daf..c1fabad6ba1f 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -2830,6 +2830,8 @@ OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
s5pv210_early_console_setup);
OF_EARLYCON_DECLARE(artpec8, "axis,artpec8-uart",
s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos850, "samsung,exynos850-uart",
+ s5pv210_early_console_setup);
static int __init gs101_early_console_setup(struct earlycon_device *device,
const char *opt)
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index c7435595dce1..1fd64a47341d 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -11,6 +11,7 @@
#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX"
#include <linux/bits.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -49,18 +50,10 @@
#define SC16IS7XX_SPR_REG (0x07) /* Scratch Pad */
#define SC16IS7XX_TXLVL_REG (0x08) /* TX FIFO level */
#define SC16IS7XX_RXLVL_REG (0x09) /* RX FIFO level */
-#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable
- * - only on 75x/76x
- */
-#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control
- * - only on 75x/76x
- */
+#define SC16IS7XX_IODIR_REG (0x0a) /* I/O Direction - only on 75x/76x */
+#define SC16IS7XX_IOSTATE_REG (0x0b) /* I/O State - only on 75x/76x */
+#define SC16IS7XX_IOINTENA_REG (0x0c) /* I/O Interrupt Enable - only on 75x/76x */
+#define SC16IS7XX_IOCONTROL_REG (0x0e) /* I/O Control - only on 75x/76x */
#define SC16IS7XX_EFCR_REG (0x0f) /* Extra Features Control */
/* TCR/TLR Register set: Only if ((MCR[2] == 1) && (EFR[4] == 1)) */
@@ -80,12 +73,9 @@
/* IER register bits */
#define SC16IS7XX_IER_RDI_BIT BIT(0) /* Enable RX data interrupt */
-#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register
- * interrupt */
-#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status
- * interrupt */
-#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status
- * interrupt */
+#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register interrupt */
+#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status interrupt */
+#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status interrupt */
/* IER register bits - write only if (EFR[4] == 1) */
#define SC16IS7XX_IER_SLEEP_BIT BIT(4) /* Enable Sleep mode */
@@ -118,9 +108,8 @@
* - only on 75x/76x
*/
#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
-#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
- * from active (LOW)
- * to inactive (HIGH)
+#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state from active
+ * (LOW) to inactive (HIGH)
*/
/* LCR register bits */
#define SC16IS7XX_LCR_LENGTH0_BIT BIT(0) /* Word length bit 0 */
@@ -136,8 +125,7 @@
*
* STOP length bit table:
* 0 -> 1 stop bit
- * 1 -> 1-1.5 stop bits if
- * word length is 5,
+ * 1 -> 1-1.5 stop bits if word length is 5,
* 2 stop bits otherwise
*/
#define SC16IS7XX_LCR_PARITY_BIT BIT(3) /* Parity bit enable */
@@ -149,29 +137,22 @@
#define SC16IS7XX_LCR_WORD_LEN_6 (0x01)
#define SC16IS7XX_LCR_WORD_LEN_7 (0x02)
#define SC16IS7XX_LCR_WORD_LEN_8 (0x03)
-#define SC16IS7XX_LCR_CONF_MODE_A SC16IS7XX_LCR_DLAB_BIT /* Special
- * reg set */
-#define SC16IS7XX_LCR_CONF_MODE_B 0xBF /* Enhanced
- * reg set */
+#define SC16IS7XX_LCR_REG_SET_SPECIAL SC16IS7XX_LCR_DLAB_BIT /* Special reg set */
+#define SC16IS7XX_LCR_REG_SET_ENHANCED 0xBF /* Enhanced reg set */
/* MCR register bits */
-#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement
- * - only on 75x/76x
- */
+#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement - only on 75x/76x */
#define SC16IS7XX_MCR_RTS_BIT BIT(1) /* RTS complement */
-#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR register enable */
+#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR registers enable */
#define SC16IS7XX_MCR_LOOP_BIT BIT(4) /* Enable loopback test mode */
#define SC16IS7XX_MCR_XONANY_BIT BIT(5) /* Enable Xon Any
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
#define SC16IS7XX_MCR_IRDA_BIT BIT(6) /* Enable IrDA mode
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
#define SC16IS7XX_MCR_CLKSEL_BIT BIT(7) /* Divide clock by 4
- * - write enabled
- * if (EFR[4] == 1)
+ * - write enabled if (EFR[4] == 1)
*/
/* LSR register bits */
@@ -192,28 +173,19 @@
/* MSR register bits */
#define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */
-#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready
- * or (IO4)
+#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready or (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator
- * or (IO7)
+#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator or (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect
- * or (IO6)
+#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect or (IO6)
* - only on 75x/76x
*/
#define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4)
- * - only on 75x/76x
- */
-#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7)
- * - only on 75x/76x
- */
-#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6)
- * - only on 75x/76x
- */
+#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4) - only on 75x/76x */
+#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7) - only on 75x/76x */
+#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6) - only on 75x/76x */
/*
* TCR register bits
@@ -252,54 +224,42 @@
#define SC16IS7XX_IOCONTROL_SRESET_BIT BIT(3) /* Software Reset */
/* EFCR register bits */
-#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop
- * mode (RS485) */
+#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop mode (RS485) */
#define SC16IS7XX_EFCR_RXDISABLE_BIT BIT(1) /* Disable receiver */
#define SC16IS7XX_EFCR_TXDISABLE_BIT BIT(2) /* Disable transmitter */
#define SC16IS7XX_EFCR_AUTO_RS485_BIT BIT(4) /* Auto RS485 RTS direction */
#define SC16IS7XX_EFCR_RTS_INVERT_BIT BIT(5) /* RTS output inversion */
#define SC16IS7XX_EFCR_IRDA_MODE_BIT BIT(7) /* IrDA mode
- * 0 = rate upto 115.2 kbit/s
- * - Only 75x/76x
- * 1 = rate upto 1.152 Mbit/s
- * - Only 76x
+ * 0 = rate up to 115.2 kbit/s - Only 75x/76x
+ * 1 = rate up to 1.152 Mbit/s - Only 76x
*/
/* EFR register bits */
#define SC16IS7XX_EFR_AUTORTS_BIT BIT(6) /* Auto RTS flow ctrl enable */
#define SC16IS7XX_EFR_AUTOCTS_BIT BIT(7) /* Auto CTS flow ctrl enable */
#define SC16IS7XX_EFR_XOFF2_DETECT_BIT BIT(5) /* Enable Xoff2 detection */
-#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions
- * and writing to IER[7:4],
- * FCR[5:4], MCR[7:5]
+#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions and writing to
+ * IER[7:4], FCR[5:4], MCR[7:5]
*/
#define SC16IS7XX_EFR_SWFLOW3_BIT BIT(3)
#define SC16IS7XX_EFR_SWFLOW2_BIT BIT(2)
/*
* SWFLOW bits 3 & 2 table:
- * 00 -> no transmitter flow
- * control
- * 01 -> transmitter generates
- * XON2 and XOFF2
- * 10 -> transmitter generates
- * XON1 and XOFF1
- * 11 -> transmitter generates
- * XON1, XON2, XOFF1 and
- * XOFF2
+ * 00 -> no transmitter flow control
+ * 01 -> transmitter generates XON2 and XOFF2
+ * 10 -> transmitter generates XON1 and XOFF1
+ * 11 -> transmitter generates XON1, XON2,
+ * XOFF1 and XOFF2
*/
#define SC16IS7XX_EFR_SWFLOW1_BIT BIT(1)
#define SC16IS7XX_EFR_SWFLOW0_BIT BIT(0)
/*
* SWFLOW bits 1 & 0 table:
- * 00 -> no received flow
- * control
- * 01 -> receiver compares
- * XON2 and XOFF2
- * 10 -> receiver compares
- * XON1 and XOFF1
- * 11 -> receiver compares
- * XON1, XON2, XOFF1 and
- * XOFF2
+ * 00 -> no received flow control
+ * 01 -> receiver compares XON2 and XOFF2
+ * 10 -> receiver compares XON1 and XOFF1
+ * 11 -> receiver compares XON1, XON2,
+ * XOFF1 and XOFF2
*/
#define SC16IS7XX_EFR_FLOWCTRL_BITS (SC16IS7XX_EFR_AUTORTS_BIT | \
SC16IS7XX_EFR_AUTOCTS_BIT | \
@@ -328,7 +288,7 @@ struct sc16is7xx_one_config {
struct sc16is7xx_one {
struct uart_port port;
struct regmap *regmap;
- struct mutex efr_lock; /* EFR registers access */
+ struct mutex lock; /* For registers sharing same address space. */
struct kthread_work tx_work;
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
@@ -358,16 +318,16 @@ static DEFINE_IDA(sc16is7xx_lines);
static struct uart_driver sc16is7xx_uart = {
.owner = THIS_MODULE,
- .driver_name = SC16IS7XX_NAME,
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttySC",
.nr = SC16IS7XX_MAX_DEVS,
};
-#define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e)))
+#define to_sc16is7xx_one(p) container_of((p), struct sc16is7xx_one, port)
static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int val = 0;
regmap_read(one->regmap, reg, &val);
@@ -377,21 +337,21 @@ static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg)
static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_write(one->regmap, reg, val);
}
static void sc16is7xx_fifo_read(struct uart_port *port, u8 *rxbuf, unsigned int rxlen)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_noinc_read(one->regmap, SC16IS7XX_RHR_REG, rxbuf, rxlen);
}
static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
/*
* Don't send zero-length data, at least on SPI it confuses the chip
@@ -406,7 +366,7 @@ static void sc16is7xx_fifo_write(struct uart_port *port, u8 *txbuf, u8 to_send)
static void sc16is7xx_port_update(struct uart_port *port, u8 reg,
u8 mask, u8 val)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
regmap_update_bits(one->regmap, reg, mask, val);
}
@@ -419,52 +379,56 @@ static void sc16is7xx_power(struct uart_port *port, int on)
}
/*
- * In an amazing feat of design, the Enhanced Features Register (EFR)
- * shares the address of the Interrupt Identification Register (IIR).
- * Access to EFR is switched on by writing a magic value (0xbf) to the
- * Line Control Register (LCR). Any interrupt firing during this time will
- * see the EFR where it expects the IIR to be, leading to
+ * In an amazing feat of design, the enhanced register set shares the
+ * addresses 0x02 and 0x04-0x07 with the general register set.
+ * The special register set also shares the addresses 0x00-0x01 with the
+ * general register set.
+ *
+ * Access to the enhanced or special register set is enabled by writing a magic
+ * value to the Line Control Register (LCR). When enhanced register set access
+ * is enabled, for example, any interrupt firing during this time will see the
+ * EFR where it expects the IIR to be, leading to
* "Unexpected interrupt" messages.
*
- * Prevent this possibility by claiming a mutex while accessing the EFR,
- * and claiming the same mutex from within the interrupt handler. This is
- * similar to disabling the interrupt, but that doesn't work because the
- * bulk of the interrupt processing is run as a workqueue job in thread
- * context.
+ * Prevent this possibility by claiming a mutex when access to the enhanced
+ * or special register set is enabled, and claiming the same mutex from within
+ * the interrupt handler. This is similar to disabling the interrupt, but that
+ * doesn't work because the bulk of the interrupt processing is run as a
+ * workqueue job in thread context.
*/
-static void sc16is7xx_efr_lock(struct uart_port *port)
+static void sc16is7xx_regs_lock(struct uart_port *port, u8 register_set)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- mutex_lock(&one->efr_lock);
+ mutex_lock(&one->lock);
/* Backup content of LCR. */
one->old_lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
- /* Enable access to Enhanced register set */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_CONF_MODE_B);
+ /* Enable access to the desired register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, register_set);
- /* Disable cache updates when writing to EFR registers */
+ /* Disable cache updates when writing to non-general registers */
regcache_cache_bypass(one->regmap, true);
}
-static void sc16is7xx_efr_unlock(struct uart_port *port)
+static void sc16is7xx_regs_unlock(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- /* Re-enable cache updates when writing to normal registers */
+ /* Re-enable cache updates when writing to general registers */
regcache_cache_bypass(one->regmap, false);
/* Restore original content of LCR */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, one->old_lcr);
- mutex_unlock(&one->efr_lock);
+ mutex_unlock(&one->lock);
}
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);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
lockdep_assert_held_once(&port->lock);
@@ -477,7 +441,7 @@ static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit)
static void sc16is7xx_ier_set(struct uart_port *port, u8 bit)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
lockdep_assert_held_once(&port->lock);
@@ -535,10 +499,11 @@ EXPORT_SYMBOL_GPL(sc16is762_devtype);
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
switch (reg) {
- case SC16IS7XX_RHR_REG:
- case SC16IS7XX_IIR_REG:
- case SC16IS7XX_LSR_REG:
- case SC16IS7XX_MSR_REG:
+ case SC16IS7XX_RHR_REG: /* Shared address space with THR & DLL */
+ case SC16IS7XX_IIR_REG: /* Shared address space with FCR & EFR */
+ case SC16IS7XX_LSR_REG: /* Shared address space with XON2 */
+ case SC16IS7XX_MSR_REG: /* Shared address space with TCR & XOFF1 */
+ case SC16IS7XX_SPR_REG: /* Shared address space with TLR & XOFF2 */
case SC16IS7XX_TXLVL_REG:
case SC16IS7XX_RXLVL_REG:
case SC16IS7XX_IOSTATE_REG:
@@ -578,8 +543,6 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg)
*/
static int sc16is7xx_set_baud(struct uart_port *port, int baud)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
- u8 lcr;
unsigned int prescaler = 1;
unsigned long clk = port->uartclk, div = clk / 16 / baud;
@@ -593,23 +556,15 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);
- mutex_lock(&one->efr_lock);
-
- /* Backup LCR and access special register set (DLL/DLH) */
- lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
- SC16IS7XX_LCR_CONF_MODE_A);
+ /* Access special register set (DLL/DLH) */
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_SPECIAL);
/* Write the new divisor */
- regcache_cache_bypass(one->regmap, true);
sc16is7xx_port_write(port, SC16IS7XX_DLH_REG, div / 256);
sc16is7xx_port_write(port, SC16IS7XX_DLL_REG, div % 256);
- regcache_cache_bypass(one->regmap, false);
- /* Restore LCR and access to general register set */
- sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
-
- mutex_unlock(&one->efr_lock);
+ /* Restore access to general register set */
+ sc16is7xx_regs_unlock(port);
return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}
@@ -617,7 +572,7 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
unsigned int iir)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int lsr = 0, bytes_read, i;
bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC);
u8 ch, flag;
@@ -756,7 +711,8 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
unsigned long flags;
unsigned int status, changed;
- lockdep_assert_held_once(&one->efr_lock);
+ /* Lock required as MSR address is shared with TCR and XOFF1. */
+ lockdep_assert_held_once(&one->lock);
status = sc16is7xx_get_hwmctrl(port);
changed = status ^ one->old_mctrl;
@@ -782,18 +738,15 @@ static void sc16is7xx_update_mlines(struct sc16is7xx_one *one)
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
- bool rc = true;
unsigned int iir, rxlen;
struct uart_port *port = &s->p[portno].port;
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
- mutex_lock(&one->efr_lock);
+ guard(mutex)(&one->lock);
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
- if (iir & SC16IS7XX_IIR_NO_INT_BIT) {
- rc = false;
- goto out_port_irq;
- }
+ if (iir & SC16IS7XX_IIR_NO_INT_BIT)
+ return false;
iir &= SC16IS7XX_IIR_ID_MASK;
@@ -833,18 +786,14 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
break;
}
-out_port_irq:
- mutex_unlock(&one->efr_lock);
-
- return rc;
+ return true;
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
{
+ struct sc16is7xx_port *s = dev_id;
bool keep_polling;
- struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id;
-
do {
int i;
@@ -871,16 +820,15 @@ static void sc16is7xx_poll_proc(struct kthread_work *ws)
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
- struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, tx_work);
+ struct uart_port *port = &one->port;
if ((port->rs485.flags & SER_RS485_ENABLED) &&
(port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send);
- mutex_lock(&one->efr_lock);
+ guard(mutex)(&one->lock);
sc16is7xx_handle_tx(port);
- mutex_unlock(&one->efr_lock);
}
static void sc16is7xx_reconf_rs485(struct uart_port *port)
@@ -905,7 +853,7 @@ static void sc16is7xx_reconf_rs485(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 *one = container_of(ws, struct sc16is7xx_one, reg_work);
struct sc16is7xx_one_config config;
unsigned long irqflags;
@@ -943,13 +891,12 @@ static void sc16is7xx_reg_proc(struct kthread_work *ws)
static void sc16is7xx_ms_proc(struct kthread_work *ws)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(ws, ms_work.work);
+ struct sc16is7xx_one *one = container_of(ws, struct sc16is7xx_one, ms_work.work);
struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev);
if (one->port.state) {
- mutex_lock(&one->efr_lock);
- sc16is7xx_update_mlines(one);
- mutex_unlock(&one->efr_lock);
+ scoped_guard(mutex, &one->lock)
+ sc16is7xx_update_mlines(one);
kthread_queue_delayed_work(&s->kworker, &one->ms_work, HZ);
}
@@ -957,7 +904,7 @@ static void sc16is7xx_ms_proc(struct kthread_work *ws)
static void sc16is7xx_enable_ms(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
lockdep_assert_held_once(&port->lock);
@@ -968,7 +915,7 @@ static void sc16is7xx_enable_ms(struct uart_port *port)
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);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
kthread_queue_work(&s->kworker, &one->tx_work);
}
@@ -1007,7 +954,7 @@ static unsigned int sc16is7xx_tx_empty(struct uart_port *port)
static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
/* Called with port lock taken so we can only return cached value */
return one->old_mctrl;
@@ -1016,7 +963,7 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port)
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);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
one->config.flags |= SC16IS7XX_RECONF_MD;
kthread_queue_work(&s->kworker, &one->reg_work);
@@ -1033,7 +980,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
unsigned int lcr, flow = 0;
int baud;
unsigned long flags;
@@ -1106,12 +1053,12 @@ static void sc16is7xx_set_termios(struct uart_port *port,
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
/* Update EFR registers */
- sc16is7xx_efr_lock(port);
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED);
sc16is7xx_port_write(port, SC16IS7XX_XON1_REG, termios->c_cc[VSTART]);
sc16is7xx_port_write(port, SC16IS7XX_XOFF1_REG, termios->c_cc[VSTOP]);
sc16is7xx_port_update(port, SC16IS7XX_EFR_REG,
SC16IS7XX_EFR_FLOWCTRL_BITS, flow);
- sc16is7xx_efr_unlock(port);
+ sc16is7xx_regs_unlock(port);
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
@@ -1136,7 +1083,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
struct serial_rs485 *rs485)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
if (rs485->flags & SER_RS485_ENABLED) {
/*
@@ -1156,14 +1103,14 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
static int sc16is7xx_startup(struct uart_port *port)
{
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
sc16is7xx_power(port, 1);
- /* Reset FIFOs*/
+ /* Reset FIFOs */
val = SC16IS7XX_FCR_RXRESET_BIT | SC16IS7XX_FCR_TXRESET_BIT;
sc16is7xx_port_write(port, SC16IS7XX_FCR_REG, val);
udelay(5);
@@ -1191,8 +1138,7 @@ static int sc16is7xx_startup(struct uart_port *port)
/* This bit must be written with LCR[7] = 0 */
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_IRDA_BIT,
- one->irda_mode ?
- SC16IS7XX_MCR_IRDA_BIT : 0);
+ one->irda_mode ? SC16IS7XX_MCR_IRDA_BIT : 0);
/* Enable the Rx and Tx FIFO */
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
@@ -1220,7 +1166,7 @@ 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);
- struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port);
kthread_cancel_delayed_work_sync(&one->ms_work);
@@ -1510,6 +1456,75 @@ static int sc16is7xx_reset(struct device *dev, struct regmap *regmap)
return 0;
}
+static int sc16is7xx_setup_channel(struct sc16is7xx_one *one, int i,
+ bool *port_registered)
+{
+ struct uart_port *port = &one->port;
+ int ret;
+
+ ret = ida_alloc_max(&sc16is7xx_lines, SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+
+ port->line = ret;
+
+ /* Initialize port data */
+ port->type = PORT_SC16IS7XX;
+ port->fifosize = SC16IS7XX_FIFO_SIZE;
+ port->flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
+ port->iobase = i;
+ /*
+ * Use all ones as membase to make sure uart_configure_port() in
+ * serial_core.c does not abort for SPI/I2C devices where the
+ * membase address is not applicable.
+ */
+ port->membase = (void __iomem *)~0;
+ port->iotype = UPIO_PORT;
+ port->rs485_config = sc16is7xx_config_rs485;
+ port->rs485_supported = sc16is7xx_rs485_supported;
+ port->ops = &sc16is7xx_ops;
+ one->old_mctrl = 0;
+
+ mutex_init(&one->lock);
+
+ ret = uart_get_rs485_mode(port);
+ if (ret)
+ return ret;
+
+ /* Enable access to general register set */
+ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, 0x00);
+
+ /* Disable all interrupts */
+ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
+ /* Disable TX/RX */
+ sc16is7xx_port_write(port, SC16IS7XX_EFCR_REG,
+ SC16IS7XX_EFCR_RXDISABLE_BIT |
+ SC16IS7XX_EFCR_TXDISABLE_BIT);
+
+ /* Initialize kthread work structs */
+ kthread_init_work(&one->tx_work, sc16is7xx_tx_proc);
+ kthread_init_work(&one->reg_work, sc16is7xx_reg_proc);
+ kthread_init_delayed_work(&one->ms_work, sc16is7xx_ms_proc);
+
+ /* Register port */
+ ret = uart_add_one_port(&sc16is7xx_uart, port);
+ if (ret)
+ return ret;
+
+ *port_registered = true;
+
+ sc16is7xx_regs_lock(port, SC16IS7XX_LCR_REG_SET_ENHANCED);
+ /* Enable write access to enhanced features */
+ sc16is7xx_port_write(port, SC16IS7XX_EFR_REG,
+ SC16IS7XX_EFR_ENABLE_BIT);
+ sc16is7xx_regs_unlock(port);
+
+ /* Go to suspend mode */
+ sc16is7xx_power(port, 0);
+
+ return 0;
+}
+
int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
struct regmap *regmaps[], int irq)
{
@@ -1539,10 +1554,8 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
/* Alloc port structure */
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL);
- if (!s) {
- dev_err(dev, "Error allocating port structure\n");
+ if (!s)
return -ENOMEM;
- }
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
@@ -1595,76 +1608,14 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
}
for (i = 0; i < devtype->nr_uart; ++i) {
- ret = ida_alloc_max(&sc16is7xx_lines,
- SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
- if (ret < 0)
- goto out_ports;
-
- s->p[i].port.line = ret;
-
- /* Initialize port data */
s->p[i].port.dev = dev;
s->p[i].port.irq = irq;
- s->p[i].port.type = PORT_SC16IS7XX;
- s->p[i].port.fifosize = SC16IS7XX_FIFO_SIZE;
- s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
- s->p[i].port.iobase = i;
- /*
- * Use all ones as membase to make sure uart_configure_port() in
- * serial_core.c does not abort for SPI/I2C devices where the
- * membase address is not applicable.
- */
- s->p[i].port.membase = (void __iomem *)~0;
- s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.uartclk = freq;
- s->p[i].port.rs485_config = sc16is7xx_config_rs485;
- s->p[i].port.rs485_supported = sc16is7xx_rs485_supported;
- s->p[i].port.ops = &sc16is7xx_ops;
- s->p[i].old_mctrl = 0;
s->p[i].regmap = regmaps[i];
- mutex_init(&s->p[i].efr_lock);
-
- ret = uart_get_rs485_mode(&s->p[i].port);
- if (ret)
- goto out_ports;
-
- /* Disable all interrupts */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0);
- /* Disable TX/RX */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG,
- SC16IS7XX_EFCR_RXDISABLE_BIT |
- SC16IS7XX_EFCR_TXDISABLE_BIT);
-
- /* Initialize kthread work structs */
- kthread_init_work(&s->p[i].tx_work, sc16is7xx_tx_proc);
- kthread_init_work(&s->p[i].reg_work, sc16is7xx_reg_proc);
- kthread_init_delayed_work(&s->p[i].ms_work, sc16is7xx_ms_proc);
-
- /* Register port */
- ret = uart_add_one_port(&sc16is7xx_uart, &s->p[i].port);
+ ret = sc16is7xx_setup_channel(&s->p[i], i, &port_registered[i]);
if (ret)
goto out_ports;
-
- port_registered[i] = true;
-
- /* Enable EFR */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
- SC16IS7XX_LCR_CONF_MODE_B);
-
- regcache_cache_bypass(regmaps[i], true);
-
- /* Enable write access to enhanced features */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFR_REG,
- SC16IS7XX_EFR_ENABLE_BIT);
-
- regcache_cache_bypass(regmaps[i], false);
-
- /* Restore access to general registers */
- sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG, 0x00);
-
- /* Go to suspend mode */
- sc16is7xx_power(&s->p[i].port, 0);
}
sc16is7xx_setup_irda_ports(s);
@@ -1814,4 +1765,4 @@ module_exit(sc16is7xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
-MODULE_DESCRIPTION("SC16IS7xx tty serial core driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " tty serial core driver");
diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h
index afb784eaee45..9c584d6d3593 100644
--- a/drivers/tty/serial/sc16is7xx.h
+++ b/drivers/tty/serial/sc16is7xx.h
@@ -8,7 +8,6 @@
#include <linux/regmap.h>
#include <linux/types.h>
-#define SC16IS7XX_NAME "sc16is7xx"
#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
struct device;
diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c
index cd7de9e057b8..699376c3b3a5 100644
--- a/drivers/tty/serial/sc16is7xx_i2c.c
+++ b/drivers/tty/serial/sc16is7xx_i2c.c
@@ -52,7 +52,7 @@ MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
static struct i2c_driver sc16is7xx_i2c_driver = {
.driver = {
- .name = SC16IS7XX_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = sc16is7xx_dt_ids,
},
.probe = sc16is7xx_i2c_probe,
@@ -63,5 +63,5 @@ static struct i2c_driver sc16is7xx_i2c_driver = {
module_i2c_driver(sc16is7xx_i2c_driver);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SC16IS7xx I2C interface driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver");
MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c
index 20d736b657b1..7e76d0e38da7 100644
--- a/drivers/tty/serial/sc16is7xx_spi.c
+++ b/drivers/tty/serial/sc16is7xx_spi.c
@@ -75,7 +75,7 @@ MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
static struct spi_driver sc16is7xx_spi_driver = {
.driver = {
- .name = SC16IS7XX_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = sc16is7xx_dt_ids,
},
.probe = sc16is7xx_spi_probe,
@@ -86,5 +86,5 @@ static struct spi_driver sc16is7xx_spi_driver = {
module_spi_driver(sc16is7xx_spi_driver);
MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("SC16IS7xx SPI interface driver");
+MODULE_DESCRIPTION(KBUILD_MODNAME " interface driver");
MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 4757293ece8c..9930023e924c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1034,9 +1034,8 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
- int retval;
- down_write(&tty->termios_rwsem);
+ guard(rwsem_write)(&tty->termios_rwsem);
/*
* This semaphore protects port->count. It is also
* very useful to prevent opens. Also, take the
@@ -1044,11 +1043,8 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
* module insertion/removal doesn't change anything
* under us.
*/
- mutex_lock(&port->mutex);
- retval = uart_set_info(tty, port, state, ss);
- mutex_unlock(&port->mutex);
- up_write(&tty->termios_rwsem);
- return retval;
+ guard(mutex)(&port->mutex);
+ return uart_set_info(tty, port, state, ss);
}
/**
@@ -1560,85 +1556,66 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
-
- /*
- * These ioctls don't rely on the hardware to be present.
- */
- switch (cmd) {
- case TIOCSERCONFIG:
- down_write(&tty->termios_rwsem);
- ret = uart_do_autoconfig(tty, state);
- up_write(&tty->termios_rwsem);
- break;
- }
-
- if (ret != -ENOIOCTLCMD)
- goto out;
-
- if (tty_io_error(tty)) {
- ret = -EIO;
- goto out;
+ /* This ioctl doesn't rely on the hardware to be present. */
+ if (cmd == TIOCSERCONFIG) {
+ guard(rwsem_write)(&tty->termios_rwsem);
+ return uart_do_autoconfig(tty, state);
}
- /*
- * The following should only be used when hardware is present.
- */
- switch (cmd) {
- case TIOCMIWAIT:
- ret = uart_wait_modem_status(state, arg);
- break;
- }
+ if (tty_io_error(tty))
+ return -EIO;
- if (ret != -ENOIOCTLCMD)
- goto out;
+ /* This should only be used when the hardware is present. */
+ if (cmd == TIOCMIWAIT)
+ return uart_wait_modem_status(state, arg);
/* rs485_config requires more locking than others */
if (cmd == TIOCSRS485)
down_write(&tty->termios_rwsem);
- mutex_lock(&port->mutex);
- uport = uart_port_check(state);
+ scoped_guard(mutex, &port->mutex) {
+ uport = uart_port_check(state);
- if (!uport || tty_io_error(tty)) {
- ret = -EIO;
- goto out_up;
- }
+ if (!uport || tty_io_error(tty)) {
+ ret = -EIO;
+ break;
+ }
- /*
- * All these rely on hardware being present and need to be
- * protected against the tty being hung up.
- */
+ /*
+ * All these rely on hardware being present and need to be
+ * protected against the tty being hung up.
+ */
- switch (cmd) {
- case TIOCSERGETLSR: /* Get line status register */
- ret = uart_get_lsr_info(tty, state, uarg);
- break;
+ switch (cmd) {
+ case TIOCSERGETLSR: /* Get line status register */
+ ret = uart_get_lsr_info(tty, state, uarg);
+ break;
- case TIOCGRS485:
- ret = uart_get_rs485_config(uport, uarg);
- break;
+ case TIOCGRS485:
+ ret = uart_get_rs485_config(uport, uarg);
+ break;
- case TIOCSRS485:
- ret = uart_set_rs485_config(tty, uport, uarg);
- break;
+ case TIOCSRS485:
+ ret = uart_set_rs485_config(tty, uport, uarg);
+ break;
- case TIOCSISO7816:
- ret = uart_set_iso7816_config(state->uart_port, uarg);
- break;
+ case TIOCSISO7816:
+ ret = uart_set_iso7816_config(state->uart_port, uarg);
+ break;
- case TIOCGISO7816:
- ret = uart_get_iso7816_config(state->uart_port, uarg);
- break;
- default:
- if (uport->ops->ioctl)
- ret = uport->ops->ioctl(uport, cmd, arg);
- break;
+ case TIOCGISO7816:
+ ret = uart_get_iso7816_config(state->uart_port, uarg);
+ break;
+ default:
+ if (uport->ops->ioctl)
+ ret = uport->ops->ioctl(uport, cmd, arg);
+ break;
+ }
}
-out_up:
- mutex_unlock(&port->mutex);
+
if (cmd == TIOCSRS485)
up_write(&tty->termios_rwsem);
-out:
+
return ret;
}
@@ -1651,11 +1628,10 @@ static void uart_set_ldisc(struct tty_struct *tty)
if (!tty_port_initialized(port))
return;
- mutex_lock(&state->port.mutex);
+ guard(mutex)(&state->port.mutex);
uport = uart_port_check(state);
if (uport && uport->ops->set_ldisc)
uport->ops->set_ldisc(uport, &tty->termios);
- mutex_unlock(&state->port.mutex);
}
static void uart_set_termios(struct tty_struct *tty,
@@ -1729,9 +1705,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
state = drv->state + tty->index;
port = &state->port;
- spin_lock_irq(&port->lock);
+ guard(spinlock_irq)(&port->lock);
--port->count;
- spin_unlock_irq(&port->lock);
return;
}
@@ -1843,20 +1818,18 @@ static void uart_hangup(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- unsigned long flags;
pr_debug("uart_hangup(%d)\n", tty->index);
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
WARN(!uport, "hangup of detached port!\n");
if (tty_port_active(port)) {
uart_flush_buffer(tty);
uart_shutdown(tty, state);
- spin_lock_irqsave(&port->lock, flags);
- port->count = 0;
- spin_unlock_irqrestore(&port->lock, flags);
+ scoped_guard(spinlock_irqsave, &port->lock)
+ port->count = 0;
tty_port_set_active(port, false);
tty_port_tty_set(port, NULL);
if (uport && !uart_console(uport))
@@ -1864,7 +1837,6 @@ static void uart_hangup(struct tty_struct *tty)
wake_up_interruptible(&port->open_wait);
wake_up_interruptible(&port->delta_msr_wait);
}
- mutex_unlock(&port->mutex);
}
/* uport == NULL if uart_port has already been removed */
@@ -2969,11 +2941,11 @@ static ssize_t console_show(struct device *dev,
struct uart_port *uport;
bool console = false;
- mutex_lock(&port->mutex);
- uport = uart_port_check(state);
- if (uport)
- console = uart_console_registered(uport);
- mutex_unlock(&port->mutex);
+ scoped_guard(mutex, &port->mutex) {
+ uport = uart_port_check(state);
+ if (uport)
+ console = uart_console_registered(uport);
+ }
return sprintf(buf, "%c\n", console ? 'Y' : 'N');
}
@@ -3158,17 +3130,14 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
struct tty_port *port = &state->port;
struct uart_port *uart_port;
- mutex_lock(&port->mutex);
- uart_port = uart_port_check(state);
- if (uart_port != uport)
- dev_alert(uport->dev, "Removing wrong port: %p != %p\n",
- uart_port, uport);
+ scoped_guard(mutex, &port->mutex) {
+ uart_port = uart_port_check(state);
+ if (uart_port != uport)
+ dev_alert(uport->dev, "Removing wrong port: %p != %p\n", uart_port, uport);
- if (!uart_port) {
- mutex_unlock(&port->mutex);
- return;
+ if (!uart_port)
+ return;
}
- mutex_unlock(&port->mutex);
/*
* Remove the devices from the tty layer
@@ -3197,11 +3166,10 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
uport->type = PORT_UNKNOWN;
uport->port_dev = NULL;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
WARN_ON(atomic_dec_return(&state->refcount) < 0);
wait_event(state->remove_wait, !atomic_read(&state->refcount));
state->uart_port = NULL;
- mutex_unlock(&port->mutex);
}
/**
@@ -3354,7 +3322,7 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port
struct serial_ctrl_device *ctrl_dev = serial_core_get_ctrl_dev(port_dev);
int ctrl_id = port->ctrl_id;
- mutex_lock(&port_mutex);
+ guard(mutex)(&port_mutex);
port->flags |= UPF_DEAD;
@@ -3366,8 +3334,6 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port
/* Drop the serial core controller device if no ports are using it */
if (!serial_core_ctrl_find(drv, phys_dev, ctrl_id))
serial_base_ctrl_device_remove(ctrl_dev);
-
- mutex_unlock(&port_mutex);
}
/**
@@ -3536,6 +3502,14 @@ int uart_get_rs485_mode(struct uart_port *port)
if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
return 0;
+ /*
+ * Retrieve properties only if a firmware node exists. If no firmware
+ * node exists, then don't touch rs485 config and keep initial rs485
+ * properties set by driver.
+ */
+ if (!dev_fwnode(dev))
+ return 0;
+
ret = device_property_read_u32_array(dev, "rs485-rts-delay",
rs485_delay, 2);
if (!ret) {
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 62bb62b82cbe..53edbf1d8963 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -17,29 +17,32 @@
*/
#undef DEBUG
+#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/console.h>
-#include <linux/ctype.h>
#include <linux/cpufreq.h>
+#include <linux/ctype.h>
#include <linux/delay.h>
-#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/ktime.h>
#include <linux/major.h>
#include <linux/minmax.h>
-#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/scatterlist.h>
#include <linux/serial.h>
+#include <linux/serial_core.h>
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
@@ -50,15 +53,186 @@
#include <linux/tty_flip.h>
#ifdef CONFIG_SUPERH
-#include <asm/sh_bios.h>
#include <asm/platform_early.h>
+#include <asm/sh_bios.h>
#endif
#include "rsci.h"
#include "serial_mctrl_gpio.h"
-#include "sh-sci.h"
#include "sh-sci-common.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 */
+ SCDL, /* BRG Frequency Division Register */
+ SCCKS, /* BRG Clock Select Register */
+ HSRTRGR, /* Rx FIFO Data Count Trigger Register */
+ HSTTRGR, /* Tx FIFO Data Count Trigger Register */
+ SEMR, /* Serial extended mode register */
+};
+
+/* SCSMR (Serial Mode Register) */
+#define SCSMR_C_A BIT(7) /* Communication Mode */
+#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
+#define SCSMR_ASYNC 0 /* - Asynchronous mode */
+#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 Mode Register, SCIFA/SCIFB only bits */
+#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
+#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
+#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
+#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
+#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
+#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
+#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
+#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
+#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
+#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
+
+/* Serial Control Register, SCI only bits */
+#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */
+
+/* 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 */
+
+/* Serial Control Register, HSCIF-only bits */
+#define HSSCR_TOT_SHIFT 14
+
+/* 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 (u32)(~(SCI_RESERVED | SCI_RDRF))
+#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
+#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
+#define SCI_BREAK_CLEAR (u32)(~(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 (u32)(~(SCIF_DR | SCIF_RDF))
+#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
+#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
+#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
+
+/* SCFCR (FIFO Control Register) */
+#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */
+#define SCFCR_RTRG0 BIT(6)
+#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */
+#define SCFCR_TTRG0 BIT(4)
+#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_TO BIT(2) /* Timeout */
+#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_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
+#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock 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 */
+#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */
+
+#define HSCIF_SRHP_SHIFT 8
+#define HSCIF_SRHP_MASK 0x0f00
+
+/* 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 */
+#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
+#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
+#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output 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 SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
+#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
+#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
+
+/*
+ * BRG Clock Select Register (Some SCIF and HSCIF)
+ * The Baud Rate Generator for external clock can provide a clock source for
+ * the sampling clock. It outputs either its frequency divided clock, or the
+ * (undivided) (H)SCK external clock.
+ */
+#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
+#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
+
+#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
+#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF)
+#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
+#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
+#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
+#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
+
+#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask)
+
+#define SCxSR_RDxF_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
+#define SCxSR_ERROR_CLEAR(port) \
+ (to_sci_port(port)->params->error_clear)
+#define SCxSR_TDxE_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
+#define SCxSR_BREAK_CLEAR(port) \
+ (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
+
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
(port)->irqs[SCIx_RXI_IRQ]) || \
@@ -1024,8 +1198,16 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
status = s->ops->read_reg(port, s->params->overrun_reg);
if (status & s->params->overrun_mask) {
- status &= ~s->params->overrun_mask;
- s->ops->write_reg(port, s->params->overrun_reg, status);
+ if (s->type == SCI_PORT_RSCI) {
+ /*
+ * All of the CFCLR_*C clearing bits match the corresponding
+ * CSR_*status bits. So, reuse the overrun mask for clearing.
+ */
+ s->ops->clear_SCxSR(port, s->params->overrun_mask);
+ } else {
+ status &= ~s->params->overrun_mask;
+ s->ops->write_reg(port, s->params->overrun_reg, status);
+ }
port->icount.overrun++;
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
deleted file mode 100644
index 951681aba586..000000000000
--- a/drivers/tty/serial/sh-sci.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#include <linux/bitops.h>
-#include <linux/serial_core.h>
-#include <linux/io.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 */
- SCDL, /* BRG Frequency Division Register */
- SCCKS, /* BRG Clock Select Register */
- HSRTRGR, /* Rx FIFO Data Count Trigger Register */
- HSTTRGR, /* Tx FIFO Data Count Trigger Register */
- SEMR, /* Serial extended mode register */
-};
-
-
-/* SCSMR (Serial Mode Register) */
-#define SCSMR_C_A BIT(7) /* Communication Mode */
-#define SCSMR_CSYNC BIT(7) /* - Clocked synchronous mode */
-#define SCSMR_ASYNC 0 /* - Asynchronous mode */
-#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 Mode Register, SCIFA/SCIFB only bits */
-#define SCSMR_CKEDG BIT(12) /* Transmit/Receive Clock Edge Select */
-#define SCSMR_SRC_MASK 0x0700 /* Sampling Control */
-#define SCSMR_SRC_16 0x0000 /* Sampling rate 1/16 */
-#define SCSMR_SRC_5 0x0100 /* Sampling rate 1/5 */
-#define SCSMR_SRC_7 0x0200 /* Sampling rate 1/7 */
-#define SCSMR_SRC_11 0x0300 /* Sampling rate 1/11 */
-#define SCSMR_SRC_13 0x0400 /* Sampling rate 1/13 */
-#define SCSMR_SRC_17 0x0500 /* Sampling rate 1/17 */
-#define SCSMR_SRC_19 0x0600 /* Sampling rate 1/19 */
-#define SCSMR_SRC_27 0x0700 /* Sampling rate 1/27 */
-
-/* Serial Control Register, SCI only bits */
-#define SCSCR_TEIE BIT(2) /* Transmit End Interrupt Enable */
-
-/* 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 */
-
-/* Serial Control Register, HSCIF-only bits */
-#define HSSCR_TOT_SHIFT 14
-
-/* 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 (u32)(~(SCI_RESERVED | SCI_RDRF))
-#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER))
-#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE))
-#define SCI_BREAK_CLEAR (u32)(~(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 (u32)(~(SCIF_DR | SCIF_RDF))
-#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER))
-#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE))
-#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK))
-
-/* SCFCR (FIFO Control Register) */
-#define SCFCR_RTRG1 BIT(7) /* Receive FIFO Data Count Trigger */
-#define SCFCR_RTRG0 BIT(6)
-#define SCFCR_TTRG1 BIT(5) /* Transmit FIFO Data Count Trigger */
-#define SCFCR_TTRG0 BIT(4)
-#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_TO BIT(2) /* Timeout */
-#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_SCKIO BIT(3) /* Serial Port Clock Pin Input/Output */
-#define SCSPTR_SCKDT BIT(2) /* Serial Port Clock 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 */
-#define HSCIF_SRDE BIT(14) /* Sampling Point Register Enable */
-
-#define HSCIF_SRHP_SHIFT 8
-#define HSCIF_SRHP_MASK 0x0f00
-
-/* 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 */
-#define SCPCR_SCKC BIT(2) /* Serial Port SCK Pin / Output Pin */
-#define SCPCR_RXDC BIT(1) /* Serial Port RXD Pin / Input Pin */
-#define SCPCR_TXDC BIT(0) /* Serial Port TXD Pin / Output 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 SCPDR_SCKD BIT(2) /* Serial Port SCK Output Pin Data */
-#define SCPDR_RXDD BIT(1) /* Serial Port RXD Input Pin Data */
-#define SCPDR_TXDD BIT(0) /* Serial Port TXD Output Pin Data */
-
-/*
- * BRG Clock Select Register (Some SCIF and HSCIF)
- * The Baud Rate Generator for external clock can provide a clock source for
- * the sampling clock. It outputs either its frequency divided clock, or the
- * (undivided) (H)SCK external clock.
- */
-#define SCCKS_CKS BIT(15) /* Select (H)SCK (1) or divided SC_CLK (0) */
-#define SCCKS_XIN BIT(14) /* SC_CLK uses bus clock (1) or SCIF_CLK (0) */
-
-#define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
-#define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_DR | SCIF_RDF)
-#define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
-#define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
-#define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
-#define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
-
-#define SCxSR_ERRORS(port) (to_sci_port(port)->params->error_mask)
-
-#define SCxSR_RDxF_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR)
-#define SCxSR_ERROR_CLEAR(port) \
- (to_sci_port(port)->params->error_clear)
-#define SCxSR_TDxE_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR)
-#define SCxSR_BREAK_CLEAR(port) \
- (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR)
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 8c9366321f8e..092755f35683 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -1133,6 +1133,9 @@ static int sprd_clk_init(struct uart_port *uport)
clk_uart = devm_clk_get(uport->dev, "uart");
if (IS_ERR(clk_uart)) {
+ if (PTR_ERR(clk_uart) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
dev_warn(uport->dev, "uart%d can't get uart clock\n",
uport->line);
clk_uart = NULL;
@@ -1140,6 +1143,9 @@ static int sprd_clk_init(struct uart_port *uport)
clk_parent = devm_clk_get(uport->dev, "source");
if (IS_ERR(clk_parent)) {
+ if (PTR_ERR(clk_parent) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
dev_warn(uport->dev, "uart%d can't get source clock\n",
uport->line);
clk_parent = NULL;
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index a66b44d21fba..c793fc74c26b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -190,7 +190,6 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @port: Pointer to the UART port
* @uartclk: Reference clock
* @pclk: APB clock
- * @cdns_uart_driver: Pointer to UART driver
* @baud: Current baud rate
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
@@ -204,7 +203,6 @@ struct cdns_uart {
struct uart_port *port;
struct clk *uartclk;
struct clk *pclk;
- struct uart_driver *cdns_uart_driver;
unsigned int baud;
struct notifier_block clk_rate_change_nb;
u32 quirks;
@@ -1465,7 +1463,6 @@ static struct console cdns_uart_console = {
static int cdns_uart_suspend(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
- struct cdns_uart *cdns_uart = port->private_data;
int may_wake;
may_wake = device_may_wakeup(device);
@@ -1489,7 +1486,7 @@ static int cdns_uart_suspend(struct device *device)
* Call the API provided in serial_core.c file which handles
* the suspend.
*/
- return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
+ return uart_suspend_port(&cdns_uart_uart_driver, port);
}
/**
@@ -1550,7 +1547,7 @@ static int cdns_uart_resume(struct device *device)
uart_port_unlock_irqrestore(port, flags);
}
- return uart_resume_port(cdns_uart->cdns_uart_driver, port);
+ return uart_resume_port(&cdns_uart_uart_driver, port);
}
#endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
@@ -1686,8 +1683,6 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
}
- cdns_uart_data->cdns_uart_driver = &cdns_uart_uart_driver;
-
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
if (match && match->data) {
const struct cdns_platform_data *data = match->data;
@@ -1862,7 +1857,7 @@ err_out_clk_dis_pclk:
clk_disable_unprepare(cdns_uart_data->pclk);
err_out_unregister_driver:
if (!instances)
- uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+ uart_unregister_driver(&cdns_uart_uart_driver);
return rc;
}
@@ -1880,7 +1875,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
#endif
- uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
+ uart_remove_one_port(&cdns_uart_uart_driver, port);
port->mapbase = 0;
clk_disable_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk);
@@ -1896,7 +1891,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
reset_control_assert(cdns_uart_data->rstc);
if (!--instances)
- uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
+ uart_unregister_driver(&cdns_uart_uart_driver);
}
static struct platform_driver cdns_uart_platform_driver = {