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.h10
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c5
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c4
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c3
-rw-r--r--drivers/tty/serial/8250/8250_core.c9
-rw-r--r--drivers/tty/serial/8250/8250_dma.c2
-rw-r--r--drivers/tty/serial/8250/8250_dw.c73
-rw-r--r--drivers/tty/serial/8250/8250_early.c2
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c8
-rw-r--r--drivers/tty/serial/8250/8250_ni.c446
-rw-r--r--drivers/tty/serial/8250/8250_of.c16
-rw-r--r--drivers/tty/serial/8250/8250_omap.c38
-rw-r--r--drivers/tty/serial/8250/8250_pci.c46
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c10
-rw-r--r--drivers/tty/serial/8250/8250_platform.c9
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c10
-rw-r--r--drivers/tty/serial/8250/8250_port.c150
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c23
-rw-r--r--drivers/tty/serial/8250/Kconfig13
-rw-r--r--drivers/tty/serial/8250/Makefile1
-rw-r--r--drivers/tty/serial/Kconfig44
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/altera_jtaguart.c10
-rw-r--r--drivers/tty/serial/altera_uart.c11
-rw-r--r--drivers/tty/serial/amba-pl011.c282
-rw-r--r--drivers/tty/serial/atmel_serial.c26
-rw-r--r--drivers/tty/serial/fsl_lpuart.c509
-rw-r--r--drivers/tty/serial/icom.c9
-rw-r--r--drivers/tty/serial/imx.c33
-rw-r--r--drivers/tty/serial/jsm/jsm_tty.c1
-rw-r--r--drivers/tty/serial/kgdb_nmi.c381
-rw-r--r--drivers/tty/serial/kgdboc.c8
-rw-r--r--drivers/tty/serial/lantiq.c4
-rw-r--r--drivers/tty/serial/liteuart.c6
-rw-r--r--drivers/tty/serial/ma35d1_serial.c2
-rw-r--r--drivers/tty/serial/max3100.c9
-rw-r--r--drivers/tty/serial/max310x.c7
-rw-r--r--drivers/tty/serial/milbeaut_usio.c5
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c3
-rw-r--r--drivers/tty/serial/msm_serial.c6
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/pch_uart.c3
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c25
-rw-r--r--drivers/tty/serial/sa1100.c6
-rw-r--r--drivers/tty/serial/samsung_tty.c6
-rw-r--r--drivers/tty/serial/sc16is7xx.c44
-rw-r--r--drivers/tty/serial/sccnxp.c4
-rw-r--r--drivers/tty/serial/serial_base_bus.c4
-rw-r--r--drivers/tty/serial/serial_core.c422
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c62
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h27
-rw-r--r--drivers/tty/serial/serial_port.c9
-rw-r--r--drivers/tty/serial/sh-sci-common.h167
-rw-r--r--drivers/tty/serial/sh-sci.c597
-rw-r--r--drivers/tty/serial/sh-sci.h2
-rw-r--r--drivers/tty/serial/sifive.c94
-rw-r--r--drivers/tty/serial/stm32-usart.c6
-rw-r--r--drivers/tty/serial/sunsu.c178
-rw-r--r--drivers/tty/serial/tegra-utc.c625
-rw-r--r--drivers/tty/serial/uartlite.c25
-rw-r--r--drivers/tty/serial/xilinx_uartps.c8
61 files changed, 2941 insertions, 1611 deletions
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 10a706fe4b24..18530c31a598 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -223,16 +223,10 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line);
-void serial8250_rpm_get(struct uart_8250_port *p);
-void serial8250_rpm_put(struct uart_8250_port *p);
-
-void serial8250_rpm_get_tx(struct uart_8250_port *p);
-void serial8250_rpm_put_tx(struct uart_8250_port *p);
-
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
-void serial8250_em485_start_tx(struct uart_8250_port *p);
-void serial8250_em485_stop_tx(struct uart_8250_port *p);
+void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier);
+void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier);
void serial8250_em485_destroy(struct uart_8250_port *p);
extern struct serial_rs485 serial8250_em485_supported;
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index e5da9ce26006..26fc0464f1cc 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -304,7 +304,8 @@ static void aspeed_vuart_unthrottle(struct uart_port *port)
static void aspeed_vuart_unthrottle_exp(struct timer_list *timer)
{
- struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer);
+ struct aspeed_vuart *vuart = timer_container_of(vuart, timer,
+ unthrottle_timer);
struct uart_8250_port *up = vuart->port;
if (!tty_buffer_space_avail(&up->port.state->port)) {
@@ -550,7 +551,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
{
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
- del_timer_sync(&vuart->unthrottle_timer);
+ timer_delete_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index fdb53b54e99e..0609582a62f7 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -46,7 +46,7 @@ struct bcm2835aux_data {
u32 cntl;
};
-static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
+static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
@@ -65,7 +65,7 @@ static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
serial8250_out_MCR(up, UART_MCR_RTS);
}
-static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
+static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
serial8250_out_MCR(up, 0);
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index d0b18358859e..742004d63c6f 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -1056,8 +1056,7 @@ static int brcmuart_probe(struct platform_device *pdev)
}
/* setup HR timer */
- hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- priv->hrt.function = brcmuart_hrtimer_func;
+ hrtimer_setup(&priv->hrt, brcmuart_hrtimer_func, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
up.port.shutdown = brcmuart_shutdown;
up.port.startup = brcmuart_startup;
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 68baf75bdadc..7a6050f1c094 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -206,7 +206,7 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up)
*/
static void serial8250_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
up->port.handle_irq(&up->port);
mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port));
@@ -214,7 +214,7 @@ static void serial8250_timeout(struct timer_list *t)
static void serial8250_backup_timeout(struct timer_list *t)
{
- struct uart_8250_port *up = from_timer(up, t, timer);
+ struct uart_8250_port *up = timer_container_of(up, t, timer);
unsigned int iir, ier = 0, lsr;
unsigned long flags;
@@ -298,7 +298,7 @@ static void univ8250_release_irq(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
- del_timer_sync(&up->timer);
+ timer_delete_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (port->irq)
serial_unlink_irq_chain(up);
@@ -461,7 +461,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
char *options)
{
char match[] = "uart"; /* 8250-specific earlycon name */
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
@@ -675,7 +675,6 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
uart_port_lock_irqsave(port, &flags);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
- up->port.read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
uart_port_unlock_irqrestore(port, flags);
}
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index f245a84f4a50..bdd26c9f34bd 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -162,7 +162,7 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
*/
dma->tx_size = 0;
- dmaengine_terminate_async(dma->rxchan);
+ dmaengine_terminate_async(dma->txchan);
}
int serial8250_rx_dma(struct uart_8250_port *p)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 6afcf27db3b8..1902f29444a1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -107,11 +107,23 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
return value;
}
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
static void dw8250_force_idle(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int lsr;
+ /*
+ * The following call currently performs serial_out()
+ * against the FCR register. Because it differs to LCR
+ * there will be no infinite loop, but if it ever gets
+ * modified, we might need a new custom version of it
+ * that avoids infinite recursion.
+ */
serial8250_clear_and_reinit_fifos(up);
/*
@@ -120,14 +132,19 @@ static void dw8250_force_idle(struct uart_port *p)
* enabled.
*/
if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = p->serial_in(p, UART_LSR);
+ lsr = serial_port_in(p, UART_LSR);
if (!(lsr & UART_LSR_DR))
return;
}
- (void)p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
}
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
@@ -139,7 +156,7 @@ static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
/* Make sure LCR write wasn't ignored */
while (tries--) {
- unsigned int lcr = p->serial_in(p, offset);
+ unsigned int lcr = serial_port_in(p, offset);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
@@ -260,7 +277,7 @@ static int dw8250_handle_irq(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
struct dw8250_data *d = to_dw8250_data(p->private_data);
- unsigned int iir = p->serial_in(p, UART_IIR);
+ unsigned int iir = serial_port_in(p, UART_IIR);
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
@@ -281,7 +298,7 @@ static int dw8250_handle_irq(struct uart_port *p)
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
- (void) p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
uart_port_unlock_irqrestore(p, flags);
}
@@ -303,7 +320,7 @@ static int dw8250_handle_irq(struct uart_port *p)
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
- (void)p->serial_in(p, d->pdata->usr_reg);
+ serial_port_in(p, d->pdata->usr_reg);
return 1;
}
@@ -390,7 +407,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int mcr = p->serial_in(p, UART_MCR);
+ unsigned int mcr = serial_port_in(p, UART_MCR);
if (up->capabilities & UART_CAP_IRDA) {
if (termios->c_line == N_IRDA)
@@ -398,7 +415,7 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
else
mcr &= ~DW_UART_MCR_SIRE;
- p->serial_out(p, UART_MCR, mcr);
+ serial_port_out(p, UART_MCR, mcr);
}
serial8250_do_set_ldisc(p, termios);
}
@@ -421,6 +438,18 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev;
}
+static void dw8250_setup_dma_filter(struct uart_port *p, struct dw8250_data *data)
+{
+ /* Platforms with iDMA 64-bit */
+ if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) {
+ data->data.dma.rx_param = p->dev->parent;
+ data->data.dma.tx_param = p->dev->parent;
+ data->data.dma.fn = dw8250_idma_filter;
+ } else {
+ data->data.dma.fn = dw8250_fallback_dma_filter;
+ }
+}
+
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
{
if (max_burst >= 8)
@@ -459,8 +488,8 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
- unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
- u32 cpr_value = data->pdata ? data->pdata->cpr_value : 0;
+ unsigned int quirks = data->pdata->quirks;
+ u32 cpr_value = data->pdata->cpr_value;
if (quirks & DW_UART_QUIRK_CPR_VALUE)
data->data.cpr_value = cpr_value;
@@ -491,14 +520,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32;
data->uart_16550_compatible = true;
}
-
- /* Platforms with iDMA 64-bit */
- if (platform_get_resource_byname(to_platform_device(p->dev),
- IORESOURCE_MEM, "lpss_priv")) {
- data->data.dma.rx_param = p->dev->parent;
- data->data.dma.tx_param = p->dev->parent;
- data->data.dma.fn = dw8250_idma_filter;
- }
}
static void dw8250_reset_control_assert(void *data)
@@ -520,7 +541,6 @@ static int dw8250_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
spin_lock_init(&p->lock);
- p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm;
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
@@ -532,13 +552,8 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- data->data.dma.fn = dw8250_fallback_dma_filter;
- data->pdata = device_get_match_data(p->dev);
p->private_data = &data->data;
- data->uart_16550_compatible = device_property_read_bool(dev,
- "snps,uart-16550-compatible");
-
p->mapbase = regs->start;
p->mapsize = resource_size(regs);
@@ -626,11 +641,19 @@ static int dw8250_probe(struct platform_device *pdev)
if (err)
return err;
- dw8250_quirks(p, data);
+ data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
+
+ data->pdata = device_get_match_data(p->dev);
+ if (data->pdata)
+ dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
if (data->uart_16550_compatible)
p->handle_irq = NULL;
+ else if (data->pdata)
+ p->handle_irq = dw8250_handle_irq;
+
+ dw8250_setup_dma_filter(p, data);
if (!data->skip_autocfg)
dw8250_setup_port(p);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 842422921765..dc0371857ecb 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -77,6 +77,8 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
outb(value, port->iobase + offset);
break;
#endif
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index 1b7bd55619c6..649ae5c8304d 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -32,7 +32,7 @@ int fsl8250_handle_irq(struct uart_port *port)
uart_port_lock_irqsave(&up->port, &flags);
- iir = port->serial_in(port, UART_IIR);
+ iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT) {
uart_port_unlock_irqrestore(&up->port, flags);
return 0;
@@ -54,12 +54,12 @@ int fsl8250_handle_irq(struct uart_port *port)
if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
(up->lsr_saved_flags & UART_LSR_BI))) {
up->lsr_saved_flags &= ~UART_LSR_BI;
- port->serial_in(port, UART_RX);
+ serial_port_in(port, UART_RX);
uart_port_unlock_irqrestore(&up->port, flags);
return 1;
}
- lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
+ lsr = orig_lsr = serial_port_in(port, UART_LSR);
/* Process incoming characters first */
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
@@ -71,7 +71,7 @@ int fsl8250_handle_irq(struct uart_port *port)
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
unsigned long delay;
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
new file mode 100644
index 000000000000..b0e44fb00b3a
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -0,0 +1,446 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NI 16550 UART Driver
+ *
+ * The National Instruments (NI) 16550 is a UART that is compatible with the
+ * TL16C550C and OX16C950B register interfaces, but has additional functions
+ * for RS-485 transceiver control. This driver implements support for the
+ * additional functionality on top of the standard serial8250 core.
+ *
+ * Copyright 2012-2023 National Instruments Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/serial_core.h>
+#include <linux/types.h>
+
+#include "8250.h"
+
+/* Extra bits in UART_ACR */
+#define NI16550_ACR_AUTO_DTR_EN BIT(4)
+
+/* TFS - TX FIFO Size */
+#define NI16550_TFS_OFFSET 0x0C
+/* RFS - RX FIFO Size */
+#define NI16550_RFS_OFFSET 0x0D
+
+/* PMR - Port Mode Register */
+#define NI16550_PMR_OFFSET 0x0E
+/* PMR[1:0] - Port Capabilities */
+#define NI16550_PMR_CAP_MASK GENMASK(1, 0)
+#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */
+#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */
+#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */
+#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */
+/* PMR[4] - Interface Mode */
+#define NI16550_PMR_MODE_MASK GENMASK(4, 4)
+#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */
+#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */
+
+/* PCR - Port Control Register */
+/*
+ * Wire Mode | Tx enabled? | Rx enabled?
+ * ---------------|----------------------|--------------------------
+ * PCR_RS422 | Always | Always
+ * PCR_ECHO_RS485 | When DTR asserted | Always
+ * PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled
+ * PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled
+ */
+#define NI16550_PCR_OFFSET 0x0F
+#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0)
+#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0)
+#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1)
+#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2)
+#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3)
+#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
+#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
+
+/* flags for ni16550_device_info */
+#define NI_HAS_PMR BIT(0)
+
+struct ni16550_device_info {
+ u32 uartclk;
+ u8 prescaler;
+ u8 flags;
+};
+
+struct ni16550_data {
+ int line;
+ struct clk *clk;
+};
+
+static int ni16550_enable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr |= NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr);
+ port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_disable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
+ u8 pcr;
+
+ pcr = serial_port_in(port, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
+
+ if ((rs485->flags & SER_RS485_MODE_RS422) ||
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ /* RS-422 */
+ pcr |= NI16550_PCR_RS422;
+ up->acr &= ~NI16550_ACR_AUTO_DTR_EN;
+ } else {
+ /* RS-485 2-wire Auto */
+ pcr |= NI16550_PCR_AUTO_RS485;
+ up->acr |= NI16550_ACR_AUTO_DTR_EN;
+ }
+
+ dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
+ serial_port_out(port, NI16550_PCR_OFFSET, pcr);
+ serial_icr_write(up, UART_ACR, up->acr);
+
+ return 0;
+}
+
+static bool is_pmr_rs232_mode(struct uart_8250_port *up)
+{
+ u8 pmr = serial_in(up, NI16550_PMR_OFFSET);
+ u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK;
+ u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK;
+
+ /*
+ * If the PMR is not implemented, then by default NI UARTs are
+ * connected to RS-485 transceivers
+ */
+ if (pmr_cap == NI16550_PMR_NOT_IMPL)
+ return false;
+
+ if (pmr_cap == NI16550_PMR_CAP_DUAL)
+ /*
+ * If the port is dual-mode capable, then read the mode bit
+ * to know the current mode
+ */
+ return pmr_mode == NI16550_PMR_MODE_RS232;
+ /*
+ * If it is not dual-mode capable, then decide based on the
+ * capability
+ */
+ return pmr_cap == NI16550_PMR_CAP_RS232;
+}
+
+static void ni16550_config_prescaler(struct uart_8250_port *up,
+ u8 prescaler)
+{
+ /*
+ * Page in the Enhanced Mode Registers
+ * Sets EFR[4] for Enhanced Mode.
+ */
+ u8 lcr_value;
+ u8 efr_value;
+
+ lcr_value = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ efr_value = serial_in(up, UART_EFR);
+ efr_value |= UART_EFR_ECB;
+
+ serial_out(up, UART_EFR, efr_value);
+
+ /* Page out the Enhanced Mode Registers */
+ serial_out(up, UART_LCR, lcr_value);
+
+ /* Set prescaler to CPR register. */
+ serial_out(up, UART_SCR, UART_CPR);
+ serial_out(up, UART_ICR, prescaler);
+}
+
+static const struct serial_rs485 ni16550_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ /*
+ * delay_rts_* and RX_DURING_TX are not supported.
+ *
+ * RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver
+ * is connected in only one way and we don't need userspace to tell
+ * us, but want to retain compatibility with applications that do.
+ */
+};
+
+static void ni16550_rs485_setup(struct uart_port *port)
+{
+ port->rs485_config = ni16550_rs485_config;
+ port->rs485_supported = ni16550_rs485_supported;
+ /*
+ * The hardware comes up by default in 2-wire auto mode and we
+ * set the flags to represent that
+ */
+ port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
+}
+
+static int ni16550_port_startup(struct uart_port *port)
+{
+ int ret;
+
+ ret = serial8250_do_startup(port);
+ if (ret)
+ return ret;
+
+ return ni16550_enable_transceivers(port);
+}
+
+static void ni16550_port_shutdown(struct uart_port *port)
+{
+ ni16550_disable_transceivers(port);
+
+ serial8250_do_shutdown(port);
+}
+
+static int ni16550_get_regs(struct platform_device *pdev,
+ struct uart_port *port)
+{
+ struct resource *regs;
+
+ regs = platform_get_mem_or_io(pdev, 0);
+ if (!regs)
+ return dev_err_probe(&pdev->dev, -EINVAL, "no registers defined\n");
+
+ switch (resource_type(regs)) {
+ case IORESOURCE_IO:
+ port->iotype = UPIO_PORT;
+ port->iobase = regs->start;
+
+ return 0;
+ case IORESOURCE_MEM:
+ port->iotype = UPIO_MEM;
+ port->mapbase = regs->start;
+ port->mapsize = resource_size(regs);
+ port->flags |= UPF_IOREMAP;
+
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Very old implementations don't have the TFS or RFS registers
+ * defined, so we may read all-0s or all-1s. For such devices,
+ * assume a FIFO size of 128.
+ */
+static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg)
+{
+ u8 value = serial_in(uart, reg);
+
+ if (value == 0x00 || value == 0xFF)
+ return 128;
+
+ return value;
+}
+
+static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ up->mcr |= UART_MCR_CLKSEL;
+ serial8250_do_set_mctrl(port, mctrl);
+}
+
+static int ni16550_probe(struct platform_device *pdev)
+{
+ const struct ni16550_device_info *info;
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = {};
+ unsigned int txfifosz, rxfifosz;
+ unsigned int prescaler;
+ struct ni16550_data *data;
+ const char *portmode;
+ bool rs232_property;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&uart.port.lock);
+
+ ret = ni16550_get_regs(pdev, &uart.port);
+ if (ret < 0)
+ return ret;
+
+ /* early setup so that serial_in()/serial_out() work */
+ serial8250_set_defaults(&uart);
+
+ info = device_get_match_data(dev);
+
+ uart.port.dev = dev;
+ uart.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.startup = ni16550_port_startup;
+ uart.port.shutdown = ni16550_port_shutdown;
+
+ /*
+ * Hardware instantiation of FIFO sizes are held in registers.
+ */
+ txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET);
+ rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET);
+
+ dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n",
+ txfifosz, rxfifosz);
+
+ uart.port.type = PORT_16550A;
+ uart.port.fifosize = txfifosz;
+ uart.tx_loadsz = txfifosz;
+ uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+ uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
+
+ /*
+ * Declaration of the base clock frequency can come from one of:
+ * - static declaration in this driver (for older ACPI IDs)
+ * - a "clock-frequency" ACPI
+ */
+ uart.port.uartclk = info->uartclk;
+
+ ret = uart_read_port_properties(&uart.port);
+ if (ret)
+ return ret;
+
+ if (!uart.port.uartclk) {
+ data->clk = devm_clk_get_enabled(dev, NULL);
+ if (!IS_ERR(data->clk))
+ uart.port.uartclk = clk_get_rate(data->clk);
+ }
+
+ if (!uart.port.uartclk)
+ return dev_err_probe(dev, -ENODEV, "unable to determine clock frequency!\n");
+
+ prescaler = info->prescaler;
+ device_property_read_u32(dev, "clock-prescaler", &prescaler);
+ if (prescaler) {
+ uart.port.set_mctrl = ni16550_set_mctrl;
+ ni16550_config_prescaler(&uart, (u8)prescaler);
+ }
+
+ /*
+ * The determination of whether or not this is an RS-485 or RS-232 port
+ * can come from the PMR (if present), otherwise we're solely an RS-485
+ * port.
+ *
+ * This is a device-specific property, and there are old devices in the
+ * field using "transceiver" as an ACPI property, so we have to check
+ * for that as well.
+ */
+ if (!device_property_read_string(dev, "transceiver", &portmode)) {
+ rs232_property = strncmp(portmode, "RS-232", 6) == 0;
+
+ dev_dbg(dev, "port is in %s mode (via device property)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else if (info->flags & NI_HAS_PMR) {
+ rs232_property = is_pmr_rs232_mode(&uart);
+
+ dev_dbg(dev, "port is in %s mode (via PMR)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else {
+ rs232_property = 0;
+
+ dev_dbg(dev, "port is fixed as RS-485\n");
+ }
+
+ if (!rs232_property) {
+ /*
+ * Neither the 'transceiver' property nor the PMR indicate
+ * that this is an RS-232 port, so it must be an RS-485 one.
+ */
+ ni16550_rs485_setup(&uart.port);
+ }
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ return ret;
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+}
+
+static void ni16550_remove(struct platform_device *pdev)
+{
+ struct ni16550_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+}
+
+/* NI 16550 RS-485 Interface */
+static const struct ni16550_device_info nic7750 = {
+ .uartclk = 33333333,
+};
+
+/* NI CVS-145x RS-485 Interface */
+static const struct ni16550_device_info nic7772 = {
+ .uartclk = 1843200,
+ .flags = NI_HAS_PMR,
+};
+
+/* NI cRIO-904x RS-485 Interface */
+static const struct ni16550_device_info nic792b = {
+ /* Sets UART clock rate to 22.222 MHz with 1.125 prescale */
+ .uartclk = 22222222,
+ .prescaler = 0x09,
+};
+
+/* NI sbRIO 96x8 RS-232/485 Interfaces */
+static const struct ni16550_device_info nic7a69 = {
+ /* Set UART clock rate to 29.629 MHz with 1.125 prescale */
+ .uartclk = 29629629,
+ .prescaler = 0x09,
+};
+
+static const struct acpi_device_id ni16550_acpi_match[] = {
+ { "NIC7750", (kernel_ulong_t)&nic7750 },
+ { "NIC7772", (kernel_ulong_t)&nic7772 },
+ { "NIC792B", (kernel_ulong_t)&nic792b },
+ { "NIC7A69", (kernel_ulong_t)&nic7a69 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
+
+static struct platform_driver ni16550_driver = {
+ .driver = {
+ .name = "ni16550",
+ .acpi_match_table = ni16550_acpi_match,
+ },
+ .probe = ni16550_probe,
+ .remove = ni16550_remove,
+};
+
+module_platform_driver(ni16550_driver);
+
+MODULE_AUTHOR("Emerson Electric Co.");
+MODULE_DESCRIPTION("NI 16550 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 64aed7efc569..d178b6c54ea1 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -24,6 +24,7 @@
struct of_serial_info {
struct clk *clk;
+ struct clk *bus_clk;
struct reset_control *rst;
int type;
int line;
@@ -110,7 +111,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
spin_lock_init(&port->lock);
if (resource_type(&resource) == IORESOURCE_IO) {
- port->iotype = UPIO_PORT;
port->iobase = resource.start;
} else {
port->mapbase = resource.start;
@@ -124,12 +124,22 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
/* Get clk rate through clk driver if present */
if (!port->uartclk) {
- info->clk = devm_clk_get_enabled(dev, NULL);
+ struct clk *bus_clk;
+
+ bus_clk = devm_clk_get_optional_enabled(dev, "bus");
+ if (IS_ERR(bus_clk)) {
+ ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");
+ goto err_pmruntime;
+ }
+
+ /* If the bus clock is required, core clock must be named */
+ info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL);
if (IS_ERR(info->clk)) {
ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
goto err_pmruntime;
}
+ info->bus_clk = bus_clk;
port->uartclk = clk_get_rate(info->clk);
}
/* If current-speed was set, then try not to change it. */
@@ -291,6 +301,7 @@ static int of_serial_suspend(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_put_sync(dev);
clk_disable_unprepare(info->clk);
+ clk_disable_unprepare(info->bus_clk);
}
return 0;
}
@@ -303,6 +314,7 @@ static int of_serial_resume(struct device *dev)
if (!uart_console(port) || console_suspend_enabled) {
pm_runtime_get_sync(dev);
+ clk_prepare_enable(info->bus_clk);
clk_prepare_enable(info->clk);
}
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 9eb9aa766811..72ae08d6204f 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -365,7 +365,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
if (up->port.rs485.flags & SER_RS485_ENABLED &&
up->port.rs485_config == serial8250_em485_config)
- serial8250_em485_stop_tx(up);
+ serial8250_em485_stop_tx(up, true);
}
/*
@@ -412,7 +412,13 @@ static void omap_8250_set_termios(struct uart_port *port,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ /*
+ * Specify which conditions may be considered for error
+ * handling and the ignoring of characters. The actual
+ * ignoring of characters only occurs if the bit is set
+ * in @ignore_status_mask as well.
+ */
+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | PARMRK))
@@ -686,7 +692,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
/* Synchronize UART_IER access against the console. */
uart_port_lock(port);
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
@@ -838,7 +844,6 @@ static void omap_8250_unthrottle(struct uart_port *port)
if (up->dma)
up->dma->rx_dma(up);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
- port->read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
uart_port_unlock_irqrestore(port, flags);
@@ -1168,16 +1173,6 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return 0;
}
- sg_init_table(&sg, 1);
- ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
- if (ret != 1) {
- serial8250_clear_THRI(p);
- return 0;
- }
-
- dma->tx_size = sg_dma_len(&sg);
-
if (priv->habit & OMAP_DMA_TX_KICK) {
unsigned char c;
u8 tx_lvl;
@@ -1202,18 +1197,22 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EBUSY;
goto err;
}
- if (dma->tx_size < 4) {
+ if (kfifo_len(&tport->xmit_fifo) < 4) {
ret = -EINVAL;
goto err;
}
- if (!kfifo_get(&tport->xmit_fifo, &c)) {
+ if (!uart_fifo_out(&p->port, &c, 1)) {
ret = -EINVAL;
goto err;
}
skip_byte = c;
- /* now we need to recompute due to kfifo_get */
- kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
- UART_XMIT_SIZE, dma->tx_addr);
+ }
+
+ sg_init_table(&sg, 1);
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1, UART_XMIT_SIZE, dma->tx_addr);
+ if (ret != 1) {
+ ret = -EINVAL;
+ goto err;
}
desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
@@ -1223,6 +1222,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
goto err;
}
+ dma->tx_size = sg_dma_len(&sg);
dma->tx_running = 1;
desc->callback = omap_8250_dma_tx_complete;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index df4d0d832e54..73c200127b08 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -2728,6 +2728,22 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_oxsemi_tornado_setup,
},
{
+ .vendor = PCI_VENDOR_ID_INTASHIELD,
+ .device = 0x4026,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_oxsemi_tornado_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTASHIELD,
+ .device = 0x4021,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_oxsemi_tornado_setup,
+ },
+ {
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8811,
.subvendor = PCI_ANY_ID,
@@ -5253,6 +5269,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0BA2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0BA3,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_2_115200 },
/*
* Brainboxes UC-235/246
*/
@@ -5373,6 +5397,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0C42,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0C43,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_4_115200 },
/*
* Brainboxes UC-420
*/
@@ -5599,6 +5631,20 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_oxsemi_1_15625000 },
+ /*
+ * Brainboxes XC-235
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x4026,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_oxsemi_1_15625000 },
+ /*
+ * Brainboxes XC-475
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x4021,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_oxsemi_1_15625000 },
/*
* Perle PCI-RAS cards
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index e9c51d4e447d..4c149db84692 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -115,6 +115,7 @@
#define UART_RESET_REG 0x94
#define UART_RESET_D3_RESET_DISABLE BIT(16)
+#define UART_RESET_HOT_RESET_DISABLE BIT(17)
#define UART_BURST_STATUS_REG 0x9C
#define UART_TX_BURST_FIFO 0xA0
@@ -620,6 +621,10 @@ static int pci1xxxx_suspend(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data |= UART_RESET_HOT_RESET_DISABLE;
+
writel(data | UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
if (wakeup)
@@ -647,7 +652,12 @@ static int pci1xxxx_resume(struct device *dev)
}
data = readl(p + UART_RESET_REG);
+
+ if (priv->dev_rev >= 0xC0)
+ data &= ~UART_RESET_HOT_RESET_DISABLE;
+
writel(data & ~UART_RESET_D3_RESET_DISABLE, p + UART_RESET_REG);
+
iounmap(p);
for (i = 0; i < priv->nr; i++) {
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
index 8bdc1879d952..c0343bfb8064 100644
--- a/drivers/tty/serial/8250/8250_platform.c
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -112,7 +112,6 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct uart_8250_port uart = { };
struct resource *regs;
- unsigned char iotype;
int ret, line;
regs = platform_get_mem_or_io(pdev, 0);
@@ -122,13 +121,11 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
switch (resource_type(regs)) {
case IORESOURCE_IO:
uart.port.iobase = regs->start;
- iotype = UPIO_PORT;
break;
case IORESOURCE_MEM:
uart.port.mapbase = regs->start;
uart.port.mapsize = resource_size(regs);
uart.port.flags = UPF_IOREMAP;
- iotype = UPIO_MEM;
break;
default:
return -EINVAL;
@@ -147,12 +144,6 @@ static int serial8250_probe_acpi(struct platform_device *pdev)
if (ret)
return ret;
- /*
- * The previous call may not set iotype correctly when reg-io-width
- * property is absent and it doesn't support IO port resource.
- */
- uart.port.iotype = iotype;
-
line = serial8250_register_8250_port(&uart);
if (line < 0)
return line;
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 7c06ae79d8e2..7a837fdf9df1 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -436,7 +436,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart, *port;
int ret, flags = dev_id->driver_data;
- unsigned char iotype;
long line;
if (flags & UNKNOWN_DEV) {
@@ -448,14 +447,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
memset(&uart, 0, sizeof(uart));
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
uart.port.iobase = pnp_port_start(dev, 2);
- iotype = UPIO_PORT;
} else if (pnp_port_valid(dev, 0)) {
uart.port.iobase = pnp_port_start(dev, 0);
- iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
uart.port.mapbase = pnp_mem_start(dev, 0);
uart.port.mapsize = pnp_mem_len(dev, 0);
- iotype = UPIO_MEM;
uart.port.flags = UPF_IOREMAP;
} else
return -ENODEV;
@@ -471,12 +467,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
if (ret)
return ret;
- /*
- * The previous call may not set iotype correctly when reg-io-width
- * property is absent and it doesn't support IO port resource.
- */
- uart.port.iotype = iotype;
-
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 27572e5f1ff1..6d7b8c4667c9 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -517,22 +517,20 @@ void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
-void serial8250_rpm_get(struct uart_8250_port *p)
+static void serial8250_rpm_get(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get);
-void serial8250_rpm_put(struct uart_8250_port *p)
+static void serial8250_rpm_put(struct uart_8250_port *p)
{
if (!(p->capabilities & UART_CAP_RPM))
return;
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put);
/**
* serial8250_em485_init() - put uart_8250_port into rs485 emulating
@@ -566,19 +564,17 @@ static int serial8250_em485_init(struct uart_8250_port *p)
if (!p->em485)
return -ENOMEM;
- hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
- p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
+ hrtimer_setup(&p->em485->stop_tx_timer, &serial8250_em485_handle_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&p->em485->start_tx_timer, &serial8250_em485_handle_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
p->em485->port = p;
p->em485->active_timer = NULL;
p->em485->tx_stopped = true;
deassert_rts:
if (p->em485->tx_stopped)
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
return 0;
}
@@ -649,7 +645,7 @@ EXPORT_SYMBOL_GPL(serial8250_em485_config);
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
* empty and the HW can idle again.
*/
-void serial8250_rpm_get_tx(struct uart_8250_port *p)
+static void serial8250_rpm_get_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -661,9 +657,8 @@ void serial8250_rpm_get_tx(struct uart_8250_port *p)
return;
pm_runtime_get_sync(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_get_tx);
-void serial8250_rpm_put_tx(struct uart_8250_port *p)
+static void serial8250_rpm_put_tx(struct uart_8250_port *p)
{
unsigned char rpm_active;
@@ -676,7 +671,6 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p)
pm_runtime_mark_last_busy(p->port.dev);
pm_runtime_put_autosuspend(p->port.dev);
}
-EXPORT_SYMBOL_GPL(serial8250_rpm_put_tx);
/*
* IER sleep support. UARTs which have EFRs need the "extended
@@ -1390,7 +1384,6 @@ static void serial8250_stop_rx(struct uart_port *port)
serial8250_rpm_get(up);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
serial_port_out(port, UART_IER, up->ier);
serial8250_rpm_put(up);
@@ -1399,10 +1392,11 @@ static void serial8250_stop_rx(struct uart_port *port)
/**
* serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
* @p: uart 8250 port
+ * @toggle_ier: true to allow enabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to stop rs485 transmission.
*/
-void serial8250_em485_stop_tx(struct uart_8250_port *p)
+void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(p);
@@ -1423,8 +1417,10 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p)
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_and_reinit_fifos(p);
- p->ier |= UART_IER_RLSI | UART_IER_RDI;
- serial_port_out(&p->port, UART_IER, p->ier);
+ if (toggle_ier) {
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_port_out(&p->port, UART_IER, p->ier);
+ }
}
}
EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
@@ -1439,7 +1435,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
serial8250_rpm_get(p);
uart_port_lock_irqsave(&p->port, &flags);
if (em485->active_timer == &em485->stop_tx_timer) {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1471,7 +1467,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay)
em485->active_timer = &em485->stop_tx_timer;
hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL);
} else {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1560,6 +1556,7 @@ static inline void __start_tx(struct uart_port *port)
/**
* serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
* @up: uart 8250 port
+ * @toggle_ier: true to allow disabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to start rs485 transmission.
* Assumes that setting the RTS bit in the MCR register means RTS is high.
@@ -1567,11 +1564,11 @@ static inline void __start_tx(struct uart_port *port)
* stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the
* UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.)
*/
-void serial8250_em485_start_tx(struct uart_8250_port *up)
+void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(up);
- if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier)
serial8250_stop_rx(&up->port);
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
@@ -1605,7 +1602,7 @@ static bool start_tx_rs485(struct uart_port *port)
if (em485->tx_stopped) {
em485->tx_stopped = false;
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, true);
if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer;
@@ -1677,7 +1674,7 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
- mctrl_gpio_disable_ms(up->gpios);
+ mctrl_gpio_disable_ms_no_sync(up->gpios);
up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier);
@@ -1931,7 +1928,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
- !(port->read_status_mask & UART_LSR_DR))
+ !(up->ier & (UART_IER_RLSI | UART_IER_RDI)))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
@@ -2082,9 +2079,17 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
/* Returns true if @bits were set, false on timeout */
static bool wait_for_lsr(struct uart_8250_port *up, int bits)
{
- unsigned int status, tmout = 10000;
+ unsigned int status, tmout;
+
+ /*
+ * Wait for a character to be sent. Fallback to a safe default
+ * timeout value if @frame_time is not available.
+ */
+ if (up->port.frame_time)
+ tmout = up->port.frame_time * 2 / NSEC_PER_USEC;
+ else
+ tmout = 10000;
- /* Wait up to 10ms for the character(s) to be sent. */
for (;;) {
status = serial_lsr_in(up);
@@ -2397,28 +2402,26 @@ int serial8250_do_startup(struct uart_port *port)
* test if we receive TX irq. This way, we'll never enable
* UART_BUG_TXEN.
*/
- if (up->port.quirks & UPQ_NO_TXEN_TEST)
- goto dont_test_tx_en;
-
- /*
- * Do a quick test to see if we receive an interrupt when we enable
- * the TX irq.
- */
- serial_port_out(port, UART_IER, UART_IER_THRI);
- lsr = serial_port_in(port, UART_LSR);
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
+ if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
+ /*
+ * Do a quick test to see if we receive an interrupt when we
+ * enable the TX irq.
+ */
+ serial_port_out(port, UART_IER, UART_IER_THRI);
+ lsr = serial_port_in(port, UART_LSR);
+ iir = serial_port_in(port, UART_IIR);
+ serial_port_out(port, UART_IER, 0);
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
- if (!(up->bugs & UART_BUG_TXEN)) {
- up->bugs |= UART_BUG_TXEN;
- dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ }
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
}
- } else {
- up->bugs &= ~UART_BUG_TXEN;
}
-dont_test_tx_en:
uart_port_unlock_irqrestore(port, flags);
/*
@@ -2795,7 +2798,13 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ /*
+ * Specify which conditions may be considered for error
+ * handling and the ignoring of characters. The actual
+ * ignoring of characters only occurs if the bit is set
+ * in @ignore_status_mask as well.
+ */
+ port->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
@@ -2953,7 +2962,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
- int ret = 0;
switch (port->iotype) {
case UPIO_AU:
@@ -2962,32 +2970,30 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
- if (!port->mapbase) {
- ret = -EINVAL;
- break;
- }
+ if (!port->mapbase)
+ return -EINVAL;
- if (!request_mem_region(port->mapbase, size, "serial")) {
- ret = -EBUSY;
- break;
- }
+ if (!request_mem_region(port->mapbase, size, "serial"))
+ return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
release_mem_region(port->mapbase, size);
- ret = -ENOMEM;
+ return -ENOMEM;
}
}
- break;
-
+ return 0;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(port->iobase, size, "serial"))
- ret = -EBUSY;
+ return -EBUSY;
+ return 0;
+ case UPIO_UNKNOWN:
break;
}
- return ret;
+
+ return 0;
}
static void serial8250_release_std_resource(struct uart_8250_port *up)
@@ -3017,6 +3023,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_PORT:
release_region(port->iobase, size);
break;
+ case UPIO_UNKNOWN:
+ break;
}
}
@@ -3260,7 +3268,7 @@ void serial8250_init_port(struct uart_8250_port *up)
port->ops = &serial8250_pops;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
- up->cur_iotype = 0xFF;
+ up->cur_iotype = UPIO_UNKNOWN;
}
EXPORT_SYMBOL_GPL(serial8250_init_port);
@@ -3295,10 +3303,15 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
{
+ serial_port_out(port, UART_TX, ch);
+}
+
+static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch)
+{
struct uart_8250_port *up = up_to_u8250p(port);
wait_for_xmitr(up, UART_LSR_THRE);
- serial_port_out(port, UART_TX, ch);
+ serial8250_console_putchar(port, ch);
}
/*
@@ -3348,6 +3361,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
{
const char *end = s + count;
unsigned int fifosize = up->tx_loadsz;
+ struct uart_port *port = &up->port;
unsigned int tx_count = 0;
bool cr_sent = false;
unsigned int i;
@@ -3358,10 +3372,10 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
- serial_out(up, UART_TX, '\r');
+ serial8250_console_putchar(port, '\r');
cr_sent = true;
} else {
- serial_out(up, UART_TX, *s++);
+ serial8250_console_putchar(port, *s++);
cr_sent = false;
}
}
@@ -3414,7 +3428,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
if (em485->tx_stopped)
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, false);
mdelay(port->rs485.delay_rts_before_send);
}
@@ -3441,7 +3455,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
- uart_console_write(port, s, count, serial8250_console_putchar);
+ uart_console_write(port, s, count, serial8250_console_wait_putchar);
/*
* Finally, wait for transmitter to become empty
@@ -3452,7 +3466,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
if (em485->tx_stopped)
- up->rs485_stop_tx(up);
+ up->rs485_stop_tx(up, false);
}
serial_port_out(port, UART_IER, ier);
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
index dfaa613e452d..4c8b9671bd41 100644
--- a/drivers/tty/serial/8250/8250_rsa.c
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -16,36 +16,35 @@ static unsigned int probe_rsa_count;
static int rsa8250_request_resource(struct uart_8250_port *up)
{
- unsigned long start = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
- int ret = -EINVAL;
+ unsigned long start = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
start += port->iobase;
- if (request_region(start, size, "serial-rsa"))
- ret = 0;
- else
- ret = -EBUSY;
- break;
+ if (!request_region(start, size, "serial-rsa"))
+ return -EBUSY;
+ return 0;
+ default:
+ return -EINVAL;
}
-
- return ret;
}
static void rsa8250_release_resource(struct uart_8250_port *up)
{
- unsigned long offset = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
struct uart_port *port = &up->port;
+ unsigned long offset = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
switch (port->iotype) {
case UPIO_HUB6:
case UPIO_PORT:
release_region(port->iobase + offset, size);
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 55d26d16df9b..f64ef0819cd4 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -569,6 +569,19 @@ config SERIAL_8250_BCM7271
including DMA support and high accuracy BAUD rates, say
Y to this option. If unsure, say N.
+config SERIAL_8250_NI
+ tristate "NI 16550 based serial port"
+ depends on SERIAL_8250
+ depends on X86 || COMPILE_TEST
+ help
+ This driver supports the integrated serial ports on National
+ Instruments (NI) controller hardware. This is required for all NI
+ controller models with onboard RS-485 or dual-mode RS-485/RS-232
+ ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_ni.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 1516de629b61..b04eeda03b23 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 45f0f779fbf9..79a8186d3361 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -128,7 +128,7 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL
bool "AT91 on-chip serial port support"
depends on COMMON_CLK
- depends on ARCH_AT91 || COMPILE_TEST
+ depends on ARCH_AT91 || ARCH_LAN969X || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
select MFD_AT91_USART
@@ -179,25 +179,6 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
-config SERIAL_KGDB_NMI
- bool "Serial console over KGDB NMI debugger port"
- depends on KGDB_SERIAL_CONSOLE
- help
- This special driver allows you to temporary use NMI debugger port
- as a normal console (assuming that the port is attached to KGDB).
-
- Unlike KDB's disable_nmi command, with this driver you are always
- able to go back to the debugger using KGDB escape sequence ($3#33).
- This is because this console driver processes the input in NMI
- context, and thus is able to intercept the magic sequence.
-
- Note that since the console interprets input and uses polling
- communication methods, for things like PPP you still must fully
- detach debugger port from the KGDB NMI (i.e. disable_nmi), and
- use raw console.
-
- If unsure, say N.
-
config SERIAL_MESON
tristate "Meson serial port support"
depends on ARCH_MESON || COMPILE_TEST
@@ -306,6 +287,29 @@ config SERIAL_TEGRA_TCU_CONSOLE
If unsure, say Y.
+config SERIAL_TEGRA_UTC
+ tristate "NVIDIA Tegra UART Trace Controller"
+ depends on ARCH_TEGRA || COMPILE_TEST
+ select SERIAL_CORE
+ help
+ Support for Tegra UTC (UART Trace controller) client serial port.
+
+ UTC is a HW based serial port that allows multiplexing multiple data
+ streams of up to 16 UTC clients into a single hardware serial port.
+
+config SERIAL_TEGRA_UTC_CONSOLE
+ bool "Support for console on a Tegra UTC serial port"
+ depends on SERIAL_TEGRA_UTC
+ select SERIAL_CORE_CONSOLE
+ default SERIAL_TEGRA_UTC
+ help
+ If you say Y here, it will be possible to use a Tegra UTC client as
+ the system console (the system console is the device which receives
+ all kernel messages and warnings and which allows logins in single
+ user mode).
+
+ If unsure, say Y.
+
config SERIAL_MAX3100
tristate "MAX3100/3110/3111/3222 support"
depends on SPI
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 6ff74f0a9530..d58d9f719889 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
+obj-$(CONFIG_SERIAL_TEGRA_UTC) += tegra-utc.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
@@ -96,6 +97,5 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
-obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index b9c3c3bed0c1..d47a62d1c9f7 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -24,8 +24,6 @@
#include <linux/io.h>
#include <linux/altera_jtaguart.h>
-#define DRV_NAME "altera_jtaguart"
-
/*
* Altera JTAG UART register definitions according to the Altera JTAG UART
* datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
@@ -173,7 +171,7 @@ static int altera_jtaguart_startup(struct uart_port *port)
int ret;
ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
- DRV_NAME, port);
+ dev_name(port->dev), port);
if (ret) {
dev_err(port->dev, "unable to attach Altera JTAG UART %d interrupt vector=%d\n",
port->line, port->irq);
@@ -365,7 +363,7 @@ OF_EARLYCON_DECLARE(juart, "altr,juart-1.0", altera_jtaguart_earlycon_setup);
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
- .driver_name = "altera_jtaguart",
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttyJ",
.major = ALTERA_JTAGUART_MAJOR,
.minor = ALTERA_JTAGUART_MINOR,
@@ -451,7 +449,7 @@ static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
.remove = altera_jtaguart_remove,
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(altera_jtaguart_match),
},
};
@@ -481,4 +479,4 @@ module_exit(altera_jtaguart_exit);
MODULE_DESCRIPTION("Altera JTAG UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index c94655453c33..837991dc4db9 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -24,7 +24,6 @@
#include <linux/io.h>
#include <linux/altera_uart.h>
-#define DRV_NAME "altera_uart"
#define SERIAL_ALTERA_MAJOR 204
#define SERIAL_ALTERA_MINOR 213
@@ -276,7 +275,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
static void altera_uart_timer(struct timer_list *t)
{
- struct altera_uart *pp = from_timer(pp, t, tmr);
+ struct altera_uart *pp = timer_container_of(pp, t, tmr);
struct uart_port *port = &pp->port;
altera_uart_interrupt(0, port);
@@ -340,7 +339,7 @@ static void altera_uart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&pp->tmr);
+ timer_delete_sync(&pp->tmr);
}
static const char *altera_uart_type(struct uart_port *port)
@@ -518,7 +517,7 @@ OF_EARLYCON_DECLARE(uart, "altr,uart-1.0", altera_uart_earlycon_setup);
*/
static struct uart_driver altera_uart_driver = {
.owner = THIS_MODULE,
- .driver_name = DRV_NAME,
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttyAL",
.major = SERIAL_ALTERA_MAJOR,
.minor = SERIAL_ALTERA_MINOR,
@@ -619,7 +618,7 @@ static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
.remove = altera_uart_remove,
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(altera_uart_match),
},
};
@@ -649,5 +648,5 @@ module_exit(altera_uart_exit);
MODULE_DESCRIPTION("Altera UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 69b7a3e1e418..22939841b1de 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -248,6 +248,13 @@ struct pl011_dmatx_data {
bool queued;
};
+enum pl011_rs485_tx_state {
+ OFF,
+ WAIT_AFTER_RTS,
+ SEND,
+ WAIT_AFTER_SEND,
+};
+
/*
* We wrap our port structure around the generic uart_port.
*/
@@ -261,8 +268,11 @@ struct uart_amba_port {
unsigned int fifosize; /* vendor-specific */
unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
- bool rs485_tx_started;
- unsigned int rs485_tx_drain_interval; /* usecs */
+ ktime_t rs485_tx_drain_interval; /* nano */
+ enum pl011_rs485_tx_state rs485_tx_state;
+ struct hrtimer trigger_start_tx;
+ struct hrtimer trigger_stop_tx;
+ bool console_line_ended;
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
unsigned int dmacr; /* dma control reg */
@@ -1036,7 +1046,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
*/
static void pl011_dma_rx_poll(struct timer_list *t)
{
- struct uart_amba_port *uap = from_timer(uap, t, dmarx.timer);
+ struct uart_amba_port *uap = timer_container_of(uap, t, dmarx.timer);
struct tty_port *port = &uap->port.state->port;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = uap->dmarx.chan;
@@ -1074,7 +1084,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
uap->dmarx.running = false;
dmaengine_terminate_all(rxchan);
- del_timer(&uap->dmarx.timer);
+ timer_delete(&uap->dmarx.timer);
} else {
mod_timer(&uap->dmarx.timer,
jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
@@ -1189,7 +1199,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
if (uap->dmarx.poll_rate)
- del_timer_sync(&uap->dmarx.timer);
+ timer_delete_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
@@ -1260,30 +1270,31 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{
- /*
- * To be on the safe side only time out after twice as many iterations
- * as fifo size.
- */
- const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
struct uart_port *port = &uap->port;
- int i = 0;
u32 cr;
- /* Wait until hardware tx queue is empty */
- while (!pl011_tx_empty(port)) {
- if (i > MAX_TX_DRAIN_ITERS) {
- dev_warn(port->dev,
- "timeout while draining hardware tx queue\n");
- break;
- }
+ if (uap->rs485_tx_state == SEND)
+ uap->rs485_tx_state = WAIT_AFTER_SEND;
- udelay(uap->rs485_tx_drain_interval);
- i++;
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
+ /* Schedule hrtimer if tx queue not empty */
+ if (!pl011_tx_empty(port)) {
+ hrtimer_start(&uap->trigger_stop_tx,
+ uap->rs485_tx_drain_interval,
+ HRTIMER_MODE_REL);
+ return;
+ }
+ if (port->rs485.delay_rts_after_send > 0) {
+ hrtimer_start(&uap->trigger_stop_tx,
+ ms_to_ktime(port->rs485.delay_rts_after_send),
+ HRTIMER_MODE_REL);
+ return;
+ }
+ /* Continue without any delay */
+ } else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ hrtimer_try_to_cancel(&uap->trigger_start_tx);
}
- if (port->rs485.delay_rts_after_send)
- mdelay(port->rs485.delay_rts_after_send);
-
cr = pl011_read(uap, REG_CR);
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
@@ -1296,7 +1307,7 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
cr |= UART011_CR_RXE;
pl011_write(cr, uap, REG_CR);
- uap->rs485_tx_started = false;
+ uap->rs485_tx_state = OFF;
}
static void pl011_stop_tx(struct uart_port *port)
@@ -1304,11 +1315,18 @@ static void pl011_stop_tx(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ pl011_rs485_tx_stop(uap);
+ return;
+ }
+
uap->im &= ~UART011_TXIM;
pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_tx_stop(uap);
- if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ uap->rs485_tx_state != OFF)
pl011_rs485_tx_stop(uap);
}
@@ -1328,10 +1346,19 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
struct uart_port *port = &uap->port;
u32 cr;
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ uap->rs485_tx_state = SEND;
+ return;
+ }
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
+ hrtimer_try_to_cancel(&uap->trigger_stop_tx);
+ uap->rs485_tx_state = SEND;
+ return;
+ }
+ /* uap->rs485_tx_state == OFF */
/* Enable transmitter */
cr = pl011_read(uap, REG_CR);
cr |= UART011_CR_TXE;
-
/* Disable receiver if half-duplex */
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
cr &= ~UART011_CR_RXE;
@@ -1343,10 +1370,14 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
pl011_write(cr, uap, REG_CR);
- if (port->rs485.delay_rts_before_send)
- mdelay(port->rs485.delay_rts_before_send);
-
- uap->rs485_tx_started = true;
+ if (port->rs485.delay_rts_before_send > 0) {
+ uap->rs485_tx_state = WAIT_AFTER_RTS;
+ hrtimer_start(&uap->trigger_start_tx,
+ ms_to_ktime(port->rs485.delay_rts_before_send),
+ HRTIMER_MODE_REL);
+ } else {
+ uap->rs485_tx_state = SEND;
+ }
}
static void pl011_start_tx(struct uart_port *port)
@@ -1355,13 +1386,44 @@ static void pl011_start_tx(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
- !uap->rs485_tx_started)
+ uap->rs485_tx_state != SEND) {
pl011_rs485_tx_start(uap);
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS)
+ return;
+ }
if (!pl011_dma_tx_start(uap))
pl011_start_tx_pio(uap);
}
+static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t)
+{
+ struct uart_amba_port *uap =
+ container_of(t, struct uart_amba_port, trigger_start_tx);
+ unsigned long flags;
+
+ uart_port_lock_irqsave(&uap->port, &flags);
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS)
+ pl011_start_tx(&uap->port);
+ uart_port_unlock_irqrestore(&uap->port, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
+{
+ struct uart_amba_port *uap =
+ container_of(t, struct uart_amba_port, trigger_stop_tx);
+ unsigned long flags;
+
+ uart_port_lock_irqsave(&uap->port, &flags);
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND)
+ pl011_rs485_tx_stop(uap);
+ uart_port_unlock_irqrestore(&uap->port, flags);
+
+ return HRTIMER_NORESTART;
+}
+
static void pl011_stop_rx(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1953,7 +2015,7 @@ static void pl011_shutdown(struct uart_port *port)
pl011_dma_shutdown(uap);
- if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
pl011_rs485_tx_stop(uap);
free_irq(uap->port.irq, uap);
@@ -2098,7 +2160,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* with the given baud rate. We use this as the poll interval when we
* wait for the tx queue to empty.
*/
- uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
+ uap->rs485_tx_drain_interval = ns_to_ktime(DIV_ROUND_UP(bits * NSEC_PER_SEC, baud));
pl011_setup_status_masks(port, termios);
@@ -2305,50 +2367,7 @@ static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
cpu_relax();
pl011_write(ch, uap, REG_DR);
-}
-
-static void
-pl011_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int old_cr = 0, new_cr;
- unsigned long flags;
- int locked = 1;
-
- clk_enable(uap->clk);
-
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&uap->port, &flags);
- else
- uart_port_lock_irqsave(&uap->port, &flags);
-
- /*
- * First save the CR then disable the interrupts
- */
- if (!uap->vendor->always_enabled) {
- old_cr = pl011_read(uap, REG_CR);
- new_cr = old_cr & ~UART011_CR_CTSEN;
- new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- pl011_write(new_cr, uap, REG_CR);
- }
-
- uart_console_write(&uap->port, s, count, pl011_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty and restore the
- * TCR. Allow feature register bits to be inverted to work around
- * errata.
- */
- while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
- & uap->vendor->fr_busy)
- cpu_relax();
- if (!uap->vendor->always_enabled)
- pl011_write(old_cr, uap, REG_CR);
-
- if (locked)
- uart_port_unlock_irqrestore(&uap->port, flags);
-
- clk_disable(uap->clk);
+ uap->console_line_ended = (ch == '\n');
}
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
@@ -2411,6 +2430,8 @@ static int pl011_console_setup(struct console *co, char *options)
if (ret)
return ret;
+ uap->console_line_ended = true;
+
if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
@@ -2455,7 +2476,7 @@ static int pl011_console_setup(struct console *co, char *options)
static int pl011_console_match(struct console *co, char *name, int idx,
char *options)
{
- unsigned char iotype;
+ enum uart_iotype iotype;
resource_size_t addr;
int i;
@@ -2494,14 +2515,105 @@ static int pl011_console_match(struct console *co, char *name, int idx,
return -ENODEV;
}
+static void
+pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (!uap->console_line_ended)
+ uart_console_write(&uap->port, "\n", 1, pl011_console_putchar);
+ uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int i;
+ unsigned int len = READ_ONCE(wctxt->len);
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+ uart_console_write(&uap->port, wctxt->outbuf + i, 1, pl011_console_putchar);
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_device_lock(struct console *co, unsigned long *flags)
+{
+ __uart_port_lock_irqsave(&amba_ports[co->index]->port, flags);
+}
+
+static void
+pl011_console_device_unlock(struct console *co, unsigned long flags)
+{
+ __uart_port_unlock_irqrestore(&amba_ports[co->index]->port, flags);
+}
+
static struct uart_driver amba_reg;
static struct console amba_console = {
.name = "ttyAMA",
- .write = pl011_console_write,
.device = uart_console_device,
.setup = pl011_console_setup,
.match = pl011_console_match,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
+ .write_atomic = pl011_console_write_atomic,
+ .write_thread = pl011_console_write_thread,
+ .device_lock = pl011_console_device_lock,
+ .device_unlock = pl011_console_device_unlock,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
.index = -1,
.data = &amba_reg,
};
@@ -2806,6 +2918,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
return -EINVAL;
}
}
+ hrtimer_setup(&uap->trigger_start_tx, pl011_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&uap->trigger_stop_tx, pl011_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
if (ret)
@@ -2935,7 +3051,7 @@ static const struct of_device_id sbsa_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
-static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
+static const struct acpi_device_id sbsa_uart_acpi_match[] = {
{ "ARMH0011", 0 },
{ "ARMHB000", 0 },
{},
@@ -2948,8 +3064,8 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
.driver = {
.name = "sbsa-uart",
.pm = &pl011_dev_pm_ops,
- .of_match_table = of_match_ptr(sbsa_uart_of_match),
- .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
+ .of_match_table = sbsa_uart_of_match,
+ .acpi_match_table = sbsa_uart_acpi_match,
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
};
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 0cf05ac18993..08dd8f887956 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -700,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = false;
- mctrl_gpio_disable_ms(atmel_port->gpios);
+ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios);
if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
idr |= ATMEL_US_CTSIC;
@@ -1266,8 +1266,8 @@ chan_err:
static void atmel_uart_timer_callback(struct timer_list *t)
{
- struct atmel_uart_port *atmel_port = from_timer(atmel_port, t,
- uart_timer);
+ struct atmel_uart_port *atmel_port = timer_container_of(atmel_port, t,
+ uart_timer);
struct uart_port *port = &atmel_port->uart;
if (!atomic_read(&atmel_port->tasklet_shutdown)) {
@@ -1727,26 +1727,16 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
/* DMA/PDC usage specification */
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
- if (of_property_read_bool(np, "dmas")) {
- atmel_port->use_dma_rx = true;
- atmel_port->use_pdc_rx = false;
- } else {
- atmel_port->use_dma_rx = false;
- atmel_port->use_pdc_rx = true;
- }
+ atmel_port->use_dma_rx = of_property_present(np, "dmas");
+ atmel_port->use_pdc_rx = !atmel_port->use_dma_rx;
} else {
atmel_port->use_dma_rx = false;
atmel_port->use_pdc_rx = false;
}
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
- if (of_property_read_bool(np, "dmas")) {
- atmel_port->use_dma_tx = true;
- atmel_port->use_pdc_tx = false;
- } else {
- atmel_port->use_dma_tx = false;
- atmel_port->use_pdc_tx = true;
- }
+ atmel_port->use_dma_tx = of_property_present(np, "dmas");
+ atmel_port->use_pdc_tx = !atmel_port->use_dma_tx;
} else {
atmel_port->use_dma_tx = false;
atmel_port->use_pdc_tx = false;
@@ -2027,7 +2017,7 @@ static void atmel_shutdown(struct uart_port *port)
* Prevent any tasklets being scheduled during
* cleanup
*/
- del_timer_sync(&atmel_port->uart_timer);
+ timer_delete_sync(&atmel_port->uart_timer);
/* Make sure that no interrupt is on the fly */
synchronize_irq(port->irq);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 57b0632a3db6..2790b4078e7e 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -245,7 +245,7 @@
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
-#define UART_NR 8
+#define UART_NR 12
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
@@ -403,6 +403,8 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
case UPIO_MEM32BE:
iowrite32be(val, port->membase + off);
break;
+ default:
+ break;
}
}
@@ -441,36 +443,36 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
static void lpuart_stop_tx(struct uart_port *port)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TIE | UARTCR2_TCIE);
- writeb(temp, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_stop_tx(struct uart_port *port)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_stop_rx(struct uart_port *port)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 & ~UARTCR2_RE, port->membase + UARTCR2);
}
static void lpuart32_stop_rx(struct uart_port *port)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl & ~UARTCTRL_RE, UARTCTRL);
}
static void lpuart_dma_tx(struct lpuart_port *sport)
@@ -563,8 +565,9 @@ static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport)
return sport->port.mapbase + UARTDATA;
case UPIO_MEM32BE:
return sport->port.mapbase + UARTDATA + sizeof(u32) - 1;
+ default:
+ return sport->port.mapbase + UARTDR;
}
- return sport->port.mapbase + UARTDR;
}
static int lpuart_dma_tx_request(struct uart_port *port)
@@ -581,7 +584,7 @@ static int lpuart_dma_tx_request(struct uart_port *port)
ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
if (ret) {
- dev_err(sport->port.dev,
+ dev_err(port->dev,
"DMA slave config failed, err = %d\n", ret);
return ret;
}
@@ -599,7 +602,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
struct dma_chan *chan = sport->dma_tx_chan;
- u32 val;
+ u32 fifo;
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
@@ -611,13 +614,13 @@ static void lpuart_flush_buffer(struct uart_port *port)
}
if (lpuart_is_32(sport)) {
- val = lpuart32_read(&sport->port, UARTFIFO);
- val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
- lpuart32_write(&sport->port, val, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
+ fifo |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(port, fifo, UARTFIFO);
} else {
- val = readb(sport->port.membase + UARTCFIFO);
- val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
- writeb(val, sport->port.membase + UARTCFIFO);
+ fifo = readb(port->membase + UARTCFIFO);
+ fifo |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
+ writeb(fifo, port->membase + UARTCFIFO);
}
}
@@ -639,38 +642,36 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset,
static int lpuart_poll_init(struct uart_port *port)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
unsigned long flags;
- unsigned char temp;
+ u8 fifo;
- sport->port.fifosize = 0;
+ port->fifosize = 0;
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
/* Disable Rx & Tx */
- writeb(0, sport->port.membase + UARTCR2);
+ writeb(0, port->membase + UARTCR2);
- temp = readb(sport->port.membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
/* Enable Rx and Tx FIFO */
- writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
- sport->port.membase + UARTPFIFO);
+ writeb(fifo | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
+ port->membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
- sport->port.membase + UARTCFIFO);
+ port->membase + UARTCFIFO);
/* explicitly clear RDRF */
- if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) {
- readb(sport->port.membase + UARTDR);
- writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
+ if (readb(port->membase + UARTSR1) & UARTSR1_RDRF) {
+ readb(port->membase + UARTDR);
+ writeb(UARTSFIFO_RXUF, port->membase + UARTSFIFO);
}
- writeb(0, sport->port.membase + UARTTWFIFO);
- writeb(1, sport->port.membase + UARTRWFIFO);
+ writeb(0, port->membase + UARTTWFIFO);
+ writeb(1, port->membase + UARTRWFIFO);
/* Enable Rx and Tx */
- writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2);
- uart_port_unlock_irqrestore(&sport->port, flags);
+ writeb(UARTCR2_RE | UARTCR2_TE, port->membase + UARTCR2);
+ uart_port_unlock_irqrestore(port, flags);
return 0;
}
@@ -693,33 +694,32 @@ static int lpuart_poll_get_char(struct uart_port *port)
static int lpuart32_poll_init(struct uart_port *port)
{
unsigned long flags;
- struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u32 temp;
+ u32 fifo;
- sport->port.fifosize = 0;
+ port->fifosize = 0;
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
/* Disable Rx & Tx */
- lpuart32_write(&sport->port, 0, UARTCTRL);
+ lpuart32_write(port, 0, UARTCTRL);
- temp = lpuart32_read(&sport->port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
/* Enable Rx and Tx FIFO */
- lpuart32_write(&sport->port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
+ lpuart32_write(port, fifo | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
/* flush Tx and Rx FIFO */
- lpuart32_write(&sport->port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO);
+ lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO);
/* explicitly clear RDRF */
- if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) {
- lpuart32_read(&sport->port, UARTDATA);
- lpuart32_write(&sport->port, UARTFIFO_RXUF, UARTFIFO);
+ if (lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF) {
+ lpuart32_read(port, UARTDATA);
+ lpuart32_write(port, UARTFIFO_RXUF, UARTFIFO);
}
/* Enable Rx and Tx */
- lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL);
- uart_port_unlock_irqrestore(&sport->port, flags);
+ lpuart32_write(port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL);
+ uart_port_unlock_irqrestore(port, flags);
return 0;
}
@@ -752,7 +752,7 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
{
struct tty_port *tport = &sport->port.state->port;
- unsigned long txcnt;
+ u32 txcnt;
unsigned char c;
if (sport->port.x_char) {
@@ -789,10 +789,10 @@ static void lpuart_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 | UARTCR2_TIE, port->membase + UARTCR2);
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
@@ -806,14 +806,14 @@ static void lpuart_start_tx(struct uart_port *port)
static void lpuart32_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 ctrl;
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
lpuart_dma_tx(sport);
} else {
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl | UARTCTRL_TIE, UARTCTRL);
if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
lpuart32_transmit_buffer(sport);
@@ -839,8 +839,8 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned char sr1 = readb(port->membase + UARTSR1);
- unsigned char sfifo = readb(port->membase + UARTSFIFO);
+ u8 sr1 = readb(port->membase + UARTSR1);
+ u8 sfifo = readb(port->membase + UARTSFIFO);
if (sport->dma_tx_in_progress)
return 0;
@@ -855,9 +855,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned long stat = lpuart32_read(port, UARTSTAT);
- unsigned long sfifo = lpuart32_read(port, UARTFIFO);
- unsigned long ctrl = lpuart32_read(port, UARTCTRL);
+ u32 stat = lpuart32_read(port, UARTSTAT);
+ u32 sfifo = lpuart32_read(port, UARTFIFO);
+ u32 ctrl = lpuart32_read(port, UARTCTRL);
if (sport->dma_tx_in_progress)
return 0;
@@ -884,7 +884,7 @@ static void lpuart_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0, overrun = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned char rx, sr;
+ u8 rx, sr;
uart_port_lock(&sport->port);
@@ -961,7 +961,7 @@ static void lpuart32_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long rx, sr;
+ u32 rx, sr;
bool is_break;
uart_port_lock(&sport->port);
@@ -1039,7 +1039,7 @@ out:
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned char sts;
+ u8 sts;
sts = readb(sport->port.membase + UARTSR1);
@@ -1113,7 +1113,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
int count, copied;
if (lpuart_is_32(sport)) {
- unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
+ u32 sr = lpuart32_read(&sport->port, UARTSTAT);
if (sr & (UARTSTAT_PE | UARTSTAT_FE)) {
/* Clear the error flags */
@@ -1125,10 +1125,10 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
sport->port.icount.frame++;
}
} else {
- unsigned char sr = readb(sport->port.membase + UARTSR1);
+ u8 sr = readb(sport->port.membase + UARTSR1);
if (sr & (UARTSR1_PE | UARTSR1_FE)) {
- unsigned char cr2;
+ u8 cr2;
/* Disable receiver during this operation... */
cr2 = readb(sport->port.membase + UARTCR2);
@@ -1279,7 +1279,7 @@ static void lpuart32_dma_idleint(struct lpuart_port *sport)
static irqreturn_t lpuart32_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned long sts, rxcount;
+ u32 sts, rxcount;
sts = lpuart32_read(&sport->port, UARTSTAT);
rxcount = lpuart32_read(&sport->port, UARTWATER);
@@ -1307,7 +1307,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
*/
static void lpuart_timer_func(struct timer_list *t)
{
- struct lpuart_port *sport = from_timer(sport, t, lpuart_timer);
+ struct lpuart_port *sport = timer_container_of(sport, t, lpuart_timer);
enum dma_status dmastat;
struct dma_chan *chan = sport->dma_rx_chan;
struct circ_buf *ring = &sport->rx_ring;
@@ -1411,12 +1411,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
dma_async_issue_pending(chan);
if (lpuart_is_32(sport)) {
- unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
+ u32 baud = lpuart32_read(&sport->port, UARTBAUD);
- lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+ lpuart32_write(&sport->port, baud | UARTBAUD_RDMAE, UARTBAUD);
if (sport->dma_idle_int) {
- unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ u32 ctrl = lpuart32_read(&sport->port, UARTCTRL);
lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL);
}
@@ -1436,7 +1436,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
dmaengine_terminate_sync(chan);
if (!sport->dma_idle_int)
- del_timer_sync(&sport->lpuart_timer);
+ timer_delete_sync(&sport->lpuart_timer);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
@@ -1449,12 +1449,9 @@ static void lpuart_dma_rx_free(struct uart_port *port)
static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
-
- u8 modem = readb(sport->port.membase + UARTMODEM) &
+ u8 modem = readb(port->membase + UARTMODEM) &
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(modem, port->membase + UARTMODEM);
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
@@ -1472,19 +1469,29 @@ static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
modem &= ~UARTMODEM_TXRTSPOL;
}
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(modem, port->membase + UARTMODEM);
return 0;
}
static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
-
- unsigned long modem = lpuart32_read(&sport->port, UARTMODIR)
+ u32 modem = lpuart32_read(port, UARTMODIR)
& ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE);
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ u32 ctrl;
+
+ /* TXRTSE and TXRTSPOL only can be changed when transmitter is disabled. */
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_TE) {
+ /* wait for the transmit engine to complete */
+ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC);
+ lpuart32_write(port, ctrl & ~UARTCTRL_TE, UARTCTRL);
+
+ while (lpuart32_read(port, UARTCTRL) & UARTCTRL_TE)
+ cpu_relax();
+ }
+
+ lpuart32_write(port, modem, UARTMODIR);
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
@@ -1502,17 +1509,21 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
modem &= ~UARTMODIR_TXRTSPOL;
}
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ lpuart32_write(port, modem, UARTMODIR);
+
+ if (ctrl & UARTCTRL_TE)
+ lpuart32_write(port, ctrl, UARTCTRL);
+
return 0;
}
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
- if (reg & UARTCR1_LOOPS)
+ cr1 = readb(port->membase + UARTCR1);
+ if (cr1 & UARTCR1_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1521,10 +1532,10 @@ static unsigned int lpuart_get_mctrl(struct uart_port *port)
static unsigned int lpuart32_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
- if (reg & UARTCTRL_LOOPS)
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1532,49 +1543,49 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
+ cr1 = readb(port->membase + UARTCR1);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
+ cr1 &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCR1_LOOPS;
+ cr1 |= UARTCR1_LOOPS;
- writeb(reg, port->membase + UARTCR1);
+ writeb(cr1, port->membase + UARTCR1);
}
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
+ ctrl &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCTRL_LOOPS;
+ ctrl |= UARTCTRL_LOOPS;
- lpuart32_write(port, reg, UARTCTRL);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
+ cr2 = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
if (break_state != 0)
- temp |= UARTCR2_SBK;
+ cr2 |= UARTCR2_SBK;
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/*
* LPUART IP now has two known bugs, one is CTS has higher priority than the
@@ -1591,23 +1602,22 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
* Disable the transmitter to prevent any data from being sent out
* during break, then invert the TX line to send break.
*/
- temp &= ~UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
} else {
/* Disable the TXINV to turn off break and re-enable transmitter. */
- temp &= ~UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
}
}
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
- unsigned char val, cr2;
- unsigned char cr2_saved;
+ u8 fifo, cr2, cr2_saved;
cr2 = readb(sport->port.membase + UARTCR2);
cr2_saved = cr2;
@@ -1615,8 +1625,8 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
- val = readb(sport->port.membase + UARTPFIFO);
- writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
+ fifo = readb(sport->port.membase + UARTPFIFO);
+ writeb(fifo | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
@@ -1640,7 +1650,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
static void lpuart_setup_watermark_enable(struct lpuart_port *sport)
{
- unsigned char cr2;
+ u8 cr2;
lpuart_setup_watermark(sport);
@@ -1651,8 +1661,7 @@ static void lpuart_setup_watermark_enable(struct lpuart_port *sport)
static void lpuart32_setup_watermark(struct lpuart_port *sport)
{
- unsigned long val, ctrl;
- unsigned long ctrl_saved;
+ u32 val, ctrl, ctrl_saved;
ctrl = lpuart32_read(&sport->port, UARTCTRL);
ctrl_saved = ctrl;
@@ -1687,14 +1696,14 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
{
- u32 temp;
+ u32 ctrl;
lpuart32_setup_watermark(sport);
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp |= UARTCTRL_RE | UARTCTRL_TE;
- temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl |= UARTCTRL_RE | UARTCTRL_TE;
+ ctrl |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void rx_dma_timer_init(struct lpuart_port *sport)
@@ -1761,7 +1770,7 @@ err:
static void lpuart_rx_dma_startup(struct lpuart_port *sport)
{
int ret;
- unsigned char cr3;
+ u8 cr3;
if (uart_console(&sport->port))
goto err;
@@ -1811,16 +1820,16 @@ static void lpuart_hw_setup(struct lpuart_port *sport)
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned char temp;
+ u8 fifo;
/* determine FIFO size and enable FIFO mode */
- temp = readb(sport->port.membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_TXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
lpuart_request_dma(sport);
@@ -1831,24 +1840,24 @@ static int lpuart_startup(struct uart_port *port)
static void lpuart32_hw_disable(struct lpuart_port *sport)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
UARTCTRL_TIE | UARTCTRL_TE);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_configure(struct lpuart_port *sport)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
if (!sport->lpuart_dma_rx_use)
- temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
+ ctrl |= UARTCTRL_RIE | UARTCTRL_ILIE;
if (!sport->lpuart_dma_tx_use)
- temp |= UARTCTRL_TIE;
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl |= UARTCTRL_TIE;
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_hw_setup(struct lpuart_port *sport)
@@ -1871,16 +1880,16 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
static int lpuart32_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 fifo;
/* determine FIFO size */
- temp = lpuart32_read(&sport->port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_TXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_RXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
/*
@@ -1891,7 +1900,7 @@ static int lpuart32_startup(struct uart_port *port)
if (is_layerscape_lpuart(sport)) {
sport->rxfifo_size = 16;
sport->txfifo_size = 16;
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
}
lpuart_request_dma(sport);
@@ -1925,16 +1934,16 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
static void lpuart_shutdown(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned char temp;
+ u8 cr2;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
/* disable Rx/Tx and interrupts */
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TE | UARTCR2_RE |
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TE | UARTCR2_RE |
UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
uart_port_unlock_irqrestore(port, flags);
@@ -1945,14 +1954,14 @@ static void lpuart32_shutdown(struct uart_port *port)
{
struct lpuart_port *sport =
container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 temp;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
/* clear status */
- temp = lpuart32_read(&sport->port, UARTSTAT);
- lpuart32_write(&sport->port, temp, UARTSTAT);
+ temp = lpuart32_read(port, UARTSTAT);
+ lpuart32_write(port, temp, UARTSTAT);
/* disable Rx/Tx DMA */
temp = lpuart32_read(port, UARTBAUD);
@@ -1965,6 +1974,11 @@ static void lpuart32_shutdown(struct uart_port *port)
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
lpuart32_write(port, temp, UARTCTRL);
+ /* flush Rx/Tx FIFO */
+ temp = lpuart32_read(port, UARTFIFO);
+ temp |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(port, temp, UARTFIFO);
+
uart_port_unlock_irqrestore(port, flags);
lpuart_dma_shutdown(sport);
@@ -1976,17 +1990,17 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
- unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem;
+ u8 cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned int sbr, brfa;
- cr1 = old_cr1 = readb(sport->port.membase + UARTCR1);
- old_cr2 = readb(sport->port.membase + UARTCR2);
- cr3 = readb(sport->port.membase + UARTCR3);
- cr4 = readb(sport->port.membase + UARTCR4);
- bdh = readb(sport->port.membase + UARTBDH);
- modem = readb(sport->port.membase + UARTMODEM);
+ cr1 = old_cr1 = readb(port->membase + UARTCR1);
+ old_cr2 = readb(port->membase + UARTCR2);
+ cr3 = readb(port->membase + UARTCR3);
+ cr4 = readb(port->membase + UARTCR4);
+ bdh = readb(port->membase + UARTBDH);
+ modem = readb(port->membase + UARTMODEM);
/*
* only support CS8 and CS7, and for CS7 must enable PE.
* supported mode:
@@ -2018,7 +2032,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
* When auto RS-485 RTS mode is enabled,
* hardware flow control need to be disabled.
*/
- if (sport->port.rs485.flags & SER_RS485_ENABLED)
+ if (port->rs485.flags & SER_RS485_ENABLED)
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS)
@@ -2059,59 +2073,59 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
* Need to update the Ring buffer length according to the selected
* baud rate and restart Rx DMA path.
*
- * Since timer function acqures sport->port.lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * Since timer function acqures port->lock, need to stop before
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
- lpuart_dma_rx_free(&sport->port);
+ lpuart_dma_rx_free(port);
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
- sport->port.read_status_mask = 0;
+ port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
- sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE;
+ port->read_status_mask |= UARTSR1_FE | UARTSR1_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- sport->port.read_status_mask |= UARTSR1_FE;
+ port->read_status_mask |= UARTSR1_FE;
/* characters to ignore */
- sport->port.ignore_status_mask = 0;
+ port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSR1_PE;
+ port->ignore_status_mask |= UARTSR1_PE;
if (termios->c_iflag & IGNBRK) {
- sport->port.ignore_status_mask |= UARTSR1_FE;
+ port->ignore_status_mask |= UARTSR1_FE;
/*
* if we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSR1_OR;
+ port->ignore_status_mask |= UARTSR1_OR;
}
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/* wait transmit engin complete */
- lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC);
+ lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TC);
/* disable transmit and receive */
writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE),
- sport->port.membase + UARTCR2);
+ port->membase + UARTCR2);
- sbr = sport->port.uartclk / (16 * baud);
- brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud;
+ sbr = port->uartclk / (16 * baud);
+ brfa = ((port->uartclk - (16 * sbr * baud)) * 2) / baud;
bdh &= ~UARTBDH_SBR_MASK;
bdh |= (sbr >> 8) & 0x1F;
cr4 &= ~UARTCR4_BRFA_MASK;
brfa &= UARTCR4_BRFA_MASK;
- writeb(cr4 | brfa, sport->port.membase + UARTCR4);
- writeb(bdh, sport->port.membase + UARTBDH);
- writeb(sbr & 0xFF, sport->port.membase + UARTBDL);
- writeb(cr3, sport->port.membase + UARTCR3);
- writeb(cr1, sport->port.membase + UARTCR1);
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(cr4 | brfa, port->membase + UARTCR4);
+ writeb(bdh, port->membase + UARTBDH);
+ writeb(sbr & 0xFF, port->membase + UARTBDL);
+ writeb(cr3, port->membase + UARTCR3);
+ writeb(cr1, port->membase + UARTCR1);
+ writeb(modem, port->membase + UARTMODEM);
/* restore control register */
- writeb(old_cr2, sport->port.membase + UARTCR2);
+ writeb(old_cr2, port->membase + UARTCR2);
if (old && sport->lpuart_dma_rx_use) {
if (!lpuart_start_rx_dma(sport))
@@ -2120,14 +2134,14 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
sport->lpuart_dma_rx_use = false;
}
- uart_port_unlock_irqrestore(&sport->port, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static void __lpuart32_serial_setbrg(struct uart_port *port,
unsigned int baudrate, bool use_rx_dma,
bool use_tx_dma)
{
- u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, baud;
u32 clk = port->uartclk;
/*
@@ -2156,9 +2170,9 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
/* select best values between sbr and sbr+1 */
- tmp = clk / (tmp_osr * (tmp_sbr + 1));
- if (tmp_diff > (baudrate - tmp)) {
- tmp_diff = baudrate - tmp;
+ baud = clk / (tmp_osr * (tmp_sbr + 1));
+ if (tmp_diff > (baudrate - baud)) {
+ tmp_diff = baudrate - baud;
tmp_sbr++;
}
@@ -2180,23 +2194,23 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
dev_warn(port->dev,
"unacceptable baud rate difference of more than 3%%\n");
- tmp = lpuart32_read(port, UARTBAUD);
+ baud = lpuart32_read(port, UARTBAUD);
if ((osr > 3) && (osr < 8))
- tmp |= UARTBAUD_BOTHEDGE;
+ baud |= UARTBAUD_BOTHEDGE;
- tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
- tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
+ baud &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
+ baud |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
- tmp &= ~UARTBAUD_SBR_MASK;
- tmp |= sbr & UARTBAUD_SBR_MASK;
+ baud &= ~UARTBAUD_SBR_MASK;
+ baud |= sbr & UARTBAUD_SBR_MASK;
if (!use_rx_dma)
- tmp &= ~UARTBAUD_RDMAE;
+ baud &= ~UARTBAUD_RDMAE;
if (!use_tx_dma)
- tmp &= ~UARTBAUD_TDMAE;
+ baud &= ~UARTBAUD_TDMAE;
- lpuart32_write(port, tmp, UARTBAUD);
+ lpuart32_write(port, baud, UARTBAUD);
}
static void lpuart32_serial_setbrg(struct lpuart_port *sport,
@@ -2214,13 +2228,13 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
- unsigned long ctrl, old_ctrl, bd, modem;
+ u32 ctrl, old_ctrl, bd, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
- bd = lpuart32_read(&sport->port, UARTBAUD);
- modem = lpuart32_read(&sport->port, UARTMODIR);
+ ctrl = old_ctrl = lpuart32_read(port, UARTCTRL);
+ bd = lpuart32_read(port, UARTBAUD);
+ modem = lpuart32_read(port, UARTMODIR);
sport->is_cs7 = false;
/*
* only support CS8 and CS7
@@ -2254,7 +2268,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
* When auto RS-485 RTS mode is enabled,
* hardware flow control need to be disabled.
*/
- if (sport->port.rs485.flags & SER_RS485_ENABLED)
+ if (port->rs485.flags & SER_RS485_ENABLED)
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS)
@@ -2304,59 +2318,61 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
* Need to update the Ring buffer length according to the selected
* baud rate and restart Rx DMA path.
*
- * Since timer function acqures sport->port.lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * Since timer function acqures port->lock, need to stop before
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
- lpuart_dma_rx_free(&sport->port);
+ lpuart_dma_rx_free(port);
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
- sport->port.read_status_mask = 0;
+ port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
- sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE;
+ port->read_status_mask |= UARTSTAT_FE | UARTSTAT_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- sport->port.read_status_mask |= UARTSTAT_FE;
+ port->read_status_mask |= UARTSTAT_FE;
/* characters to ignore */
- sport->port.ignore_status_mask = 0;
+ port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSTAT_PE;
+ port->ignore_status_mask |= UARTSTAT_PE;
if (termios->c_iflag & IGNBRK) {
- sport->port.ignore_status_mask |= UARTSTAT_FE;
+ port->ignore_status_mask |= UARTSTAT_FE;
/*
* if we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSTAT_OR;
+ port->ignore_status_mask |= UARTSTAT_OR;
}
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/*
+ * disable CTS to ensure the transmit engine is not blocked by the flow
+ * control when there is dirty data in TX FIFO
+ */
+ lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
+
+ /*
* LPUART Transmission Complete Flag may never be set while queuing a break
* character, so skip waiting for transmission complete when UARTCTRL_SBK is
* asserted.
*/
- if (!(old_ctrl & UARTCTRL_SBK)) {
- lpuart32_write(&sport->port, 0, UARTMODIR);
- lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC);
- }
+ if (!(old_ctrl & UARTCTRL_SBK))
+ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC);
/* disable transmit and receive */
- lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
+ lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
UARTCTRL);
- lpuart32_write(&sport->port, bd, UARTBAUD);
+ lpuart32_write(port, bd, UARTBAUD);
lpuart32_serial_setbrg(sport, baud);
- /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */
- lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
/* restore control register */
- lpuart32_write(&sport->port, ctrl, UARTCTRL);
+ lpuart32_write(port, ctrl, UARTCTRL);
/* re-enable the CTS if needed */
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ lpuart32_write(port, modem, UARTMODIR);
if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE)
sport->is_cs7 = true;
@@ -2368,7 +2384,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
sport->lpuart_dma_rx_use = false;
}
- uart_port_unlock_irqrestore(&sport->port, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static const char *lpuart_type(struct uart_port *port)
@@ -2481,7 +2497,7 @@ static void
lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
- unsigned char old_cr2, cr2;
+ u8 old_cr2, cr2;
unsigned long flags;
int locked = 1;
@@ -2511,7 +2527,7 @@ static void
lpuart32_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
- unsigned long old_cr, cr;
+ u32 old_cr, cr;
unsigned long flags;
int locked = 1;
@@ -2545,7 +2561,7 @@ static void __init
lpuart_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
- unsigned char cr, bdh, bdl, brfa;
+ u8 cr, bdh, bdl, brfa;
unsigned int sbr, uartclk, baud_raw;
cr = readb(sport->port.membase + UARTCR2);
@@ -2594,7 +2610,7 @@ static void __init
lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
- unsigned long cr, bd;
+ u32 cr, bd;
unsigned int sbr, uartclk, baud_raw;
cr = lpuart32_read(&sport->port, UARTCTRL);
@@ -2800,13 +2816,13 @@ static int lpuart_global_reset(struct lpuart_port *sport)
{
struct uart_port *port = &sport->port;
void __iomem *global_addr;
- unsigned long ctrl, bd;
+ u32 ctrl, bd;
unsigned int val = 0;
int ret;
ret = clk_prepare_enable(sport->ipg_clk);
if (ret) {
- dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
+ dev_err(port->dev, "failed to enable uart ipg clk: %d\n", ret);
return ret;
}
@@ -2817,10 +2833,10 @@ static int lpuart_global_reset(struct lpuart_port *sport)
*/
ctrl = lpuart32_read(port, UARTCTRL);
if (ctrl & UARTCTRL_TE) {
- bd = lpuart32_read(&sport->port, UARTBAUD);
+ bd = lpuart32_read(port, UARTBAUD);
if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false,
port)) {
- dev_warn(sport->port.dev,
+ dev_warn(port->dev,
"timeout waiting for transmit engine to complete\n");
clk_disable_unprepare(sport->ipg_clk);
return 0;
@@ -2949,7 +2965,7 @@ static int lpuart_probe(struct platform_device *pdev)
goto failed_attach_port;
ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0,
- DRIVER_NAME, sport);
+ dev_name(&pdev->dev), sport);
if (ret)
goto failed_irq_request;
@@ -3006,7 +3022,7 @@ static int lpuart_runtime_resume(struct device *dev)
static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
{
- unsigned int val, baud;
+ u32 val, baud;
if (lpuart_is_32(sport)) {
val = lpuart32_read(&sport->port, UARTCTRL);
@@ -3071,7 +3087,7 @@ static int lpuart_suspend_noirq(struct device *dev)
static int lpuart_resume_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned int val;
+ u32 stat;
pinctrl_pm_select_default_state(dev);
@@ -3080,8 +3096,8 @@ static int lpuart_resume_noirq(struct device *dev)
/* clear the wakeup flags */
if (lpuart_is_32(sport)) {
- val = lpuart32_read(&sport->port, UARTSTAT);
- lpuart32_write(&sport->port, val, UARTSTAT);
+ stat = lpuart32_read(&sport->port, UARTSTAT);
+ lpuart32_write(&sport->port, stat, UARTSTAT);
}
}
@@ -3091,7 +3107,8 @@ static int lpuart_resume_noirq(struct device *dev)
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned long temp, flags;
+ u32 temp;
+ unsigned long flags;
uart_suspend_port(&lpuart_reg, &sport->port);
@@ -3171,7 +3188,7 @@ static void lpuart_console_fixup(struct lpuart_port *sport)
* in VLLS mode, or restore console setting here.
*/
if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
- console_suspend_enabled && uart_console(&sport->port)) {
+ console_suspend_enabled && uart_console(uport)) {
mutex_lock(&port->mutex);
memset(&termios, 0, sizeof(struct ktermios));
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index 29e42831df39..7fb995a8490e 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -1764,11 +1764,10 @@ static int icom_probe(struct pci_dev *dev,
goto probe_exit1;
}
- /* save off irq and request irq line */
- retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
- if (retval) {
- goto probe_exit2;
- }
+ /* save off irq and request irq line */
+ retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, icom_adapter);
+ if (retval)
+ goto probe_exit2;
retval = icom_load_ports(icom_adapter);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 9c59ec128bb4..500dfc009d03 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -235,6 +235,7 @@ struct imx_port {
enum imx_tx_state tx_state;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
+ unsigned int rxtl;
};
struct imx_port_ucrs {
@@ -1165,7 +1166,7 @@ static void imx_uart_break_ctl(struct uart_port *port, int break_state)
*/
static void imx_uart_timeout(struct timer_list *t)
{
- struct imx_port *sport = from_timer(sport, t, timer);
+ struct imx_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
@@ -1339,6 +1340,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
#define TXTL_DEFAULT 8
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
+#define RXTL_CONSOLE_DEFAULT 1
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_DMA 9 /* DMA burst setting */
@@ -1457,7 +1459,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN);
imx_uart_writel(sport, ucr1, UCR1);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
sport->dma_is_enabled = 0;
}
@@ -1482,7 +1484,12 @@ static int imx_uart_startup(struct uart_port *port)
return retval;
}
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ if (uart_console(&sport->port))
+ sport->rxtl = RXTL_CONSOLE_DEFAULT;
+ else
+ sport->rxtl = RXTL_DEFAULT;
+
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
/* disable the DREN bit (Data Ready interrupt enable) before
* requesting IRQs
@@ -1608,7 +1615,7 @@ static void imx_uart_shutdown(struct uart_port *port)
imx_uart_dma_exit(sport);
}
- mctrl_gpio_disable_ms(sport->gpios);
+ mctrl_gpio_disable_ms_sync(sport->gpios);
uart_port_lock_irqsave(&sport->port, &flags);
ucr2 = imx_uart_readl(sport, UCR2);
@@ -1619,7 +1626,7 @@ static void imx_uart_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Disable all interrupts, port and break condition.
@@ -1752,7 +1759,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
old_csize = CS8;
}
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Ask the core to calculate the divisor for us.
@@ -1948,7 +1955,7 @@ static int imx_uart_poll_init(struct uart_port *port)
if (retval)
clk_disable_unprepare(sport->clk_ipg);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
uart_port_lock_irqsave(&sport->port, &flags);
@@ -2040,7 +2047,7 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
/* If the receiver trigger is 0, set it to a default value */
ufcr = imx_uart_readl(sport, UFCR);
if ((ufcr & UFCR_RXTL_MASK) == 0)
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
imx_uart_start_rx(port);
}
@@ -2302,7 +2309,7 @@ imx_uart_console_setup(struct console *co, char *options)
else
imx_uart_console_get_options(sport, &baud, &parity, &bits);
- imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, sport->rxtl);
retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
@@ -2582,10 +2589,10 @@ static int imx_uart_probe(struct platform_device *pdev)
imx_uart_writel(sport, ucr3, UCR3);
}
- hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- sport->trigger_start_tx.function = imx_trigger_start_tx;
- sport->trigger_stop_tx.function = imx_trigger_stop_tx;
+ hrtimer_setup(&sport->trigger_start_tx, imx_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&sport->trigger_stop_tx, imx_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c
index ce0fef7e2c66..be2f130696b3 100644
--- a/drivers/tty/serial/jsm/jsm_tty.c
+++ b/drivers/tty/serial/jsm/jsm_tty.c
@@ -451,6 +451,7 @@ int jsm_uart_port_init(struct jsm_board *brd)
if (!brd->channels[i])
continue;
+ brd->channels[i]->uart_port.dev = &brd->pci_dev->dev;
brd->channels[i]->uart_port.irq = brd->irq;
brd->channels[i]->uart_port.uartclk = 14745600;
brd->channels[i]->uart_port.type = PORT_JSM;
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
deleted file mode 100644
index e93850f6447a..000000000000
--- a/drivers/tty/serial/kgdb_nmi.c
+++ /dev/null
@@ -1,381 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * KGDB NMI serial console
- *
- * Copyright 2010 Google, Inc.
- * Arve Hjønnevåg <arve@android.com>
- * Colin Cross <ccross@android.com>
- * Copyright 2012 Linaro Ltd.
- * Anton Vorontsov <anton.vorontsov@linaro.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/atomic.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <linux/kfifo.h>
-#include <linux/kgdb.h>
-#include <linux/kdb.h>
-
-static int kgdb_nmi_knock = 1;
-module_param_named(knock, kgdb_nmi_knock, int, 0600);
-MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \
- "must be used to enter the debugger; when set to 0, " \
- "hitting return key is enough to enter the debugger; " \
- "when set to -1, the debugger is entered immediately " \
- "upon NMI");
-
-static char *kgdb_nmi_magic = "$3#33";
-module_param_named(magic, kgdb_nmi_magic, charp, 0600);
-MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
-
-static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
-
-static int kgdb_nmi_console_setup(struct console *co, char *options)
-{
- arch_kgdb_ops.enable_nmi(1);
-
- /* The NMI console uses the dbg_io_ops to issue console messages. To
- * avoid duplicate messages during kdb sessions we must inform kdb's
- * I/O utilities that messages sent to the console will automatically
- * be displayed on the dbg_io.
- */
- dbg_io_ops->cons = co;
-
- return 0;
-}
-
-static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(s[i]);
-}
-
-static struct tty_driver *kgdb_nmi_tty_driver;
-
-static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
-{
- *idx = co->index;
- return kgdb_nmi_tty_driver;
-}
-
-static struct console kgdb_nmi_console = {
- .name = "ttyNMI",
- .setup = kgdb_nmi_console_setup,
- .write = kgdb_nmi_console_write,
- .device = kgdb_nmi_console_device,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
- .index = -1,
-};
-
-/*
- * This is usually the maximum rate on debug ports. We make fifo large enough
- * to make copy-pasting to the terminal usable.
- */
-#define KGDB_NMI_BAUD 115200
-#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
-
-struct kgdb_nmi_tty_priv {
- struct tty_port port;
- struct timer_list timer;
- STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
-};
-
-static struct tty_port *kgdb_nmi_port;
-
-static void kgdb_tty_recv(int ch)
-{
- struct kgdb_nmi_tty_priv *priv;
- char c = ch;
-
- if (!kgdb_nmi_port || ch < 0)
- return;
- /*
- * Can't use port->tty->driver_data as tty might be not there. Timer
- * will check for tty and will get the ref, but here we don't have to
- * do that, and actually, we can't: we're in NMI context, no locks are
- * possible.
- */
- priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
- kfifo_in(&priv->fifo, &c, 1);
-}
-
-static int kgdb_nmi_poll_one_knock(void)
-{
- static int n;
- int c;
- const char *magic = kgdb_nmi_magic;
- size_t m = strlen(magic);
- bool printch = false;
-
- c = dbg_io_ops->read_char();
- if (c == NO_POLL_CHAR)
- return c;
-
- if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) {
- return 1;
- } else if (c == magic[n]) {
- n = (n + 1) % m;
- if (!n)
- return 1;
- printch = true;
- } else {
- n = 0;
- }
-
- if (atomic_read(&kgdb_nmi_num_readers)) {
- kgdb_tty_recv(c);
- return 0;
- }
-
- if (printch) {
- kdb_printf("%c", c);
- return 0;
- }
-
- kdb_printf("\r%s %s to enter the debugger> %*s",
- kgdb_nmi_knock ? "Type" : "Hit",
- kgdb_nmi_knock ? magic : "<return>", (int)m, "");
- while (m--)
- kdb_printf("\b");
- return 0;
-}
-
-/**
- * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
- *
- * "Serial ports are often noisy, especially when muxed over another port (we
- * often use serial over the headset connector). Noise on the async command
- * line just causes characters that are ignored, on a command line that blocked
- * execution noise would be catastrophic." -- Colin Cross
- *
- * So, this function implements KGDB/KDB knocking on the serial line: we won't
- * enter the debugger until we receive a known magic phrase (which is actually
- * "$3#33", known as "escape to KDB" command. There is also a relaxed variant
- * of knocking, i.e. just pressing the return key is enough to enter the
- * debugger. And if knocking is disabled, the function always returns 1.
- */
-bool kgdb_nmi_poll_knock(void)
-{
- if (kgdb_nmi_knock < 0)
- return true;
-
- while (1) {
- int ret;
-
- ret = kgdb_nmi_poll_one_knock();
- if (ret == NO_POLL_CHAR)
- return false;
- else if (ret == 1)
- break;
- }
- return true;
-}
-
-/*
- * The tasklet is cheap, it does not cause wakeups when reschedules itself,
- * instead it waits for the next tick.
- */
-static void kgdb_nmi_tty_receiver(struct timer_list *t)
-{
- struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer);
- char ch;
-
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
- !kfifo_len(&priv->fifo)))
- return;
-
- while (kfifo_out(&priv->fifo, &ch, 1))
- tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
- tty_flip_buffer_push(&priv->port);
-}
-
-static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- kgdb_nmi_port = port;
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- return 0;
-}
-
-static void kgdb_nmi_tty_shutdown(struct tty_port *port)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- del_timer(&priv->timer);
- kgdb_nmi_port = NULL;
-}
-
-static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
- .activate = kgdb_nmi_tty_activate,
- .shutdown = kgdb_nmi_tty_shutdown,
-};
-
-static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv;
- int ret;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- INIT_KFIFO(priv->fifo);
- timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0);
- tty_port_init(&priv->port);
- priv->port.ops = &kgdb_nmi_tty_port_ops;
- tty->driver_data = priv;
-
- ret = tty_port_install(&priv->port, drv, tty);
- if (ret) {
- pr_err("%s: can't install tty port: %d\n", __func__, ret);
- goto err;
- }
- return 0;
-err:
- tty_port_destroy(&priv->port);
- kfree(priv);
- return ret;
-}
-
-static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty->driver_data = NULL;
- tty_port_destroy(&priv->port);
- kfree(priv);
-}
-
-static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
- int ret;
-
- ret = tty_port_open(&priv->port, tty, file);
- if (!ret && (mode == O_RDONLY || mode == O_RDWR))
- atomic_inc(&kgdb_nmi_num_readers);
-
- return ret;
-}
-
-static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
-
- if (mode == O_RDONLY || mode == O_RDWR)
- atomic_dec(&kgdb_nmi_num_readers);
-
- tty_port_close(&priv->port, tty, file);
-}
-
-static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty_port_hangup(&priv->port);
-}
-
-static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
-{
- /* Actually, we can handle any amount as we use polled writes. */
- return 2048;
-}
-
-static ssize_t kgdb_nmi_tty_write(struct tty_struct *tty, const u8 *buf,
- size_t c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(buf[i]);
- return c;
-}
-
-static const struct tty_operations kgdb_nmi_tty_ops = {
- .open = kgdb_nmi_tty_open,
- .close = kgdb_nmi_tty_close,
- .install = kgdb_nmi_tty_install,
- .cleanup = kgdb_nmi_tty_cleanup,
- .hangup = kgdb_nmi_tty_hangup,
- .write_room = kgdb_nmi_tty_write_room,
- .write = kgdb_nmi_tty_write,
-};
-
-int kgdb_register_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
-
- kgdb_nmi_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
- if (IS_ERR(kgdb_nmi_tty_driver)) {
- pr_err("%s: cannot allocate tty\n", __func__);
- return PTR_ERR(kgdb_nmi_tty_driver);
- }
- kgdb_nmi_tty_driver->driver_name = "ttyNMI";
- kgdb_nmi_tty_driver->name = "ttyNMI";
- kgdb_nmi_tty_driver->num = 1;
- kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- kgdb_nmi_tty_driver->init_termios = tty_std_termios;
- tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
- KGDB_NMI_BAUD, KGDB_NMI_BAUD);
- tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
-
- ret = tty_register_driver(kgdb_nmi_tty_driver);
- if (ret) {
- pr_err("%s: can't register tty driver: %d\n", __func__, ret);
- goto err_drv_reg;
- }
-
- register_console(&kgdb_nmi_console);
-
- return 0;
-err_drv_reg:
- tty_driver_kref_put(kgdb_nmi_tty_driver);
- return ret;
-}
-EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
-
-int kgdb_unregister_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
- arch_kgdb_ops.enable_nmi(0);
-
- ret = unregister_console(&kgdb_nmi_console);
- if (ret)
- return ret;
-
- tty_unregister_driver(kgdb_nmi_tty_driver);
- tty_driver_kref_put(kgdb_nmi_tty_driver);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 58ea1e1391ce..85f6c5a76e0f 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -186,8 +186,6 @@ static void cleanup_kgdboc(void)
if (configured != 1)
return;
- if (kgdb_unregister_nmi_console())
- return;
kgdboc_unregister_kbd();
kgdb_unregister_io_module(&kgdboc_io_ops);
}
@@ -250,16 +248,10 @@ do_register:
if (err)
goto noconfig;
- err = kgdb_register_nmi_console();
- if (err)
- goto nmi_con_failed;
-
configured = 1;
return 0;
-nmi_con_failed:
- kgdb_unregister_io_module(&kgdboc_io_ops);
noconfig:
kgdboc_unregister_kbd();
configured = 0;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index 58a3ab030d67..62cd9e0bb377 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -773,10 +773,8 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port)
int ret;
ret = platform_get_irq(to_platform_device(dev), 0);
- if (ret < 0) {
- dev_err(dev, "failed to fetch IRQ for serial port\n");
+ if (ret < 0)
return ret;
- }
ltq_port->common_irq = ret;
port->irq = ret;
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 6c13cf1ab646..6429e8f11f36 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -96,7 +96,7 @@ static void liteuart_stop_rx(struct uart_port *port)
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
- del_timer(&uart->timer);
+ timer_delete(&uart->timer);
}
static void liteuart_rx_chars(struct uart_port *port)
@@ -152,7 +152,7 @@ static irqreturn_t liteuart_interrupt(int irq, void *data)
static void liteuart_timer(struct timer_list *t)
{
- struct liteuart_port *uart = from_timer(uart, t, timer);
+ struct liteuart_port *uart = timer_container_of(uart, t, timer);
struct uart_port *port = &uart->port;
liteuart_interrupt(0, port);
@@ -220,7 +220,7 @@ static void liteuart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&uart->timer);
+ timer_delete_sync(&uart->timer);
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 8dcad52eedfd..285b0fe41a86 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -799,7 +799,7 @@ static struct platform_driver ma35d1serial_driver = {
.resume = ma35d1serial_resume,
.driver = {
.name = "ma35d1-uart",
- .of_match_table = of_match_ptr(ma35d1_serial_of_match),
+ .of_match_table = ma35d1_serial_of_match,
},
};
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index cde5f1c86353..67d80f8f801e 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -16,6 +16,7 @@
/* 4 MAX3100s should be enough for everyone */
#define MAX_MAX3100 4
+#include <linux/bitops.h>
#include <linux/container_of.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -133,7 +134,7 @@ static int max3100_do_parity(struct max3100_port *s, u16 c)
else
c &= 0xff;
- parity = parity ^ (hweight8(c) & 1);
+ parity = parity ^ parity8(c);
return parity;
}
@@ -308,7 +309,7 @@ static void max3100_dowork(struct max3100_port *s)
static void max3100_timeout(struct timer_list *t)
{
- struct max3100_port *s = from_timer(s, t, timer);
+ struct max3100_port *s = timer_container_of(s, t, timer);
max3100_dowork(s);
mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port));
@@ -506,7 +507,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
MAX3100_STATUS_PE | MAX3100_STATUS_FE |
MAX3100_STATUS_OE;
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
uart_update_timeout(port, termios->c_cflag, baud);
spin_lock(&s->conf_lock);
@@ -532,7 +533,7 @@ static void max3100_shutdown(struct uart_port *port)
s->force_end_work = 1;
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
if (s->workqueue) {
destroy_workqueue(s->workqueue);
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 35369a2f77b2..541c790c0109 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1189,13 +1189,16 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
return !!((val >> 4) & (1 << (offset % 4)));
}
-static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+static int max310x_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct max310x_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[offset / 4].port;
max310x_port_update(port, MAX310X_GPIODATA_REG, 1 << (offset % 4),
value ? 1 << (offset % 4) : 0);
+
+ return 0;
}
static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
@@ -1411,7 +1414,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
s->gpio.direction_input = max310x_gpio_direction_input;
s->gpio.get = max310x_gpio_get;
s->gpio.direction_output= max310x_gpio_direction_output;
- s->gpio.set = max310x_gpio_set;
+ s->gpio.set_rv = max310x_gpio_set;
s->gpio.set_config = max310x_gpio_set_config;
s->gpio.base = -1;
s->gpio.ngpio = devtype->nr * 4;
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index 059bea18dbab..4e47dca2c4ed 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -523,7 +523,10 @@ static int mlb_usio_probe(struct platform_device *pdev)
}
port->membase = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
-
+ if (!port->membase) {
+ ret = -ENOMEM;
+ goto failed;
+ }
ret = platform_get_irq_byname(pdev, "rx");
mlb_usio_irq[index][RX] = ret;
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index f55aa353aed9..37eb701b0b46 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1351,7 +1351,6 @@ static const struct uart_ops mpc52xx_uart_ops = {
.startup = mpc52xx_uart_startup,
.shutdown = mpc52xx_uart_shutdown,
.set_termios = mpc52xx_uart_set_termios,
-/* .pm = mpc52xx_uart_pm, Not supported yet */
.type = mpc52xx_uart_type,
.release_port = mpc52xx_uart_release_port,
.request_port = mpc52xx_uart_request_port,
@@ -1621,7 +1620,7 @@ mpc52xx_console_setup(struct console *co, char *options)
(void *)port->mapbase, port->membase,
port->irq, port->uartclk);
- /* Setup the port parameters accoding to options */
+ /* Setup the port parameters according to options */
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 1b137e068444..3449945493ce 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -1746,6 +1746,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
+ /* Disable DM / single-character modes */
+ msm_write(&device->port, 0, UARTDM_DMEN);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
+
device->con->write = msm_serial_early_write_dm;
return 0;
}
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 85ce1e9af44a..b417faead20f 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -563,7 +563,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
- del_timer_sync(&mux_timer);
+ timer_delete_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c7cee5fee603..884fefbfd5a1 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -954,7 +954,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
__func__);
return 0;
}
- dma_sync_sg_for_device(port->dev, priv->sg_tx_p, nent, DMA_TO_DEVICE);
+ dma_sync_sg_for_device(port->dev, priv->sg_tx_p, num, DMA_TO_DEVICE);
priv->desc_tx = desc;
desc->callback = pch_dma_tx_complete;
desc->callback_param = priv;
@@ -1515,7 +1515,6 @@ static const struct uart_ops pch_uart_ops = {
.startup = pch_uart_startup,
.shutdown = pch_uart_shutdown,
.set_termios = pch_uart_set_termios,
-/* .pm = pch_uart_pm, Not supported yet */
.type = pch_uart_type,
.release_port = pch_uart_release_port,
.request_port = pch_uart_request_port,
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index a80ce7aaf309..0293b6210aa6 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -98,6 +98,8 @@
#define DMA_RX_BUF_SIZE 2048
+static DEFINE_IDA(port_ida);
+
struct qcom_geni_device_data {
bool console;
enum geni_se_xfer_mode mode;
@@ -253,10 +255,24 @@ static struct qcom_geni_serial_port *get_port_from_line(int line, bool console)
struct qcom_geni_serial_port *port;
int nr_ports = console ? GENI_UART_CONS_PORTS : GENI_UART_PORTS;
- if (line < 0 || line >= nr_ports)
- return ERR_PTR(-ENXIO);
+ if (console) {
+ if (line < 0 || line >= nr_ports)
+ return ERR_PTR(-ENXIO);
+
+ port = &qcom_geni_console_port;
+ } else {
+ int max_alias_num = of_alias_get_highest_id("serial");
+
+ if (line < 0 || line >= nr_ports)
+ line = ida_alloc_range(&port_ida, max_alias_num + 1, nr_ports, GFP_KERNEL);
+ else
+ line = ida_alloc_range(&port_ida, line, nr_ports, GFP_KERNEL);
+
+ if (line < 0)
+ return ERR_PTR(-ENXIO);
- port = console ? &qcom_geni_console_port : &qcom_geni_uart_ports[line];
+ port = &qcom_geni_uart_ports[line];
+ }
return port;
}
@@ -1761,6 +1777,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
port->wakeup_irq);
if (ret) {
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, uport);
return ret;
}
@@ -1772,10 +1789,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
static void qcom_geni_serial_remove(struct platform_device *pdev)
{
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
+ struct uart_port *uport = &port->uport;
struct uart_driver *drv = port->private_data.drv;
dev_pm_clear_wake_irq(&pdev->dev);
device_init_wakeup(&pdev->dev, false);
+ ida_free(&port_ida, uport->line);
uart_remove_one_port(drv, &port->uport);
}
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 3c34027687d2..72b1bb76415c 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -111,7 +111,7 @@ static void sa1100_mctrl_check(struct sa1100_port *sport)
*/
static void sa1100_timeout(struct timer_list *t)
{
- struct sa1100_port *sport = from_timer(sport, t, timer);
+ struct sa1100_port *sport = timer_container_of(sport, t, timer);
unsigned long flags;
if (sport->port.state) {
@@ -369,7 +369,7 @@ static void sa1100_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Free the interrupt
@@ -421,7 +421,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
uart_port_lock_irqsave(&sport->port, &flags);
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index 210fff7164c1..2fb58c626daf 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -52,7 +52,7 @@
#define S3C24XX_SERIAL_MINOR 64
#ifdef CONFIG_ARM64
-#define UART_NR 12
+#define UART_NR 18
#else
#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS
#endif
@@ -190,6 +190,8 @@ static void wr_reg(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel_relaxed(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
@@ -2713,6 +2715,8 @@ static void wr_reg_barrier(const struct uart_port *port, u32 reg, u32 val)
case UPIO_MEM32:
writel(val, portaddr(port, reg));
break;
+ default:
+ break;
}
}
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index a3093e09309f..5ea8aadb6e69 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -314,6 +314,7 @@
#define SC16IS7XX_FIFO_SIZE (64)
#define SC16IS7XX_GPIOS_PER_BANK 4
+#define SC16IS7XX_POLL_PERIOD_MS 10
#define SC16IS7XX_RECONF_MD BIT(0)
#define SC16IS7XX_RECONF_IER BIT(1)
#define SC16IS7XX_RECONF_RS485 BIT(2)
@@ -348,6 +349,8 @@ struct sc16is7xx_port {
u8 mctrl_mask;
struct kthread_worker kworker;
struct task_struct *kworker_task;
+ struct kthread_delayed_work poll_work;
+ bool polling;
struct sc16is7xx_one p[];
};
@@ -861,6 +864,18 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void sc16is7xx_poll_proc(struct kthread_work *ws)
+{
+ struct sc16is7xx_port *s = container_of(ws, struct sc16is7xx_port, poll_work.work);
+
+ /* Reuse standard IRQ handler. Interrupt ID is unused in this context. */
+ sc16is7xx_irq(0, s);
+
+ /* Setup delay based on SC16IS7XX_POLL_PERIOD_MS */
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS));
+}
+
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
@@ -1149,6 +1164,7 @@ 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_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
@@ -1211,6 +1227,10 @@ static int sc16is7xx_startup(struct uart_port *port)
sc16is7xx_enable_ms(port);
uart_port_unlock_irqrestore(port, flags);
+ if (s->polling)
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS));
+
return 0;
}
@@ -1232,6 +1252,9 @@ static void sc16is7xx_shutdown(struct uart_port *port)
sc16is7xx_power(port, 0);
+ if (s->polling)
+ kthread_cancel_delayed_work_sync(&s->poll_work);
+
kthread_flush_worker(&s->kworker);
}
@@ -1310,13 +1333,16 @@ static int sc16is7xx_gpio_get(struct gpio_chip *chip, unsigned offset)
return !!(val & BIT(offset));
}
-static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+static int sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int val)
{
struct sc16is7xx_port *s = gpiochip_get_data(chip);
struct uart_port *port = &s->p[0].port;
sc16is7xx_port_update(port, SC16IS7XX_IOSTATE_REG, BIT(offset),
val ? BIT(offset) : 0);
+
+ return 0;
}
static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
@@ -1399,7 +1425,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
s->gpio.direction_input = sc16is7xx_gpio_direction_input;
s->gpio.get = sc16is7xx_gpio_get;
s->gpio.direction_output = sc16is7xx_gpio_direction_output;
- s->gpio.set = sc16is7xx_gpio_set;
+ s->gpio.set_rv = sc16is7xx_gpio_set;
s->gpio.base = -1;
s->gpio.ngpio = s->devtype->nr_gpio;
s->gpio.can_sleep = 1;
@@ -1538,6 +1564,11 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
+ s->polling = (irq <= 0);
+ if (s->polling)
+ dev_dbg(dev,
+ "No interrupt pin definition, falling back to polling mode\n");
+
s->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
@@ -1665,6 +1696,12 @@ int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
goto out_ports;
#endif
+ if (s->polling) {
+ /* Initialize kernel thread for polling */
+ kthread_init_delayed_work(&s->poll_work, sc16is7xx_poll_proc);
+ return 0;
+ }
+
/*
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
* If that succeeds, we can allow sharing the interrupt as well.
@@ -1724,6 +1761,9 @@ void sc16is7xx_remove(struct device *dev)
sc16is7xx_power(&s->p[i].port, 0);
}
+ if (s->polling)
+ kthread_cancel_delayed_work_sync(&s->poll_work);
+
kthread_flush_worker(&s->kworker);
kthread_stop(s->kworker_task);
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index 4c851dae6624..4ceca11ce600 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -500,7 +500,7 @@ static void sccnxp_handle_events(struct sccnxp_port *s)
static void sccnxp_timer(struct timer_list *t)
{
- struct sccnxp_port *s = from_timer(s, t, timer);
+ struct sccnxp_port *s = timer_container_of(s, t, timer);
unsigned long flags;
spin_lock_irqsave(&s->lock, flags);
@@ -1033,7 +1033,7 @@ static void sccnxp_remove(struct platform_device *pdev)
if (!s->poll)
devm_free_irq(&pdev->dev, s->irq, s);
else
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
for (i = 0; i < s->uart.nr; i++)
uart_remove_one_port(&s->uart, &s->port[i]);
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index 5d1677f1b651..22749ab0428a 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -13,6 +13,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -72,6 +73,7 @@ static int serial_base_device_init(struct uart_port *port,
dev->parent = parent_dev;
dev->bus = &serial_base_bus_type;
dev->release = release;
+ device_set_of_node_from_dev(dev, parent_dev);
if (!serial_base_initialized) {
dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n");
@@ -92,6 +94,7 @@ static void serial_base_ctrl_release(struct device *dev)
{
struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev);
+ of_node_put(dev->of_node);
kfree(ctrl_dev);
}
@@ -139,6 +142,7 @@ static void serial_base_port_release(struct device *dev)
{
struct serial_port_device *port_dev = to_serial_base_port_device(dev);
+ of_node_put(dev->of_node);
kfree(port_dev);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 74fa02b23772..8a1482131257 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -75,22 +75,23 @@ static inline void uart_port_deref(struct uart_port *uport)
wake_up(&uport->state->remove_wait);
}
-#define uart_port_lock(state, flags) \
- ({ \
- struct uart_port *__uport = uart_port_ref(state); \
- if (__uport) \
- uart_port_lock_irqsave(__uport, &flags); \
- __uport; \
- })
-
-#define uart_port_unlock(uport, flags) \
- ({ \
- struct uart_port *__uport = uport; \
- if (__uport) { \
- uart_port_unlock_irqrestore(__uport, flags); \
- uart_port_deref(__uport); \
- } \
- })
+static inline struct uart_port *uart_port_ref_lock(struct uart_state *state, unsigned long *flags)
+{
+ struct uart_port *uport = uart_port_ref(state);
+
+ if (uport)
+ uart_port_lock_irqsave(uport, flags);
+
+ return uport;
+}
+
+static inline void uart_port_unlock_deref(struct uart_port *uport, unsigned long flags)
+{
+ if (uport) {
+ uart_port_unlock_irqrestore(uport, flags);
+ uart_port_deref(uport);
+ }
+}
static inline struct uart_port *uart_port_check(struct uart_state *state)
{
@@ -127,10 +128,10 @@ static void uart_stop(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (port)
port->ops->stop_tx(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void __uart_start(struct uart_state *state)
@@ -168,9 +169,9 @@ static void uart_start(struct tty_struct *tty)
struct uart_port *port;
unsigned long flags;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
}
static void
@@ -258,14 +259,14 @@ static int uart_alloc_xmit_buf(struct tty_port *port)
if (!page)
return -ENOMEM;
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsigned char *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
} else {
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
/*
* Do not free() the page under the port lock, see
* uart_free_xmit_buf().
@@ -289,11 +290,11 @@ static void uart_free_xmit_buf(struct tty_port *port)
* console driver may need to allocate/free a debug object, which
* can end up in printk() recursion.
*/
- uport = uart_port_lock(state, flags);
+ uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
- uart_port_unlock(uport, flags);
+ uart_port_unlock_deref(uport, flags);
free_page((unsigned long)xmit_buf);
}
@@ -592,15 +593,15 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
unsigned long flags;
int ret = 0;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -623,9 +624,9 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
if (WARN_ON(!state))
return -EL3HLT;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!state->port.xmit_buf) {
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return 0;
}
@@ -633,7 +634,7 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -644,9 +645,9 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_avail(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -657,9 +658,9 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
unsigned int ret;
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
ret = kfifo_len(&state->port.xmit_fifo);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
return ret;
}
@@ -678,13 +679,13 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
- port = uart_port_lock(state, flags);
+ port = uart_port_ref_lock(state, &flags);
if (!port)
return;
kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
- uart_port_unlock(port, flags);
+ uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
@@ -790,7 +791,6 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
- int ret = -ENODEV;
/* Initialize structure in case we error out later to prevent any stack info leakage. */
*retinfo = (struct serial_struct){};
@@ -799,10 +799,10 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
* Ensure the state we copy is consistent and no hardware changes
* occur as we go
*/
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
if (!uport)
- goto out;
+ return -ENODEV;
retinfo->type = uport->type;
retinfo->line = uport->line;
@@ -823,10 +823,7 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
retinfo->iomem_reg_shift = uport->regshift;
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
- ret = 0;
-out:
- mutex_unlock(&port->mutex);
- return ret;
+ return 0;
}
static int uart_get_info_user(struct tty_struct *tty,
@@ -838,16 +835,71 @@ static int uart_get_info_user(struct tty_struct *tty,
return uart_get_info(port, ss) < 0 ? -EIO : 0;
}
+static int uart_change_port(struct uart_port *uport,
+ const struct serial_struct *new_info,
+ unsigned long new_port)
+{
+ unsigned long old_iobase, old_mapbase;
+ unsigned int old_type, old_iotype, old_hub6, old_shift;
+ int retval;
+
+ old_iobase = uport->iobase;
+ old_mapbase = uport->mapbase;
+ old_type = uport->type;
+ old_hub6 = uport->hub6;
+ old_iotype = uport->iotype;
+ old_shift = uport->regshift;
+
+ if (old_type != PORT_UNKNOWN && uport->ops->release_port)
+ uport->ops->release_port(uport);
+
+ uport->iobase = new_port;
+ uport->type = new_info->type;
+ uport->hub6 = new_info->hub6;
+ uport->iotype = new_info->io_type;
+ uport->regshift = new_info->iomem_reg_shift;
+ uport->mapbase = (unsigned long)new_info->iomem_base;
+
+ if (uport->type == PORT_UNKNOWN || !uport->ops->request_port)
+ return 0;
+
+ retval = uport->ops->request_port(uport);
+ if (retval == 0)
+ return 0; /* succeeded => done */
+
+ /*
+ * If we fail to request resources for the new port, try to restore the
+ * old settings.
+ */
+ uport->iobase = old_iobase;
+ uport->type = old_type;
+ uport->hub6 = old_hub6;
+ uport->iotype = old_iotype;
+ uport->regshift = old_shift;
+ uport->mapbase = old_mapbase;
+
+ if (old_type == PORT_UNKNOWN)
+ return retval;
+
+ retval = uport->ops->request_port(uport);
+ /* If we failed to restore the old settings, we fail like this. */
+ if (retval)
+ uport->type = PORT_UNKNOWN;
+
+ /* We failed anyway. */
+ return -EBUSY;
+}
+
static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
struct uart_state *state,
struct serial_struct *new_info)
{
struct uart_port *uport = uart_port_check(state);
unsigned long new_port;
- unsigned int change_irq, change_port, closing_wait;
- unsigned int old_custom_divisor, close_delay;
+ unsigned int old_custom_divisor, close_delay, closing_wait;
+ bool change_irq, change_port;
upf_t old_flags, new_flags;
- int retval = 0;
+ int retval;
if (!uport)
return -EIO;
@@ -886,13 +938,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
if (!(uport->flags & UPF_FIXED_PORT)) {
unsigned int uartclk = new_info->baud_base * 16;
/* check needs to be done here before other settings made */
- if (uartclk == 0) {
- retval = -EINVAL;
- goto exit;
- }
+ if (uartclk == 0)
+ return -EINVAL;
}
if (!capable(CAP_SYS_ADMIN)) {
- retval = -EPERM;
if (change_irq || change_port ||
(new_info->baud_base != uport->uartclk / 16) ||
(close_delay != port->close_delay) ||
@@ -900,7 +949,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
(new_info->xmit_fifo_size &&
new_info->xmit_fifo_size != uport->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
- goto exit;
+ return -EPERM;
uport->flags = ((uport->flags & ~UPF_USR_MASK) |
(new_flags & UPF_USR_MASK));
uport->custom_divisor = new_info->custom_divisor;
@@ -910,30 +959,24 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
if (change_irq || change_port) {
retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
if (retval)
- goto exit;
+ return retval;
}
- /*
- * Ask the low level driver to verify the settings.
- */
- if (uport->ops->verify_port)
+ /* Ask the low level driver to verify the settings. */
+ if (uport->ops->verify_port) {
retval = uport->ops->verify_port(uport, new_info);
+ if (retval)
+ return retval;
+ }
if ((new_info->irq >= irq_get_nr_irqs()) || (new_info->irq < 0) ||
(new_info->baud_base < 9600))
- retval = -EINVAL;
-
- if (retval)
- goto exit;
+ return -EINVAL;
if (change_port || change_irq) {
- retval = -EBUSY;
-
- /*
- * Make sure that we are the sole user of this port.
- */
+ /* Make sure that we are the sole user of this port. */
if (tty_port_users(port) > 1)
- goto exit;
+ return -EBUSY;
/*
* We need to shutdown the serial port at the old
@@ -943,69 +986,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
}
if (change_port) {
- unsigned long old_iobase, old_mapbase;
- unsigned int old_type, old_iotype, old_hub6, old_shift;
-
- old_iobase = uport->iobase;
- old_mapbase = uport->mapbase;
- old_type = uport->type;
- old_hub6 = uport->hub6;
- old_iotype = uport->iotype;
- old_shift = uport->regshift;
-
- /*
- * Free and release old regions
- */
- if (old_type != PORT_UNKNOWN && uport->ops->release_port)
- uport->ops->release_port(uport);
-
- uport->iobase = new_port;
- uport->type = new_info->type;
- uport->hub6 = new_info->hub6;
- uport->iotype = new_info->io_type;
- uport->regshift = new_info->iomem_reg_shift;
- uport->mapbase = (unsigned long)new_info->iomem_base;
-
- /*
- * Claim and map the new regions
- */
- if (uport->type != PORT_UNKNOWN && uport->ops->request_port) {
- retval = uport->ops->request_port(uport);
- } else {
- /* Always success - Jean II */
- retval = 0;
- }
-
- /*
- * If we fail to request resources for the
- * new port, try to restore the old settings.
- */
- if (retval) {
- uport->iobase = old_iobase;
- uport->type = old_type;
- uport->hub6 = old_hub6;
- uport->iotype = old_iotype;
- uport->regshift = old_shift;
- uport->mapbase = old_mapbase;
-
- if (old_type != PORT_UNKNOWN) {
- retval = uport->ops->request_port(uport);
- /*
- * If we failed to restore the old settings,
- * we fail like this.
- */
- if (retval)
- uport->type = PORT_UNKNOWN;
-
- /*
- * We failed anyway.
- */
- retval = -EBUSY;
- }
-
- /* Added to return the correct error -Ram Gupta */
- goto exit;
- }
+ retval = uart_change_port(uport, new_info, new_port);
+ if (retval)
+ return retval;
}
if (change_irq)
@@ -1021,9 +1004,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
uport->fifosize = new_info->xmit_fifo_size;
check_and_exit:
- retval = 0;
if (uport->type == PORT_UNKNOWN)
- goto exit;
+ return 0;
+
if (tty_port_initialized(port)) {
if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
old_custom_divisor != uport->custom_divisor) {
@@ -1039,15 +1022,17 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
}
uart_change_line_settings(tty, state, NULL);
}
- } else {
- retval = uart_startup(tty, state, true);
- if (retval == 0)
- tty_port_set_initialized(port, true);
- if (retval > 0)
- retval = 0;
+
+ return 0;
}
- exit:
- return retval;
+
+ retval = uart_startup(tty, state, true);
+ if (retval < 0)
+ return retval;
+ if (retval == 0)
+ tty_port_set_initialized(port, true);
+
+ return 0;
}
static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
@@ -1291,14 +1276,13 @@ static int uart_get_icount(struct tty_struct *tty,
struct uart_state *state = tty->driver_data;
struct uart_icount cnow;
struct uart_port *uport;
+ unsigned long flags;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
if (!uport)
return -EIO;
- uart_port_lock_irq(uport);
memcpy(&cnow, &uport->icount, sizeof(struct uart_icount));
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
icount->cts = cnow.cts;
icount->dsr = cnow.dsr;
@@ -1353,28 +1337,28 @@ static void uart_sanitize_serial_rs485_delays(struct uart_port *port,
if (!port->rs485_supported.delay_rts_before_send) {
if (rs485->delay_rts_before_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending not supported\n",
+ "%s (%u): RTS delay before sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_before_send = 0;
} else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay before sending clamped to %u ms\n",
+ "%s (%u): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_before_send);
}
if (!port->rs485_supported.delay_rts_after_send) {
if (rs485->delay_rts_after_send) {
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending not supported\n",
+ "%s (%u): RTS delay after sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_after_send = 0;
} else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
- "%s (%d): RTS delay after sending clamped to %u ms\n",
+ "%s (%u): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
}
@@ -1404,14 +1388,14 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_ON_SEND instead\n",
port->name, port->line);
} else {
rs485->flags |= SER_RS485_RTS_AFTER_SEND;
rs485->flags &= ~SER_RS485_RTS_ON_SEND;
dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_AFTER_SEND instead\n",
+ "%s (%u): invalid RTS setting, using RTS_AFTER_SEND instead\n",
port->name, port->line);
}
}
@@ -1850,7 +1834,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
expire = jiffies + timeout;
- pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
+ pr_debug("uart_wait_until_sent(%u), jiffies=%lu, expire=%lu...\n",
port->line, jiffies, expire);
/*
@@ -1930,9 +1914,10 @@ static bool uart_carrier_raised(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
+ unsigned long flags;
int mctrl;
- uport = uart_port_ref(state);
+ uport = uart_port_ref_lock(state, &flags);
/*
* Should never observe uport == NULL since checks for hangup should
* abort the tty_port_block_til_ready() loop before checking for carrier
@@ -1941,11 +1926,9 @@ static bool uart_carrier_raised(struct tty_port *port)
*/
if (WARN_ON(!uport))
return true;
- uart_port_lock_irq(uport);
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
- uart_port_deref(uport);
+ uart_port_unlock_deref(uport, flags);
return mctrl & TIOCM_CAR;
}
@@ -2029,9 +2012,8 @@ static const char *uart_type(struct uart_port *port)
#ifdef CONFIG_PROC_FS
-static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_state *state)
{
- struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
enum uart_pm_state pm_state;
struct uart_port *uport;
@@ -2046,7 +2028,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
return;
mmio = uport->iotype >= UPIO_MEM;
- seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
+ seq_printf(m, "%u: uart:%s %s%08llX irq:%u",
uport->line, uart_type(uport),
mmio ? "mmio:0x" : "port:",
mmio ? (unsigned long long)uport->mapbase
@@ -2068,18 +2050,18 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
- seq_printf(m, " tx:%d rx:%d",
+ seq_printf(m, " tx:%u rx:%u",
uport->icount.tx, uport->icount.rx);
if (uport->icount.frame)
- seq_printf(m, " fe:%d", uport->icount.frame);
+ seq_printf(m, " fe:%u", uport->icount.frame);
if (uport->icount.parity)
- seq_printf(m, " pe:%d", uport->icount.parity);
+ seq_printf(m, " pe:%u", uport->icount.parity);
if (uport->icount.brk)
- seq_printf(m, " brk:%d", uport->icount.brk);
+ seq_printf(m, " brk:%u", uport->icount.brk);
if (uport->icount.overrun)
- seq_printf(m, " oe:%d", uport->icount.overrun);
+ seq_printf(m, " oe:%u", uport->icount.overrun);
if (uport->icount.buf_overrun)
- seq_printf(m, " bo:%d", uport->icount.buf_overrun);
+ seq_printf(m, " bo:%u", uport->icount.buf_overrun);
#define INFOBIT(bit, str) \
if (uport->mctrl & (bit)) \
@@ -2116,7 +2098,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
- uart_line_info(m, drv, i);
+ uart_line_info(m, drv->state + i);
return 0;
}
#endif
@@ -2195,8 +2177,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
*
* Returns: 0 on success or -%EINVAL on failure
*/
-int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
- char **options)
+int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
+ resource_size_t *addr, char **options)
{
if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
@@ -2365,9 +2347,9 @@ struct uart_match {
struct uart_driver *driver;
};
-static int serial_match_port(struct device *dev, void *data)
+static int serial_match_port(struct device *dev, const void *data)
{
- struct uart_match *match = data;
+ const struct uart_match *match = data;
struct tty_driver *tty_drv = match->driver->tty_driver;
dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
match->port->line;
@@ -2442,10 +2424,10 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
/*
- * Disable the console device before suspending.
+ * Suspend the console device before suspending the port.
*/
if (uart_console(uport))
- console_stop(uport->cons);
+ console_suspend(uport->cons);
uart_change_pm(state, UART_PM_STATE_OFF);
@@ -2500,7 +2482,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_port_unlock_irq(uport);
}
if (console_suspend_enabled)
- console_start(uport->cons);
+ console_resume(uport->cons);
}
if (tty_port_suspended(port)) {
@@ -2571,7 +2553,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
break;
}
- pr_info("%s%s%s at %s (irq = %d, base_baud = %d) is a %s\n",
+ pr_info("%s%s%s at %s (irq = %u, base_baud = %u) is a %s\n",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2579,7 +2561,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
/* The magic multiplier feature is a bit obscure, so report it too. */
if (port->flags & UPF_MAGIC_MULTIPLIER)
- pr_info("%s%s%s extra baud rates supported: %d, %d",
+ pr_info("%s%s%s extra baud rates supported: %u, %u",
port->dev ? dev_name(port->dev) : "",
port->dev ? ": " : "",
port->name,
@@ -2978,7 +2960,7 @@ static ssize_t close_delay_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.close_delay);
+ return sprintf(buf, "%u\n", tmp.close_delay);
}
static ssize_t closing_wait_show(struct device *dev,
@@ -2988,7 +2970,7 @@ static ssize_t closing_wait_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.closing_wait);
+ return sprintf(buf, "%u\n", tmp.closing_wait);
}
static ssize_t custom_divisor_show(struct device *dev,
@@ -3008,7 +2990,7 @@ static ssize_t io_type_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.io_type);
+ return sprintf(buf, "%u\n", tmp.io_type);
}
static ssize_t iomem_base_show(struct device *dev,
@@ -3028,7 +3010,7 @@ static ssize_t iomem_reg_shift_show(struct device *dev,
struct tty_port *port = dev_get_drvdata(dev);
uart_get_info(port, &tmp);
- return sprintf(buf, "%d\n", tmp.iomem_reg_shift);
+ return sprintf(buf, "%u\n", tmp.iomem_reg_shift);
}
static ssize_t console_show(struct device *dev,
@@ -3061,26 +3043,25 @@ static ssize_t console_store(struct device *dev,
if (ret)
return ret;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
- if (uport) {
- oldconsole = uart_console_registered(uport);
- if (oldconsole && !newconsole) {
- ret = unregister_console(uport->cons);
- } else if (!oldconsole && newconsole) {
- if (uart_console(uport)) {
- uport->console_reinit = 1;
- register_console(uport->cons);
- } else {
- ret = -ENOENT;
- }
- }
- } else {
- ret = -ENXIO;
+ if (!uport)
+ return -ENXIO;
+
+ oldconsole = uart_console_registered(uport);
+ if (oldconsole && !newconsole) {
+ ret = unregister_console(uport->cons);
+ if (ret < 0)
+ return ret;
+ } else if (!oldconsole && newconsole) {
+ if (!uart_console(uport))
+ return -ENOENT;
+
+ uport->console_reinit = 1;
+ register_console(uport->cons);
}
- mutex_unlock(&port->mutex);
- return ret < 0 ? ret : count;
+ return count;
}
static DEVICE_ATTR_RO(uartclk);
@@ -3136,7 +3117,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
{
struct uart_state *state;
struct tty_port *port;
- int ret = 0;
struct device *tty_dev;
int num_groups;
@@ -3146,11 +3126,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state = drv->state + uport->line;
port = &state->port;
- mutex_lock(&port->mutex);
- if (state->uart_port) {
- ret = -EINVAL;
- goto out;
- }
+ guard(mutex)(&port->mutex);
+ if (state->uart_port)
+ return -EINVAL;
/* Link the port to the driver state table and vice versa */
atomic_set(&state->refcount, 1);
@@ -3168,17 +3146,14 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->pm_state = UART_PM_STATE_UNDEFINED;
uart_port_set_cons(uport, drv->cons);
uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
+ uport->name = kasprintf(GFP_KERNEL, "%s%u", drv->dev_name,
drv->tty_driver->name_base + uport->line);
- if (!uport->name) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!uport->name)
+ return -ENOMEM;
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
- tty_port_link_device(port, drv->tty_driver, uport->line);
uart_configure_port(drv, state, uport);
port->console = uart_console(uport);
@@ -3189,10 +3164,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
GFP_KERNEL);
- if (!uport->tty_groups) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!uport->tty_groups)
+ return -ENOMEM;
+
uport->tty_groups[0] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[1] = uport->attr_group;
@@ -3211,14 +3185,11 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
device_set_wakeup_capable(tty_dev, 1);
} else {
uport->flags |= UPF_DEAD;
- dev_err(uport->dev, "Cannot register tty device on line %d\n",
+ dev_err(uport->dev, "Cannot register tty device on line %u\n",
uport->line);
}
- out:
- mutex_unlock(&port->mutex);
-
- return ret;
+ return 0;
}
/**
@@ -3317,9 +3288,9 @@ bool uart_match_port(const struct uart_port *port1,
case UPIO_AU:
case UPIO_TSI:
return port1->mapbase == port2->mapbase;
+ default:
+ return false;
}
-
- return false;
}
EXPORT_SYMBOL(uart_match_port);
@@ -3384,7 +3355,7 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
struct serial_ctrl_device *ctrl_dev, *new_ctrl_dev = NULL;
int ret;
- mutex_lock(&port_mutex);
+ guard(mutex)(&port_mutex);
/*
* Prevent serial_port_runtime_resume() from trying to use the port
@@ -3396,10 +3367,8 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
ctrl_dev = serial_core_ctrl_find(drv, port->dev, port->ctrl_id);
if (!ctrl_dev) {
new_ctrl_dev = serial_core_ctrl_device_add(port);
- if (IS_ERR(new_ctrl_dev)) {
- ret = PTR_ERR(new_ctrl_dev);
- goto err_unlock;
- }
+ if (IS_ERR(new_ctrl_dev))
+ return PTR_ERR(new_ctrl_dev);
ctrl_dev = new_ctrl_dev;
}
@@ -3420,8 +3389,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
if (ret)
goto err_unregister_port_dev;
- mutex_unlock(&port_mutex);
-
return 0;
err_unregister_port_dev:
@@ -3430,9 +3397,6 @@ err_unregister_port_dev:
err_unregister_ctrl_dev:
serial_base_ctrl_device_remove(new_ctrl_dev);
-err_unlock:
- mutex_unlock(&port_mutex);
-
return ret;
}
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index 8855688a5b6c..7b02c5ca4afd 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -217,7 +217,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
*
* This will get the {cts,rts,...}-gpios from device tree if they are present
* and request them, set direction etc, and return an allocated structure.
- * `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
+ * `devm_*` functions are used, so there's no need to explicitly free.
* As this sets up the irq handling, make sure to not handle changes to the
* gpio input lines in your driver, too.
*/
@@ -268,32 +268,6 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
/**
- * mctrl_gpio_free - explicitly free uart gpios
- * @dev: uart port's device
- * @gpios: gpios structure to be freed
- *
- * This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
- * functions are used, there's generally no need to call this function.
- */
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
-{
- enum mctrl_gpio_idx i;
-
- if (gpios == NULL)
- return;
-
- for (i = 0; i < UART_GPIO_MAX; i++) {
- if (gpios->irq[i])
- devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
-
- if (gpios->gpio[i])
- devm_gpiod_put(dev, gpios->gpio[i]);
- }
- devm_kfree(dev, gpios);
-}
-EXPORT_SYMBOL_GPL(mctrl_gpio_free);
-
-/**
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
* @gpios: gpios to enable
*/
@@ -322,11 +296,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
}
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
-/**
- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
- * @gpios: gpios to disable
- */
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync)
{
enum mctrl_gpio_idx i;
@@ -342,10 +312,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
if (!gpios->irq[i])
continue;
- disable_irq(gpios->irq[i]);
+ if (sync)
+ disable_irq(gpios->irq[i]);
+ else
+ disable_irq_nosync(gpios->irq[i]);
}
}
-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+/**
+ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms
+ * lines, and wait for any pending IRQ to be processed
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, true);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync);
+
+/**
+ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the
+ * ms lines, and return immediately
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, false);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync);
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
{
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
index fc76910fb105..961e4ba0c6f8 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.h
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -59,7 +59,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
/*
* Request and set direction of modem control line GPIOs and set up irq
* handling.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -67,7 +67,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
/*
* Request and set direction of modem control line GPIOs.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -75,21 +75,21 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
unsigned int idx);
/*
- * Free the mctrl_gpios structure.
- * Normally, this function will not be called, as the GPIOs will
- * be disposed of by the resource management code.
+ * Enable gpio interrupts to report status line changes.
*/
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
/*
- * Enable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and block until
+ * any corresponding IRQ is processed
*/
-void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios);
/*
- * Disable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and return
+ * immediately
*/
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios);
/*
* Enable gpio wakeup interrupts to enable wake up source.
@@ -139,16 +139,15 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
return NULL;
}
-static inline
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
{
}
diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c
index 85285c56fabf..2fc48cd63f6c 100644
--- a/drivers/tty/serial/serial_port.c
+++ b/drivers/tty/serial/serial_port.c
@@ -229,14 +229,15 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
break;
default:
port->iotype = UPIO_UNKNOWN;
- if (!use_defaults) {
- dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
- return -EINVAL;
- }
break;
}
}
+ if (!use_defaults && port->iotype == UPIO_UNKNOWN) {
+ dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
+ return -EINVAL;
+ }
+
/* Read the address mapping base offset (default: no offset) */
ret = device_property_read_u32(dev, "reg-offset", &value);
if (ret)
diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h
new file mode 100644
index 000000000000..bd9d9cfac1c8
--- /dev/null
+++ b/drivers/tty/serial/sh-sci-common.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __SH_SCI_COMMON_H__
+#define __SH_SCI_COMMON_H__
+
+#include <linux/serial_core.h>
+
+enum SCI_CLKS {
+ SCI_FCK, /* Functional Clock */
+ SCI_SCK, /* Optional External Clock */
+ SCI_BRG_INT, /* Optional BRG Internal Clock Source */
+ SCI_SCIF_CLK, /* Optional BRG External Clock Source */
+ SCI_NUM_CLKS
+};
+
+/* Offsets into the sci_port->irqs array */
+enum {
+ SCIx_ERI_IRQ,
+ SCIx_RXI_IRQ,
+ SCIx_TXI_IRQ,
+ SCIx_BRI_IRQ,
+ SCIx_DRI_IRQ,
+ SCIx_TEI_IRQ,
+ SCIx_NR_IRQS,
+
+ SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
+};
+
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x) BIT((x) - 1)
+#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
+
+void sci_release_port(struct uart_port *port);
+int sci_request_port(struct uart_port *port);
+void sci_config_port(struct uart_port *port, int flags);
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser);
+void sci_pm(struct uart_port *port, unsigned int state,
+ unsigned int oldstate);
+
+struct plat_sci_reg {
+ u8 offset;
+ u8 size;
+};
+
+struct sci_port_params_bits {
+ unsigned int rxtx_enable;
+ unsigned int te_clear;
+ unsigned int poll_sent_bits;
+};
+
+struct sci_common_regs {
+ unsigned int status;
+ unsigned int control;
+};
+
+/* The actual number of needed registers. This is used by sci only */
+#define SCI_NR_REGS 20
+
+struct sci_port_params {
+ const struct plat_sci_reg regs[SCI_NR_REGS];
+ const struct sci_common_regs *common_regs;
+ const struct sci_port_params_bits *param_bits;
+ unsigned int fifosize;
+ unsigned int overrun_reg;
+ unsigned int overrun_mask;
+ unsigned int sampling_rate_mask;
+ unsigned int error_mask;
+ unsigned int error_clear;
+};
+
+struct sci_port_ops {
+ u32 (*read_reg)(struct uart_port *port, int reg);
+ void (*write_reg)(struct uart_port *port, int reg, int value);
+ void (*clear_SCxSR)(struct uart_port *port, unsigned int mask);
+
+ void (*transmit_chars)(struct uart_port *port);
+ void (*receive_chars)(struct uart_port *port);
+
+ void (*poll_put_char)(struct uart_port *port, unsigned char c);
+
+ int (*set_rtrg)(struct uart_port *port, int rx_trig);
+ int (*rtrg_enabled)(struct uart_port *port);
+
+ void (*shutdown_complete)(struct uart_port *port);
+
+ void (*prepare_console_write)(struct uart_port *port, u32 ctrl);
+ void (*console_save)(struct uart_port *port);
+ void (*console_restore)(struct uart_port *port);
+ size_t (*suspend_regs_size)(void);
+};
+
+struct sci_of_data {
+ const struct sci_port_params *params;
+ const struct uart_ops *uart_ops;
+ const struct sci_port_ops *ops;
+ unsigned short regtype;
+ unsigned short type;
+};
+
+struct sci_port {
+ struct uart_port port;
+
+ /* Platform configuration */
+ const struct sci_port_params *params;
+ const struct plat_sci_port *cfg;
+
+ unsigned int sampling_rate_mask;
+ resource_size_t reg_size;
+ struct mctrl_gpios *gpios;
+
+ /* Clocks */
+ struct clk *clks[SCI_NUM_CLKS];
+ unsigned long clk_rates[SCI_NUM_CLKS];
+
+ int irqs[SCIx_NR_IRQS];
+ char *irqstr[SCIx_NR_IRQS];
+
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+
+ struct reset_control *rstc;
+ struct sci_suspend_regs *suspend_regs;
+
+#ifdef CONFIG_SERIAL_SH_SCI_DMA
+ struct dma_chan *chan_tx_saved;
+ struct dma_chan *chan_rx_saved;
+ dma_cookie_t cookie_tx;
+ dma_cookie_t cookie_rx[2];
+ dma_cookie_t active_rx;
+ dma_addr_t tx_dma_addr;
+ unsigned int tx_dma_len;
+ struct scatterlist sg_rx[2];
+ void *rx_buf[2];
+ size_t buf_len_rx;
+ struct work_struct work_tx;
+ struct hrtimer rx_timer;
+ unsigned int rx_timeout; /* microseconds */
+#endif
+ unsigned int rx_frame;
+ int rx_trigger;
+ struct timer_list rx_fifo_timer;
+ int rx_fifo_timeout;
+ u16 hscif_tot;
+
+ const struct sci_port_ops *ops;
+
+ bool has_rtscts;
+ bool autorts;
+ bool tx_occurred;
+};
+
+#define to_sci_port(uart) container_of((uart), struct sci_port, port)
+
+void sci_port_disable(struct sci_port *sci_port);
+void sci_port_enable(struct sci_port *sci_port);
+
+int sci_startup(struct uart_port *port);
+void sci_shutdown(struct uart_port *port);
+
+#define min_sr(_port) ffs((_port)->sampling_rate_mask)
+#define max_sr(_port) fls((_port)->sampling_rate_mask)
+
+#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
+int __init scix_early_console_setup(struct earlycon_device *device, const struct sci_of_data *data);
+#endif
+
+#endif /* __SH_SCI_COMMON_H__ */
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 1a050ec9912c..1c356544a832 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -56,19 +56,7 @@
#include "serial_mctrl_gpio.h"
#include "sh-sci.h"
-
-/* Offsets into the sci_port->irqs array */
-enum {
- SCIx_ERI_IRQ,
- SCIx_RXI_IRQ,
- SCIx_TXI_IRQ,
- SCIx_BRI_IRQ,
- SCIx_DRI_IRQ,
- SCIx_TEI_IRQ,
- SCIx_NR_IRQS,
-
- SCIx_MUX_IRQ = SCIx_NR_IRQS, /* special case */
-};
+#include "sh-sci-common.h"
#define SCIx_IRQ_IS_MUXED(port) \
((port)->irqs[SCIx_ERI_IRQ] == \
@@ -76,90 +64,15 @@ enum {
((port)->irqs[SCIx_ERI_IRQ] && \
((port)->irqs[SCIx_RXI_IRQ] < 0))
-enum SCI_CLKS {
- SCI_FCK, /* Functional Clock */
- SCI_SCK, /* Optional External Clock */
- SCI_BRG_INT, /* Optional BRG Internal Clock Source */
- SCI_SCIF_CLK, /* Optional BRG External Clock Source */
- SCI_NUM_CLKS
-};
-
-/* Bit x set means sampling rate x + 1 is supported */
-#define SCI_SR(x) BIT((x) - 1)
-#define SCI_SR_RANGE(x, y) GENMASK((y) - 1, (x) - 1)
-
#define SCI_SR_SCIFAB SCI_SR(5) | SCI_SR(7) | SCI_SR(11) | \
SCI_SR(13) | SCI_SR(16) | SCI_SR(17) | \
SCI_SR(19) | SCI_SR(27)
-#define min_sr(_port) ffs((_port)->sampling_rate_mask)
-#define max_sr(_port) fls((_port)->sampling_rate_mask)
-
/* Iterate over all supported sampling rates, from high to low */
#define for_each_sr(_sr, _port) \
for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--) \
if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
-struct plat_sci_reg {
- u8 offset, size;
-};
-
-struct sci_port_params {
- const struct plat_sci_reg regs[SCIx_NR_REGS];
- unsigned int fifosize;
- unsigned int overrun_reg;
- unsigned int overrun_mask;
- unsigned int sampling_rate_mask;
- unsigned int error_mask;
- unsigned int error_clear;
-};
-
-struct sci_port {
- struct uart_port port;
-
- /* Platform configuration */
- const struct sci_port_params *params;
- const struct plat_sci_port *cfg;
- unsigned int sampling_rate_mask;
- resource_size_t reg_size;
- struct mctrl_gpios *gpios;
-
- /* Clocks */
- struct clk *clks[SCI_NUM_CLKS];
- unsigned long clk_rates[SCI_NUM_CLKS];
-
- int irqs[SCIx_NR_IRQS];
- char *irqstr[SCIx_NR_IRQS];
-
- struct dma_chan *chan_tx;
- struct dma_chan *chan_rx;
-
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
- struct dma_chan *chan_tx_saved;
- struct dma_chan *chan_rx_saved;
- dma_cookie_t cookie_tx;
- dma_cookie_t cookie_rx[2];
- dma_cookie_t active_rx;
- dma_addr_t tx_dma_addr;
- unsigned int tx_dma_len;
- struct scatterlist sg_rx[2];
- void *rx_buf[2];
- size_t buf_len_rx;
- struct work_struct work_tx;
- struct hrtimer rx_timer;
- unsigned int rx_timeout; /* microseconds */
-#endif
- unsigned int rx_frame;
- int rx_trigger;
- struct timer_list rx_fifo_timer;
- int rx_fifo_timeout;
- u16 hscif_tot;
-
- bool has_rtscts;
- bool autorts;
- bool tx_occurred;
-};
-
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
static struct sci_port sci_ports[SCI_NPORTS];
@@ -168,10 +81,40 @@ static struct uart_driver sci_uart_driver;
static bool sci_uart_earlycon;
static bool sci_uart_earlycon_dev_probing;
-static inline struct sci_port *
-to_sci_port(struct uart_port *uart)
+static const struct sci_port_params_bits sci_sci_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCI_TDRE | SCI_TEND
+};
+
+static const struct sci_port_params_bits sci_scif_port_params_bits = {
+ .rxtx_enable = SCSCR_RE | SCSCR_TE,
+ .te_clear = SCSCR_TE | SCSCR_TEIE,
+ .poll_sent_bits = SCIF_TDFE | SCIF_TEND
+};
+
+static const struct sci_common_regs sci_common_regs = {
+ .status = SCxSR,
+ .control = SCSCR,
+};
+
+struct sci_suspend_regs {
+ u16 scdl;
+ u16 sccks;
+ u16 scsmr;
+ u16 scscr;
+ u16 scfcr;
+ u16 scsptr;
+ u16 hssrr;
+ u16 scpcr;
+ u16 scpdr;
+ u8 scbrr;
+ u8 semr;
+};
+
+static size_t sci_suspend_regs_size(void)
{
- return container_of(uart, struct sci_port, port);
+ return sizeof(struct sci_suspend_regs);
}
static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
@@ -194,6 +137,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_sci_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -216,6 +161,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCI_DEFAULT_ERROR_MASK | SCI_ORER,
.error_clear = SCI_ERROR_CLEAR & ~SCI_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -240,6 +187,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -265,6 +214,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_SCIFAB,
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -290,10 +241,12 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
- * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T.
+ * The "SCIFA" that is in RZ/A2, RZ/G2L and RZ/T1.
* It looks like a normal SCIF with FIFO data, but with a
* compressed address space. Also, the break out of interrupts
* are different: ERI/BRI, RXI, TXI, TEI, DRI.
@@ -318,6 +271,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -349,6 +304,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -371,6 +328,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -395,6 +354,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -422,6 +383,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -451,6 +414,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR_RANGE(8, 32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -475,6 +440,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -502,6 +469,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(32),
.error_mask = SCIF_DEFAULT_ERROR_MASK,
.error_clear = SCIF_ERROR_CLEAR,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
/*
@@ -525,6 +494,8 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
.sampling_rate_mask = SCI_SR(16),
.error_mask = SCIF_DEFAULT_ERROR_MASK | SCIFA_ORER,
.error_clear = SCIF_ERROR_CLEAR & ~SCIFA_ORER,
+ .param_bits = &sci_scif_port_params_bits,
+ .common_regs = &sci_common_regs,
},
};
@@ -562,7 +533,7 @@ static void sci_serial_out(struct uart_port *p, int offset, int value)
WARN(1, "Invalid register access\n");
}
-static void sci_port_enable(struct sci_port *sci_port)
+void sci_port_enable(struct sci_port *sci_port)
{
unsigned int i;
@@ -578,7 +549,7 @@ static void sci_port_enable(struct sci_port *sci_port)
sci_port->port.uartclk = sci_port->clk_rates[SCI_FCK];
}
-static void sci_port_disable(struct sci_port *sci_port)
+void sci_port_disable(struct sci_port *sci_port)
{
unsigned int i;
@@ -718,12 +689,13 @@ static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask)
static int sci_poll_get_char(struct uart_port *port)
{
unsigned short status;
+ struct sci_port *s = to_sci_port(port);
int c;
do {
status = sci_serial_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
continue;
}
break;
@@ -736,7 +708,7 @@ static int sci_poll_get_char(struct uart_port *port)
/* Dummy read */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
return c;
}
@@ -744,14 +716,16 @@ static int sci_poll_get_char(struct uart_port *port)
static void sci_poll_put_char(struct uart_port *port, unsigned char c)
{
- unsigned short status;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status;
do {
- status = sci_serial_in(port, SCxSR);
+ status = s->ops->read_reg(port, regs->status);
} while (!(status & SCxSR_TDxE(port)));
sci_serial_out(port, SCxTDR, c);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port));
}
#endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE ||
CONFIG_SERIAL_SH_SCI_EARLYCON */
@@ -894,7 +868,7 @@ static void sci_transmit_chars(struct uart_port *port)
port->icount.tx++;
} while (--count > 0);
- sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -913,6 +887,7 @@ static void sci_transmit_chars(struct uart_port *port)
static void sci_receive_chars(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
+ struct sci_port *s = to_sci_port(port);
int i, count, copied = 0;
unsigned short status;
unsigned char flag;
@@ -967,7 +942,7 @@ static void sci_receive_chars(struct uart_port *port)
}
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
copied += count;
port->icount.rx += count;
@@ -980,16 +955,17 @@ static void sci_receive_chars(struct uart_port *port)
/* TTY buffers full; read from RX reg to prevent lockup */
sci_serial_in(port, SCxRDR);
sci_serial_in(port, SCxSR); /* dummy read */
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
}
static int sci_handle_errors(struct uart_port *port)
{
int copied = 0;
- unsigned short status = sci_serial_in(port, SCxSR);
- struct tty_port *tport = &port->state->port;
struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
+ unsigned int status = s->ops->read_reg(port, regs->status);
+ struct tty_port *tport = &port->state->port;
/* Handle overruns */
if (status & s->params->overrun_mask) {
@@ -1144,11 +1120,11 @@ static int scif_rtrg_enabled(struct uart_port *port)
static void rx_fifo_timer_fn(struct timer_list *t)
{
- struct sci_port *s = from_timer(s, t, rx_fifo_timer);
+ struct sci_port *s = timer_container_of(s, t, rx_fifo_timer);
struct uart_port *port = &s->port;
dev_dbg(port->dev, "Rx timed out\n");
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
}
static ssize_t rx_fifo_trigger_show(struct device *dev,
@@ -1173,9 +1149,9 @@ static ssize_t rx_fifo_trigger_store(struct device *dev,
if (ret)
return ret;
- sci->rx_trigger = scif_set_rtrg(port, r);
+ sci->rx_trigger = sci->ops->set_rtrg(port, r);
if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
return count;
}
@@ -1218,7 +1194,7 @@ static ssize_t rx_fifo_timeout_store(struct device *dev,
sci->hscif_tot = r << HSSCR_TOT_SHIFT;
} else {
sci->rx_fifo_timeout = r;
- scif_set_rtrg(port, 1);
+ sci->ops->set_rtrg(port, 1);
if (r > 0)
timer_setup(&sci->rx_fifo_timer, rx_fifo_timer_fn, 0);
}
@@ -1343,7 +1319,7 @@ static void sci_dma_rx_reenable_irq(struct sci_port *s)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
enable_irq(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
else
scr &= ~SCSCR_RDRQE;
}
@@ -1702,8 +1678,7 @@ static void sci_request_dma(struct uart_port *port)
dma += s->buf_len_rx;
}
- hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s->rx_timer.function = sci_dma_rx_timer_fn;
+ hrtimer_setup(&s->rx_timer, sci_dma_rx_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
s->chan_rx_saved = s->chan_rx = chan;
@@ -1782,7 +1757,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
disable_irq_nosync(s->irqs[SCIx_RXI_IRQ]);
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
scr |= SCSCR_RIE;
} else {
scr |= SCSCR_RDRQE;
@@ -1808,8 +1783,8 @@ handle_pio:
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) {
- if (!scif_rtrg_enabled(port))
- scif_set_rtrg(port, s->rx_trigger);
+ if (!s->ops->rtrg_enabled(port))
+ s->ops->set_rtrg(port, s->rx_trigger);
mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP(
s->rx_frame * HZ * s->rx_fifo_timeout, 1000000));
@@ -1819,7 +1794,7 @@ handle_pio:
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
return IRQ_HANDLED;
}
@@ -1828,9 +1803,10 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
unsigned long flags;
+ struct sci_port *s = to_sci_port(port);
uart_port_lock_irqsave(port, &flags);
- sci_transmit_chars(port);
+ s->ops->transmit_chars(port);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1839,16 +1815,18 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
+ const struct sci_common_regs *regs = s->params->common_regs;
unsigned long flags;
- unsigned short ctrl;
+ u32 ctrl;
if (port->type != PORT_SCI)
return sci_tx_interrupt(irq, ptr);
uart_port_lock_irqsave(port, &flags);
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~(SCSCR_TE | SCSCR_TEIE);
- sci_serial_out(port, SCSCR, ctrl);
+ ctrl = s->ops->read_reg(port, regs->control) &
+ ~(s->params->param_bits->te_clear);
+ s->ops->write_reg(port, regs->control, ctrl);
uart_port_unlock_irqrestore(port, flags);
return IRQ_HANDLED;
@@ -1857,6 +1835,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr)
static irqreturn_t sci_br_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ struct sci_port *s = to_sci_port(port);
/* Handle BREAKs */
sci_handle_breaks(port);
@@ -1864,7 +1843,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr)
/* drop invalid character received before break was detected */
sci_serial_in(port, SCxRDR);
- sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
}
@@ -1892,15 +1871,15 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr)
if (sci_handle_errors(port)) {
/* discard character in rx buffer */
sci_serial_in(port, SCxSR);
- sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
}
} else {
sci_handle_fifo_overrun(port);
if (!s->chan_rx)
- sci_receive_chars(port);
+ s->ops->receive_chars(port);
}
- sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
+ s->ops->clear_SCxSR(port, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
if (!s->chan_tx)
@@ -2270,7 +2249,17 @@ static void sci_break_ctl(struct uart_port *port, int break_state)
uart_port_unlock_irqrestore(port, flags);
}
-static int sci_startup(struct uart_port *port)
+static void sci_shutdown_complete(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ u16 scr;
+
+ scr = sci_serial_in(port, SCSCR);
+ sci_serial_out(port, SCSCR,
+ scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+}
+
+int sci_startup(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
int ret;
@@ -2289,27 +2278,20 @@ static int sci_startup(struct uart_port *port)
return 0;
}
-static void sci_shutdown(struct uart_port *port)
+void sci_shutdown(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
unsigned long flags;
- u16 scr;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
s->autorts = false;
- mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
uart_port_lock_irqsave(port, &flags);
sci_stop_rx(port);
sci_stop_tx(port);
- /*
- * Stop RX and TX, disable related interrupts, keep clock source
- * and HSCIF TOT bits
- */
- scr = sci_serial_in(port, SCSCR);
- sci_serial_out(port, SCSCR,
- scr & (SCSCR_CKE1 | SCSCR_CKE0 | s->hscif_tot));
+ s->ops->shutdown_complete(port);
uart_port_unlock_irqrestore(port, flags);
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -2321,7 +2303,7 @@ static void sci_shutdown(struct uart_port *port)
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0)
- del_timer_sync(&s->rx_fifo_timer);
+ timer_delete_sync(&s->rx_fifo_timer);
sci_free_irq(s);
sci_free_dma(port);
}
@@ -2386,8 +2368,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
/* calculate sample rate, BRR, and clock select */
static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
- unsigned int *brr, unsigned int *srr,
- unsigned int *cks)
+ unsigned int *brr, unsigned int *srr,
+ unsigned int *cks)
{
unsigned long freq = s->clk_rates[SCI_FCK];
unsigned int sr, br, prediv, scrate, c;
@@ -2464,9 +2446,9 @@ static void sci_reset(struct uart_port *port)
if (reg->size)
sci_serial_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
- sci_clear_SCxSR(port,
- SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
- SCxSR_BREAK_CLEAR(port));
+ s->ops->clear_SCxSR(port,
+ SCxSR_RDxF_CLEAR(port) & SCxSR_ERROR_CLEAR(port) &
+ SCxSR_BREAK_CLEAR(port));
if (sci_getreg(port, SCLSR)->size) {
status = sci_serial_in(port, SCLSR);
status &= ~(SCLSR_TO | SCLSR_ORER);
@@ -2475,14 +2457,14 @@ static void sci_reset(struct uart_port *port)
if (s->rx_trigger > 1) {
if (s->rx_fifo_timeout) {
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
timer_setup(&s->rx_fifo_timer, rx_fifo_timer_fn, 0);
} else {
if (port->type == PORT_SCIFA ||
port->type == PORT_SCIFB)
- scif_set_rtrg(port, 1);
+ s->ops->set_rtrg(port, 1);
else
- scif_set_rtrg(port, s->rx_trigger);
+ s->ops->set_rtrg(port, s->rx_trigger);
}
}
}
@@ -2742,7 +2724,7 @@ done:
sci_enable_ms(port);
}
-static void sci_pm(struct uart_port *port, unsigned int state,
+void sci_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sci_port *sci_port = to_sci_port(port);
@@ -2805,7 +2787,7 @@ static int sci_remap_port(struct uart_port *port)
return 0;
}
-static void sci_release_port(struct uart_port *port)
+void sci_release_port(struct uart_port *port)
{
struct sci_port *sport = to_sci_port(port);
@@ -2817,7 +2799,7 @@ static void sci_release_port(struct uart_port *port)
release_mem_region(port->mapbase, sport->reg_size);
}
-static int sci_request_port(struct uart_port *port)
+int sci_request_port(struct uart_port *port)
{
struct resource *res;
struct sci_port *sport = to_sci_port(port);
@@ -2839,7 +2821,7 @@ static int sci_request_port(struct uart_port *port)
return 0;
}
-static void sci_config_port(struct uart_port *port, int flags)
+void sci_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE) {
struct sci_port *sport = to_sci_port(port);
@@ -2849,7 +2831,7 @@ static void sci_config_port(struct uart_port *port, int flags)
}
}
-static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
+int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->baud_base < 2400)
/* No paper tape reader for Mitch.. */
@@ -2858,6 +2840,75 @@ static int sci_verify_port(struct uart_port *port, struct serial_struct *ser)
return 0;
}
+static void sci_prepare_console_write(struct uart_port *port, u32 ctrl)
+{
+ struct sci_port *s = to_sci_port(port);
+ u32 ctrl_temp =
+ s->params->param_bits->rxtx_enable |
+ (s->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
+ (ctrl & (SCSCR_CKE1 | SCSCR_CKE0)) |
+ s->hscif_tot;
+ sci_serial_out(port, SCSCR, ctrl_temp);
+}
+
+static void sci_console_save(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ regs->scdl = sci_serial_in(port, SCDL);
+ if (sci_getreg(port, SCCKS)->size)
+ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+ regs->scscr = sci_serial_in(port, SCSCR);
+ if (sci_getreg(port, SCFCR)->size)
+ regs->scfcr = sci_serial_in(port, SCFCR);
+ if (sci_getreg(port, SCSPTR)->size)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
+ if (sci_getreg(port, HSSRR)->size)
+ regs->hssrr = sci_serial_in(port, HSSRR);
+ if (sci_getreg(port, SCPCR)->size)
+ regs->scpcr = sci_serial_in(port, SCPCR);
+ if (sci_getreg(port, SCPDR)->size)
+ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+}
+
+static void sci_console_restore(struct uart_port *port)
+{
+ struct sci_port *s = to_sci_port(port);
+ struct sci_suspend_regs *regs = s->suspend_regs;
+
+ if (sci_getreg(port, SCDL)->size)
+ sci_serial_out(port, SCDL, regs->scdl);
+ if (sci_getreg(port, SCCKS)->size)
+ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+ sci_serial_out(port, SCSCR, regs->scscr);
+ if (sci_getreg(port, SCFCR)->size)
+ sci_serial_out(port, SCFCR, regs->scfcr);
+ if (sci_getreg(port, SCSPTR)->size)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
+ if (sci_getreg(port, HSSRR)->size)
+ sci_serial_out(port, HSSRR, regs->hssrr);
+ if (sci_getreg(port, SCPCR)->size)
+ sci_serial_out(port, SCPCR, regs->scpcr);
+ if (sci_getreg(port, SCPDR)->size)
+ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+}
+
static const struct uart_ops sci_uart_ops = {
.tx_empty = sci_tx_empty,
.set_mctrl = sci_set_mctrl,
@@ -2883,6 +2934,25 @@ static const struct uart_ops sci_uart_ops = {
#endif
};
+static const struct sci_port_ops sci_port_ops = {
+ .read_reg = sci_serial_in,
+ .write_reg = sci_serial_out,
+ .clear_SCxSR = sci_clear_SCxSR,
+ .transmit_chars = sci_transmit_chars,
+ .receive_chars = sci_receive_chars,
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
+ defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
+ .poll_put_char = sci_poll_put_char,
+#endif
+ .set_rtrg = scif_set_rtrg,
+ .rtrg_enabled = scif_rtrg_enabled,
+ .shutdown_complete = sci_shutdown_complete,
+ .prepare_console_write = sci_prepare_console_write,
+ .console_save = sci_console_save,
+ .console_restore = sci_console_restore,
+ .suspend_regs_size = sci_suspend_regs_size,
+};
+
static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
{
const char *clk_names[] = {
@@ -2926,10 +2996,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev)
}
static const struct sci_port_params *
-sci_probe_regmap(const struct plat_sci_port *cfg)
+sci_probe_regmap(const struct plat_sci_port *cfg, struct sci_port *sci_port)
{
unsigned int regtype;
+ sci_port->ops = &sci_port_ops;
+ sci_port->port.ops = &sci_uart_ops;
+
if (cfg->regtype != SCIx_PROBE_REGTYPE)
return &sci_port_params[cfg->regtype];
@@ -2977,7 +3050,6 @@ static int sci_init_single(struct platform_device *dev,
sci_port->cfg = p;
- port->ops = &sci_uart_ops;
port->iotype = UPIO_MEM;
port->line = index;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_SH_SCI_CONSOLE);
@@ -3017,10 +3089,6 @@ static int sci_init_single(struct platform_device *dev,
for (i = 1; i < ARRAY_SIZE(sci_port->irqs); i++)
sci_port->irqs[i] = sci_port->irqs[0];
- sci_port->params = sci_probe_regmap(p);
- if (unlikely(sci_port->params == NULL))
- return -EINVAL;
-
switch (p->type) {
case PORT_SCIFB:
sci_port->rx_trigger = 48;
@@ -3088,7 +3156,7 @@ static int sci_init_single(struct platform_device *dev,
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
{
- sci_poll_put_char(port, ch);
+ to_sci_port(port)->ops->poll_put_char(port, ch);
}
/*
@@ -3100,7 +3168,9 @@ static void serial_console_write(struct console *co, const char *s,
{
struct sci_port *sci_port = &sci_ports[co->index];
struct uart_port *port = &sci_port->port;
- unsigned short bits, ctrl, ctrl_temp;
+ const struct sci_common_regs *regs = sci_port->params->common_regs;
+ unsigned int bits;
+ u32 ctrl;
unsigned long flags;
int locked = 1;
@@ -3112,21 +3182,21 @@ static void serial_console_write(struct console *co, const char *s,
uart_port_lock_irqsave(port, &flags);
/* first save SCSCR then disable interrupts, keep clock source */
- ctrl = sci_serial_in(port, SCSCR);
- ctrl_temp = SCSCR_RE | SCSCR_TE |
- (sci_port->cfg->scscr & ~(SCSCR_CKE1 | SCSCR_CKE0)) |
- (ctrl & (SCSCR_CKE1 | SCSCR_CKE0));
- sci_serial_out(port, SCSCR, ctrl_temp | sci_port->hscif_tot);
+
+ ctrl = sci_port->ops->read_reg(port, regs->control);
+ sci_port->ops->prepare_console_write(port, ctrl);
uart_console_write(port, s, count, serial_console_putchar);
/* wait until fifo is empty and last bit has been transmitted */
- bits = SCxSR_TDxE(port) | SCxSR_TEND(port);
- while ((sci_serial_in(port, SCxSR) & bits) != bits)
+
+ bits = sci_port->params->param_bits->poll_sent_bits;
+
+ while ((sci_port->ops->read_reg(port, regs->status) & bits) != bits)
cpu_relax();
/* restore the SCSCR */
- sci_serial_out(port, SCSCR, ctrl);
+ sci_port->ops->write_reg(port, regs->control, ctrl);
if (locked)
uart_port_unlock_irqrestore(port, flags);
@@ -3204,13 +3274,18 @@ static struct console early_serial_console = {
static int sci_probe_earlyprintk(struct platform_device *pdev)
{
const struct plat_sci_port *cfg = dev_get_platdata(&pdev->dev);
+ struct sci_port *sp = &sci_ports[pdev->id];
if (early_serial_console.data)
return -EEXIST;
early_serial_console.index = pdev->id;
- sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true);
+ sp->params = sci_probe_regmap(cfg, sp);
+ if (!sp->params)
+ return -ENODEV;
+
+ sci_init_single(pdev, sp, pdev->id, cfg, true);
if (!strstr(early_serial_buf, "keep"))
early_serial_console.flags |= CON_BOOT;
@@ -3259,59 +3334,126 @@ static void sci_remove(struct platform_device *dev)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout);
}
+static const struct sci_of_data of_sci_scif_sh2 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH2_SCIF_FIFODATA_REGTYPE],
+};
-#define SCI_OF_DATA(type, regtype) (void *)((type) << 16 | (regtype))
-#define SCI_OF_TYPE(data) ((unsigned long)(data) >> 16)
-#define SCI_OF_REGTYPE(data) ((unsigned long)(data) & 0xffff)
+static const struct sci_of_data of_sci_scif_rz_scifa = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZ_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZ_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_rzv2h = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_RZV2H_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_RZV2H_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_rcar_scif = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_BRG_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_BRG_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scif_sh4 = {
+ .type = PORT_SCIF,
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SH4_SCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifa = {
+ .type = PORT_SCIFA,
+ .regtype = SCIx_SCIFA_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFA_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_scifb = {
+ .type = PORT_SCIFB,
+ .regtype = SCIx_SCIFB_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCIFB_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_hscif = {
+ .type = PORT_HSCIF,
+ .regtype = SCIx_HSCIF_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_HSCIF_REGTYPE],
+};
+
+static const struct sci_of_data of_sci_sci = {
+ .type = PORT_SCI,
+ .regtype = SCIx_SCI_REGTYPE,
+ .ops = &sci_port_ops,
+ .uart_ops = &sci_uart_ops,
+ .params = &sci_port_params[SCIx_SCI_REGTYPE],
+};
static const struct of_device_id of_sci_match[] __maybe_unused = {
/* SoC-specific types */
{
.compatible = "renesas,scif-r7s72100",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH2_SCIF_FIFODATA_REGTYPE),
+ .data = &of_sci_scif_sh2,
},
{
.compatible = "renesas,scif-r7s9210",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a07g044",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
+ .data = &of_sci_scif_rz_scifa,
},
{
.compatible = "renesas,scif-r9a09g057",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ .data = &of_sci_scif_rzv2h,
},
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen2-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif,
}, {
.compatible = "renesas,rcar-gen3-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
}, {
.compatible = "renesas,rcar-gen4-scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE),
+ .data = &of_sci_rcar_scif
},
/* Generic types */
{
.compatible = "renesas,scif",
- .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_REGTYPE),
+ .data = &of_sci_scif_sh4,
}, {
.compatible = "renesas,scifa",
- .data = SCI_OF_DATA(PORT_SCIFA, SCIx_SCIFA_REGTYPE),
+ .data = &of_sci_scifa,
}, {
.compatible = "renesas,scifb",
- .data = SCI_OF_DATA(PORT_SCIFB, SCIx_SCIFB_REGTYPE),
+ .data = &of_sci_scifb,
}, {
.compatible = "renesas,hscif",
- .data = SCI_OF_DATA(PORT_HSCIF, SCIx_HSCIF_REGTYPE),
+ .data = &of_sci_hscif,
}, {
.compatible = "renesas,sci",
- .data = SCI_OF_DATA(PORT_SCI, SCIx_SCI_REGTYPE),
+ .data = &of_sci_sci,
}, {
/* Terminator */
},
@@ -3330,7 +3472,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
struct reset_control *rstc;
struct plat_sci_port *p;
struct sci_port *sp;
- const void *data;
+ const struct sci_of_data *data;
int id, ret;
if (!IS_ENABLED(CONFIG_OF) || !np)
@@ -3374,10 +3516,15 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
}
sp = &sci_ports[id];
+ sp->rstc = rstc;
*dev_id = id;
- p->type = SCI_OF_TYPE(data);
- p->regtype = SCI_OF_REGTYPE(data);
+ p->type = data->type;
+ p->regtype = data->regtype;
+
+ sp->ops = data->ops;
+ sp->port.ops = data->uart_ops;
+ sp->params = data->params;
sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts");
@@ -3484,6 +3631,7 @@ static int sci_probe(struct platform_device *dev)
p = sci_parse_dt(dev, &dev_id);
if (IS_ERR(p))
return PTR_ERR(p);
+ sp = &sci_ports[dev_id];
} else {
p = dev->dev.platform_data;
if (p == NULL) {
@@ -3492,9 +3640,17 @@ static int sci_probe(struct platform_device *dev)
}
dev_id = dev->id;
+ sp = &sci_ports[dev_id];
+ sp->params = sci_probe_regmap(p, sp);
+ if (!sp->params)
+ return -ENODEV;
}
- sp = &sci_ports[dev_id];
+ sp->suspend_regs = devm_kzalloc(&dev->dev,
+ sp->ops->suspend_regs_size(),
+ GFP_KERNEL);
+ if (!sp->suspend_regs)
+ return -ENOMEM;
/*
* In case:
@@ -3550,9 +3706,17 @@ static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
uart_suspend_port(&sci_uart_driver, &sport->port);
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_save)
+ sport->ops->console_save(&sport->port);
+ }
+ else
+ return reset_control_assert(sport->rstc);
+ }
+
return 0;
}
@@ -3560,8 +3724,19 @@ static __maybe_unused int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ if (sport->ops->console_restore)
+ sport->ops->console_restore(&sport->port);
+ } else {
+ int ret = reset_control_deassert(sport->rstc);
+
+ if (ret)
+ return ret;
+ }
+
uart_resume_port(&sci_uart_driver, &sport->port);
+ }
return 0;
}
@@ -3616,21 +3791,31 @@ static int early_console_exit(struct console *co)
return 0;
}
-static int __init early_console_setup(struct earlycon_device *device,
- int type)
+int __init scix_early_console_setup(struct earlycon_device *device,
+ const struct sci_of_data *data)
{
+ const struct sci_common_regs *regs;
+
if (!device->port.membase)
return -ENODEV;
- device->port.type = type;
- memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
- port_cfg.type = type;
+ device->port.type = data->type;
+ sci_ports[0].port = device->port;
+
+ port_cfg.type = data->type;
+ port_cfg.regtype = data->regtype;
+
sci_ports[0].cfg = &port_cfg;
- sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_ports[0].params = data->params;
+ sci_ports[0].ops = data->ops;
+ sci_ports[0].port.ops = data->uart_ops;
sci_uart_earlycon = true;
- port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
- sci_serial_out(&sci_ports[0].port, SCSCR,
- SCSCR_RE | SCSCR_TE | port_cfg.scscr);
+ regs = sci_ports[0].params->common_regs;
+
+ port_cfg.scscr = sci_ports[0].ops->read_reg(&sci_ports[0].port, regs->control);
+ sci_ports[0].ops->write_reg(&sci_ports[0].port,
+ regs->control,
+ sci_ports[0].params->param_bits->rxtx_enable | port_cfg.scscr);
device->con->write = serial_console_write;
device->con->exit = early_console_exit;
@@ -3640,41 +3825,39 @@ static int __init early_console_setup(struct earlycon_device *device,
static int __init sci_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCI);
+ return scix_early_console_setup(device, &of_sci_sci);
}
static int __init scif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_sh4);
}
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rz_scifa);
}
static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
- return early_console_setup(device, PORT_SCIF);
+ return scix_early_console_setup(device, &of_sci_scif_rzv2h);
}
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFA);
+ return scix_early_console_setup(device, &of_sci_scifa);
}
static int __init scifb_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_SCIFB);
+ return scix_early_console_setup(device, &of_sci_scifb);
}
static int __init hscif_early_console_setup(struct earlycon_device *device,
const char *opt)
{
- return early_console_setup(device, PORT_HSCIF);
+ return scix_early_console_setup(device, &of_sci_hscif);
}
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h
index 0b65563c4e9e..951681aba586 100644
--- a/drivers/tty/serial/sh-sci.h
+++ b/drivers/tty/serial/sh-sci.h
@@ -32,8 +32,6 @@ enum {
HSRTRGR, /* Rx FIFO Data Count Trigger Register */
HSTTRGR, /* Tx FIFO Data Count Trigger Register */
SEMR, /* Serial extended mode register */
-
- SCIx_NR_REGS,
};
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 5904a2d4cefa..110d67613192 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -141,6 +141,7 @@
* @baud_rate: UART serial line rate (e.g., 115200 baud)
* @clk: reference to this device's clock
* @clk_notifier: clock rate change notifier for upstream clock changes
+ * @console_line_ended: indicate that the console line is fully written
*
* Configuration data specific to this SiFive UART.
*/
@@ -151,6 +152,7 @@ struct sifive_serial_port {
unsigned long baud_rate;
struct clk *clk;
struct notifier_block clk_notifier;
+ bool console_line_ended;
};
/*
@@ -563,8 +565,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state)
static int sifive_serial_startup(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_enable_rxwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
return 0;
}
@@ -572,9 +577,12 @@ static int sifive_serial_startup(struct uart_port *port)
static void sifive_serial_shutdown(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_disable_rxwm(ssp);
__ssp_disable_txwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
}
/**
@@ -779,33 +787,88 @@ static void sifive_serial_console_putchar(struct uart_port *port, unsigned char
__ssp_wait_for_xmitr(ssp);
__ssp_transmit_char(ssp, ch);
+
+ ssp->console_line_ended = (ch == '\n');
+}
+
+static void sifive_serial_device_lock(struct console *co, unsigned long *flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_lock_irqsave(up, flags);
}
-static void sifive_serial_console_write(struct console *co, const char *s,
- unsigned int count)
+static void sifive_serial_device_unlock(struct console *co, unsigned long flags)
+{
+ struct uart_port *up = &sifive_serial_console_ports[co->index]->port;
+
+ __uart_port_unlock_irqrestore(up, flags);
+}
+
+static void sifive_serial_console_write_atomic(struct console *co,
+ struct nbcon_write_context *wctxt)
{
struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
- unsigned long flags;
+ struct uart_port *port = &ssp->port;
unsigned int ier;
- int locked = 1;
if (!ssp)
return;
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&ssp->port, &flags);
- else
- uart_port_lock_irqsave(&ssp->port, &flags);
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
- uart_console_write(&ssp->port, s, count, sifive_serial_console_putchar);
+ if (!ssp->console_line_ended)
+ uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
+ uart_console_write(port, wctxt->outbuf, wctxt->len,
+ sifive_serial_console_putchar);
__ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
- if (locked)
- uart_port_unlock_irqrestore(&ssp->port, flags);
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void sifive_serial_console_write_thread(struct console *co,
+ struct nbcon_write_context *wctxt)
+{
+ struct sifive_serial_port *ssp = sifive_serial_console_ports[co->index];
+ struct uart_port *port = &ssp->port;
+ unsigned int ier;
+
+ if (!ssp)
+ return;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
+ __ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int len = READ_ONCE(wctxt->len);
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ uart_console_write(port, wctxt->outbuf + i, 1,
+ sifive_serial_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ __ssp_writel(ier, SIFIVE_SERIAL_IE_OFFS, ssp);
+
+ nbcon_exit_unsafe(wctxt);
}
static int sifive_serial_console_setup(struct console *co, char *options)
@@ -823,6 +886,8 @@ static int sifive_serial_console_setup(struct console *co, char *options)
if (!ssp)
return -ENODEV;
+ ssp->console_line_ended = true;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -833,10 +898,13 @@ static struct uart_driver sifive_serial_uart_driver;
static struct console sifive_serial_console = {
.name = SIFIVE_TTY_PREFIX,
- .write = sifive_serial_console_write,
+ .write_atomic = sifive_serial_console_write_atomic,
+ .write_thread = sifive_serial_console_write_thread,
+ .device_lock = sifive_serial_device_lock,
+ .device_unlock = sifive_serial_device_unlock,
.device = uart_console_device,
.setup = sifive_serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_NBCON,
.index = -1,
.data = &sifive_serial_uart_driver,
};
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 1ec5d8c3aef8..ad06b760cfca 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -944,7 +944,7 @@ static void stm32_usart_enable_ms(struct uart_port *port)
static void stm32_usart_disable_ms(struct uart_port *port)
{
- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios);
}
/* Transmit stop */
@@ -965,10 +965,8 @@ static void stm32_usart_start_tx(struct uart_port *port)
{
struct tty_port *tport = &port->state->port;
- if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char) {
- stm32_usart_rs485_rts_disable(port);
+ if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char)
return;
- }
stm32_usart_rs485_rts_enable(port);
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 7f0fef07e141..383141fe7ba0 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -151,16 +151,6 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value)
}
/*
- * We used to support using pause I/O for certain machines. We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset) serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-
-/*
* For the 16C950
*/
static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
@@ -169,20 +159,6 @@ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
serial_out(up, UART_ICR, value);
}
-#if 0 /* Unused currently */
-static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
-{
- unsigned int value;
-
- serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
- serial_out(up, UART_SCR, offset);
- value = serial_in(up, UART_ICR);
- serial_icr_write(up, UART_ACR, up->acr);
-
- return value;
-}
-#endif
-
#ifdef CONFIG_SERIAL_8250_RSA
/*
* Attempts to turn on the RSA FIFO. Returns zero on failure.
@@ -193,12 +169,12 @@ static int __enable_rsa(struct uart_sunsu_port *up)
unsigned char mode;
int result;
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
}
@@ -217,7 +193,7 @@ static void enable_rsa(struct uart_sunsu_port *up)
uart_port_unlock_irq(&up->port);
}
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
}
}
@@ -236,12 +212,12 @@ static void disable_rsa(struct uart_sunsu_port *up)
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
uart_port_lock_irq(&up->port);
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
}
@@ -326,7 +302,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
int saw_console_brk = 0;
do {
- ch = serial_inp(up, UART_RX);
+ ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
@@ -387,7 +363,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
*/
tty_insert_flip_char(port, 0, TTY_OVERRUN);
ignore_char:
- *status = serial_inp(up, UART_LSR);
+ *status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
if (saw_console_brk)
@@ -401,7 +377,7 @@ static void transmit_chars(struct uart_sunsu_port *up)
int count;
if (up->port.x_char) {
- serial_outp(up, UART_TX, up->port.x_char);
+ serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
up->port.x_char = 0;
return;
@@ -460,7 +436,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
uart_port_lock_irqsave(&up->port, &flags);
do {
- status = serial_inp(up, UART_LSR);
+ status = serial_in(up, UART_LSR);
if (status & UART_LSR_DR)
receive_chars(up, &status);
check_modem_status(up);
@@ -498,7 +474,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
{
do {
- unsigned char ch = serial_inp(up, UART_RX);
+ unsigned char ch = serial_in(up, UART_RX);
/* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) {
@@ -530,7 +506,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
struct uart_sunsu_port *up = dev_id;
if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
- unsigned char status = serial_inp(up, UART_LSR);
+ unsigned char status = serial_in(up, UART_LSR);
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
@@ -619,14 +595,14 @@ static int sunsu_startup(struct uart_port *port)
if (up->port.type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_IER, 0);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_IER, 0);
+ serial_out(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0);
}
#ifdef CONFIG_SERIAL_8250_RSA
@@ -642,19 +618,19 @@ static int sunsu_startup(struct uart_port *port)
* (they will be reenabled in set_termios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
}
/*
* Clear the interrupt registers.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
/*
* At this point, there's no way the LSR could still be 0xff;
@@ -662,7 +638,7 @@ static int sunsu_startup(struct uart_port *port)
* here.
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
- (serial_inp(up, UART_LSR) == 0xff)) {
+ (serial_in(up, UART_LSR) == 0xff)) {
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
return -ENODEV;
}
@@ -682,7 +658,7 @@ static int sunsu_startup(struct uart_port *port)
/*
* Now, initialize the UART
*/
- serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+ serial_out(up, UART_LCR, UART_LCR_WLEN8);
uart_port_lock_irqsave(&up->port, &flags);
@@ -697,7 +673,7 @@ static int sunsu_startup(struct uart_port *port)
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
- serial_outp(up, UART_IER, up->ier);
+ serial_out(up, UART_IER, up->ier);
if (up->port.flags & UPF_FOURPORT) {
unsigned int icp;
@@ -712,10 +688,10 @@ static int sunsu_startup(struct uart_port *port)
/*
* And clear the interrupt registers again for luck.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
return 0;
}
@@ -730,7 +706,7 @@ static void sunsu_shutdown(struct uart_port *port)
* Disable interrupts from this port
*/
up->ier = 0;
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
uart_port_lock_irqsave(&up->port, &flags);
if (up->port.flags & UPF_FOURPORT) {
@@ -746,11 +722,11 @@ static void sunsu_shutdown(struct uart_port *port)
/*
* Disable break condition and FIFOs
*/
- serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
#ifdef CONFIG_SERIAL_8250_RSA
/*
@@ -872,22 +848,22 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) {
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
}
- serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
if (up->port.type == PORT_16750)
- serial_outp(up, UART_FCR, fcr); /* set fcr */
- serial_outp(up, UART_LCR, cval); /* reset DLAB */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
if (up->port.type != PORT_16750) {
if (fcr & UART_FCR_ENABLE_FIFO) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
}
up->cflag = cflag;
@@ -1051,18 +1027,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* 0x80 is a non-existent port; which should be safe since
* include/asm/io.h also makes this assumption.
*/
- scratch = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0);
+ scratch = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
#ifdef __i386__
outb(0xff, 0x080);
#endif
- scratch2 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0x0f);
+ scratch2 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0x0f);
#ifdef __i386__
outb(0, 0x080);
#endif
- scratch3 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, scratch);
+ scratch3 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, scratch);
if (scratch2 != 0 || scratch3 != 0x0F)
goto out; /* We failed; there's nothing here */
}
@@ -1080,16 +1056,16 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* that conflicts with COM 1-4 --- we hope!
*/
if (!(up->port.flags & UPF_SKIP_TEST)) {
- serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(up, UART_MSR) & 0xF0;
- serial_outp(up, UART_MCR, save_mcr);
+ serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_in(up, UART_MSR) & 0xF0;
+ serial_out(up, UART_MCR, save_mcr);
if (status1 != 0x90)
goto out; /* We failed loopback test */
}
- serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */
- serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0xBF); /* set up for StarTech test */
+ serial_out(up, UART_EFR, 0); /* EFR is the same as FCR */
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(up, UART_IIR) >> 6;
switch (scratch) {
case 0:
@@ -1107,19 +1083,19 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
}
if (up->port.type == PORT_16550A) {
/* Check for Startech UART's */
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
if (serial_in(up, UART_EFR) == 0) {
up->port.type = PORT_16650;
} else {
- serial_outp(up, UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
if (serial_in(up, UART_EFR) == 0)
up->port.type = PORT_16650V2;
}
}
if (up->port.type == PORT_16550A) {
/* Check for TI 16750 */
- serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 7) {
@@ -1129,24 +1105,24 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* mode if the UART_FCR7_64BYTE bit was set
* while UART_LCR_DLAB was latched.
*/
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 6)
up->port.type = PORT_16750;
}
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_LCR, save_lcr);
+ serial_out(up, UART_LCR, save_lcr);
if (up->port.type == PORT_16450) {
scratch = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0xa5);
+ serial_out(up, UART_SCR, 0xa5);
status1 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0x5a);
+ serial_out(up, UART_SCR, 0x5a);
status2 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, scratch);
+ serial_out(up, UART_SCR, scratch);
if ((status1 != 0xa5) || (status2 != 0x5a))
up->port.type = PORT_8250;
@@ -1163,15 +1139,15 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
#ifdef CONFIG_SERIAL_8250_RSA
if (up->port.type == PORT_RSA)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
#endif
- serial_outp(up, UART_MCR, save_mcr);
- serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_MCR, save_mcr);
+ serial_out(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
(void)serial_in(up, UART_RX);
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
out:
uart_port_unlock_irqrestore(&up->port, flags);
diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c
new file mode 100644
index 000000000000..0c70d3e7b9b9
--- /dev/null
+++ b/drivers/tty/serial/tegra-utc.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// NVIDIA Tegra UTC (UART Trace Controller) driver.
+
+#include <linux/bits.h>
+#include <linux/console.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+
+#define TEGRA_UTC_ENABLE 0x000
+#define TEGRA_UTC_ENABLE_CLIENT_ENABLE BIT(0)
+
+#define TEGRA_UTC_FIFO_THRESHOLD 0x008
+
+#define TEGRA_UTC_COMMAND 0x00c
+#define TEGRA_UTC_COMMAND_RESET BIT(0)
+#define TEGRA_UTC_COMMAND_FLUSH BIT(1)
+
+#define TEGRA_UTC_DATA 0x020
+
+#define TEGRA_UTC_FIFO_STATUS 0x100
+#define TEGRA_UTC_FIFO_EMPTY BIT(0)
+#define TEGRA_UTC_FIFO_FULL BIT(1)
+#define TEGRA_UTC_FIFO_REQ BIT(2)
+#define TEGRA_UTC_FIFO_OVERFLOW BIT(3)
+#define TEGRA_UTC_FIFO_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_FIFO_OCCUPANCY 0x104
+
+#define TEGRA_UTC_INTR_STATUS 0x108
+#define TEGRA_UTC_INTR_SET 0x10c
+#define TEGRA_UTC_INTR_MASK 0x110
+#define TEGRA_UTC_INTR_CLEAR 0x114
+#define TEGRA_UTC_INTR_EMPTY BIT(0)
+#define TEGRA_UTC_INTR_FULL BIT(1)
+#define TEGRA_UTC_INTR_REQ BIT(2)
+#define TEGRA_UTC_INTR_OVERFLOW BIT(3)
+#define TEGRA_UTC_INTR_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_UART_NR 16
+
+#define TEGRA_UTC_INTR_COMMON (TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY)
+
+struct tegra_utc_port {
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ struct console console;
+#endif
+ struct uart_port port;
+
+ void __iomem *rx_base;
+ void __iomem *tx_base;
+
+ u32 tx_irqmask;
+ u32 rx_irqmask;
+
+ unsigned int fifosize;
+ u32 tx_threshold;
+ u32 rx_threshold;
+};
+
+static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = TEGRA_UTC_INTR_REQ;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = 0x0;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_stop_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_disable_tx_irq(tup);
+}
+
+static void tegra_utc_init_tx(struct tegra_utc_port *tup)
+{
+ /* Disable TX. */
+ tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+
+ /* Update the FIFO Threshold. */
+ tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_disable_tx_irq(tup);
+
+ /* Enable TX. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static void tegra_utc_init_rx(struct tegra_utc_port *tup)
+{
+ tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT;
+
+ tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND);
+ tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear all the pending interrupts. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW |
+ TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+
+ /* Enable RX. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static bool tegra_utc_tx_chars(struct tegra_utc_port *tup)
+{
+ struct uart_port *port = &tup->port;
+ unsigned int pending;
+ u8 c;
+
+ pending = uart_port_tx(port, c,
+ !(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL),
+ tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA));
+
+ return pending;
+}
+
+static void tegra_utc_rx_chars(struct tegra_utc_port *tup)
+{
+ struct tty_port *port = &tup->port.state->port;
+ unsigned int max_chars = 256;
+ u32 status;
+ int sysrq;
+ u32 ch;
+
+ while (max_chars--) {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS);
+ if (status & TEGRA_UTC_FIFO_EMPTY)
+ break;
+
+ ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+ tup->port.icount.rx++;
+
+ if (status & TEGRA_UTC_FIFO_OVERFLOW)
+ tup->port.icount.overrun++;
+
+ uart_port_unlock(&tup->port);
+ sysrq = uart_handle_sysrq_char(&tup->port, ch);
+ uart_port_lock(&tup->port);
+
+ if (!sysrq)
+ tty_insert_flip_char(port, ch, TTY_NORMAL);
+ }
+
+ tty_flip_buffer_push(port);
+}
+
+static irqreturn_t tegra_utc_isr(int irq, void *dev_id)
+{
+ struct tegra_utc_port *tup = dev_id;
+ unsigned int handled = 0;
+ u32 status;
+
+ uart_port_lock(&tup->port);
+
+ /* Process RX_REQ and RX_TIMEOUT interrupts. */
+ do {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask;
+ if (status) {
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ /* Process TX_REQ interrupt. */
+ do {
+ status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask;
+ if (status) {
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_tx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ uart_port_unlock(&tup->port);
+
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int tegra_utc_tx_empty(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT;
+}
+
+static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_utc_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static void tegra_utc_start_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_tx_chars(tup))
+ tegra_utc_enable_tx_irq(tup);
+}
+
+static void tegra_utc_stop_rx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tup->rx_irqmask = 0x0;
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_hw_init(struct tegra_utc_port *tup)
+{
+ tegra_utc_init_tx(tup);
+ tegra_utc_init_rx(tup);
+}
+
+static int tegra_utc_startup(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ int ret;
+
+ tegra_utc_hw_init(tup);
+
+ /* Interrupt is dedicated to this UTC client. */
+ ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup);
+ if (ret < 0)
+ dev_err(port->dev, "failed to register interrupt handler\n");
+
+ return ret;
+}
+
+static void tegra_utc_shutdown(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+ free_irq(port->irq, tup);
+}
+
+static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ /* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+ termios->c_cflag |= CS8 | CLOCAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int tegra_utc_poll_init(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_hw_init(tup);
+ return 0;
+}
+
+static int tegra_utc_get_poll_char(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY)
+ return NO_POLL_CHAR;
+
+ return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ u32 val;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+#endif
+
+static const struct uart_ops tegra_utc_uart_ops = {
+ .tx_empty = tegra_utc_tx_empty,
+ .set_mctrl = tegra_utc_set_mctrl,
+ .get_mctrl = tegra_utc_get_mctrl,
+ .stop_tx = tegra_utc_stop_tx,
+ .start_tx = tegra_utc_start_tx,
+ .stop_rx = tegra_utc_stop_rx,
+ .startup = tegra_utc_startup,
+ .shutdown = tegra_utc_shutdown,
+ .set_termios = tegra_utc_set_termios,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = tegra_utc_poll_init,
+ .poll_get_char = tegra_utc_get_poll_char,
+ .poll_put_char = tegra_utc_put_poll_char,
+#endif
+};
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD 4
+#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE 128
+
+static void tegra_utc_putc(struct uart_port *port, unsigned char c)
+{
+ writel(c, port->membase + TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n)
+{
+ struct earlycon_device *dev = con->data;
+
+ while (n) {
+ u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE;
+
+ burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY);
+ if (n < burst_size)
+ burst_size = n;
+
+ uart_console_write(&dev->port, s, burst_size, tegra_utc_putc);
+
+ n -= burst_size;
+ s += burst_size;
+ }
+}
+
+static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ /* Configure TX */
+ writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET,
+ device->port.membase + TEGRA_UTC_COMMAND);
+ writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR);
+
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK);
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET);
+
+ /* Enable TX. */
+ writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE);
+
+ device->con->write = tegra_utc_early_write;
+
+ return 0;
+}
+OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup);
+
+static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len;
+ char *outbuf;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ outbuf = wctxt->outbuf;
+ len = wctxt->len;
+
+ while (len) {
+ u32 burst_size = tup->fifosize;
+
+ burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY);
+ if (len < burst_size)
+ burst_size = len;
+
+ uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar);
+
+ outbuf += burst_size;
+ len -= burst_size;
+ }
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len = READ_ONCE(wctxt->len);
+ unsigned int i;
+ u32 val;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+ uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+}
+
+static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_lock_irqsave(port, flags);
+}
+
+static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_unlock_irqrestore(port, flags);
+}
+
+static int tegra_utc_console_setup(struct console *cons, char *options)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+
+ tegra_utc_init_tx(tup);
+
+ return 0;
+}
+#endif
+
+static struct uart_driver tegra_utc_driver = {
+ .driver_name = "tegra-utc",
+ .dev_name = "ttyUTC",
+ .nr = TEGRA_UTC_UART_NR,
+};
+
+static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup)
+{
+ tup->port.dev = dev;
+ tup->port.fifosize = tup->fifosize;
+ tup->port.flags = UPF_BOOT_AUTOCONF;
+ tup->port.iotype = UPIO_MEM;
+ tup->port.ops = &tegra_utc_uart_ops;
+ tup->port.type = PORT_TEGRA_TCU;
+ tup->port.private_data = tup;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name));
+ tup->console.write_atomic = tegra_utc_console_write_atomic;
+ tup->console.write_thread = tegra_utc_console_write_thread;
+ tup->console.device_lock = tegra_utc_console_device_lock;
+ tup->console.device_unlock = tegra_utc_console_device_unlock;
+ tup->console.device = uart_console_device;
+ tup->console.setup = tegra_utc_console_setup;
+ tup->console.flags = CON_PRINTBUFFER | CON_NBCON;
+ tup->console.data = &tegra_utc_driver;
+#endif
+
+ return uart_read_port_properties(&tup->port);
+}
+
+static int tegra_utc_register_port(struct tegra_utc_port *tup)
+{
+ int ret;
+
+ ret = uart_add_one_port(&tegra_utc_driver, &tup->port);
+ if (ret)
+ return ret;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ register_console(&tup->console);
+#endif
+
+ return 0;
+}
+
+static int tegra_utc_probe(struct platform_device *pdev)
+{
+ const unsigned int *soc_fifosize;
+ struct device *dev = &pdev->dev;
+ struct tegra_utc_port *tup;
+ int ret;
+
+ tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL);
+ if (!tup)
+ return -ENOMEM;
+
+ ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold");
+
+ ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold");
+
+ soc_fifosize = device_get_match_data(dev);
+ tup->fifosize = *soc_fifosize;
+
+ tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
+ if (IS_ERR(tup->tx_base))
+ return PTR_ERR(tup->tx_base);
+
+ tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
+ if (IS_ERR(tup->rx_base))
+ return PTR_ERR(tup->rx_base);
+
+ ret = tegra_utc_setup_port(dev, tup);
+ if (ret)
+ dev_err_probe(dev, ret, "failed to setup uart port\n");
+
+ platform_set_drvdata(pdev, tup);
+
+ return tegra_utc_register_port(tup);
+}
+
+static void tegra_utc_remove(struct platform_device *pdev)
+{
+ struct tegra_utc_port *tup = platform_get_drvdata(pdev);
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ unregister_console(&tup->console);
+#endif
+ uart_remove_one_port(&tegra_utc_driver, &tup->port);
+}
+
+static const unsigned int tegra264_utc_soc = 128;
+
+static const struct of_device_id tegra_utc_of_match[] = {
+ { .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_utc_of_match);
+
+static struct platform_driver tegra_utc_platform_driver = {
+ .probe = tegra_utc_probe,
+ .remove = tegra_utc_remove,
+ .driver = {
+ .name = "tegra-utc",
+ .of_match_table = tegra_utc_of_match,
+ },
+};
+
+static int __init tegra_utc_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&tegra_utc_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&tegra_utc_platform_driver);
+ if (ret)
+ uart_unregister_driver(&tegra_utc_driver);
+
+ return ret;
+}
+module_init(tegra_utc_init);
+
+static void __exit tegra_utc_exit(void)
+{
+ platform_driver_unregister(&tegra_utc_platform_driver);
+ uart_unregister_driver(&tegra_utc_driver);
+}
+module_exit(tegra_utc_exit);
+
+MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
+MODULE_DESCRIPTION("Tegra UART Trace Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index a41e7fc373b7..39c1fd1ff9ce 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -880,16 +880,6 @@ of_err:
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
- if (!ulite_uart_driver.state) {
- dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
- ret = uart_register_driver(&ulite_uart_driver);
- if (ret < 0) {
- dev_err(&pdev->dev, "Failed to register driver\n");
- clk_disable_unprepare(pdata->clk);
- return ret;
- }
- }
-
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
pm_runtime_mark_last_busy(&pdev->dev);
@@ -929,16 +919,25 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
+ int ret;
+
+ pr_debug("uartlite: calling uart_register_driver()\n");
+ ret = uart_register_driver(&ulite_uart_driver);
+ if (ret)
+ return ret;
pr_debug("uartlite: calling platform_driver_register()\n");
- return platform_driver_register(&ulite_platform_driver);
+ ret = platform_driver_register(&ulite_platform_driver);
+ if (ret)
+ uart_unregister_driver(&ulite_uart_driver);
+
+ return ret;
}
static void __exit ulite_exit(void)
{
platform_driver_unregister(&ulite_platform_driver);
- if (ulite_uart_driver.state)
- uart_unregister_driver(&ulite_uart_driver);
+ uart_unregister_driver(&ulite_uart_driver);
}
module_init(ulite_init);
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 92ec51870d1d..fe457bf1e15b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -454,7 +454,7 @@ static void cdns_uart_handle_tx(void *dev_id)
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
- cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback);
hrtimer_start(&cdns_uart->tx_timer,
ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
}
@@ -734,7 +734,7 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
if (!cdns_uart->rs485_tx_started) {
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_tx_callback);
cdns_rs485_tx_setup(cdns_uart);
return hrtimer_start(&cdns_uart->tx_timer,
ms_to_ktime(port->rs485.delay_rts_before_send),
@@ -1626,8 +1626,8 @@ static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
writel(val, port->membase + CDNS_UART_MODEMCR);
/* Timer setup */
- hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_setup(&cdns_uart->tx_timer, &cdns_rs485_tx_callback, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/* Disable transmitter and make Rx setup*/
cdns_uart_stop_tx(port);