Merge tag 'tty-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial updates from Greg KH: "Here is the big set of TTY / Serial patches for 5.7-rc1 Lots of console fixups and reworking in here, serial core tweaks (doesn't that ever get old, why are we still creating new serial devices?), serial driver updates, line-protocol driver updates, and some vt cleanups and fixes included in here as well. All have been in linux-next with no reported issues" * tag 'tty-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (161 commits) serial: 8250: Optimize irq enable after console write serial: 8250: Fix rs485 delay after console write vt: vt_ioctl: fix use-after-free in vt_in_use() vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console tty: serial: make SERIAL_SPRD depend on COMMON_CLK tty: serial: fsl_lpuart: fix return value checking tty: serial: fsl_lpuart: move dma_request_chan() ARM: dts: tango4: Make /serial compatible with ns16550a ARM: dts: mmp*: Make the serial ports compatible with xscale-uart ARM: dts: mmp*: Fix serial port names ARM: dts: mmp2-brownstone: Don't redeclare phandle references ARM: dts: pxa*: Make the serial ports compatible with xscale-uart ARM: dts: pxa*: Fix serial port names ARM: dts: pxa*: Don't redeclare phandle references serial: omap: drop unused dt-bindings header serial: 8250: 8250_omap: Add DMA support for UARTs on K3 SoCs serial: 8250: 8250_omap: Work around errata causing spurious IRQs with DMA serial: 8250: 8250_omap: Extend driver data to pass FIFO trigger info serial: 8250: 8250_omap: Move locking out from __dma_rx_do_complete() serial: 8250: 8250_omap: Account for data in flight during DMA teardown ...
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Driver for 8250/16550-type serial ports
|
||||
*
|
||||
@@ -156,7 +156,9 @@ 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_init(struct uart_8250_port *p);
|
||||
int serial8250_em485_config(struct uart_port *port, 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_destroy(struct uart_8250_port *p);
|
||||
|
||||
/* MCR <-> TIOCM conversion */
|
||||
|
@@ -6,6 +6,10 @@
|
||||
*
|
||||
* Based on 8250_lpc18xx.c:
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
|
||||
* take advantage of it yet. When adding support, be sure not to enable it
|
||||
* simultaneously to rs485.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -16,16 +20,64 @@
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define BCM2835_AUX_UART_CNTL 8
|
||||
#define BCM2835_AUX_UART_CNTL_RXEN 0x01 /* Receiver enable */
|
||||
#define BCM2835_AUX_UART_CNTL_TXEN 0x02 /* Transmitter enable */
|
||||
#define BCM2835_AUX_UART_CNTL_AUTORTS 0x04 /* RTS set by RX fill level */
|
||||
#define BCM2835_AUX_UART_CNTL_AUTOCTS 0x08 /* CTS stops transmitter */
|
||||
#define BCM2835_AUX_UART_CNTL_RTS3 0x00 /* RTS set until 3 chars left */
|
||||
#define BCM2835_AUX_UART_CNTL_RTS2 0x10 /* RTS set until 2 chars left */
|
||||
#define BCM2835_AUX_UART_CNTL_RTS1 0x20 /* RTS set until 1 chars left */
|
||||
#define BCM2835_AUX_UART_CNTL_RTS4 0x30 /* RTS set until 4 chars left */
|
||||
#define BCM2835_AUX_UART_CNTL_RTSINV 0x40 /* Invert auto RTS polarity */
|
||||
#define BCM2835_AUX_UART_CNTL_CTSINV 0x80 /* Invert auto CTS polarity */
|
||||
|
||||
/**
|
||||
* struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
|
||||
* @clk: clock producer of the port's uartclk
|
||||
* @line: index of the port's serial8250_ports[] entry
|
||||
* @cntl: cached copy of CNTL register
|
||||
*/
|
||||
struct bcm2835aux_data {
|
||||
struct clk *clk;
|
||||
int line;
|
||||
u32 cntl;
|
||||
};
|
||||
|
||||
static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
|
||||
{
|
||||
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
|
||||
|
||||
data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN;
|
||||
serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
|
||||
}
|
||||
|
||||
/*
|
||||
* On the bcm2835aux, the MCR register contains no other
|
||||
* flags besides RTS. So no need for a read-modify-write.
|
||||
*/
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
serial8250_out_MCR(up, 0);
|
||||
else
|
||||
serial8250_out_MCR(up, UART_MCR_RTS);
|
||||
}
|
||||
|
||||
static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
|
||||
{
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
serial8250_out_MCR(up, 0);
|
||||
else
|
||||
serial8250_out_MCR(up, UART_MCR_RTS);
|
||||
|
||||
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
|
||||
struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
|
||||
|
||||
data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
|
||||
serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
|
||||
}
|
||||
}
|
||||
|
||||
static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port up = { };
|
||||
@@ -47,6 +99,14 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
up.port.fifosize = 8;
|
||||
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
|
||||
UPF_SKIP_TEST | UPF_IOREMAP;
|
||||
up.port.rs485_config = serial8250_em485_config;
|
||||
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
|
||||
up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
|
||||
|
||||
/* initialize cached copy with power-on reset value */
|
||||
data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
/* get the clock - this also enables the HW */
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
@@ -102,8 +162,6 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
}
|
||||
data->line = ret;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
return 0;
|
||||
|
||||
dis_clk:
|
||||
@@ -137,6 +195,24 @@ static struct platform_driver bcm2835aux_serial_driver = {
|
||||
};
|
||||
module_platform_driver(bcm2835aux_serial_driver);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
|
||||
static int __init early_bcm2835aux_setup(struct earlycon_device *device,
|
||||
const char *options)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.iotype = UPIO_MEM32;
|
||||
device->port.regshift = 2;
|
||||
|
||||
return early_serial8250_setup(device, NULL);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(bcm2835aux, "brcm,bcm2835-aux-uart",
|
||||
early_bcm2835aux_setup);
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("BCM2835 auxiliar UART driver");
|
||||
MODULE_AUTHOR("Martin Sperl <kernel@martin.sperl.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@@ -608,6 +608,14 @@ static int univ8250_console_setup(struct console *co, char *options)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int univ8250_console_exit(struct console *co)
|
||||
{
|
||||
struct uart_port *port;
|
||||
|
||||
port = &serial8250_ports[co->index].port;
|
||||
return serial8250_console_exit(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* univ8250_console_match - non-standard console matching
|
||||
* @co: registering console
|
||||
@@ -666,6 +674,7 @@ static struct console univ8250_console = {
|
||||
.write = univ8250_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = univ8250_console_setup,
|
||||
.exit = univ8250_console_exit,
|
||||
.match = univ8250_console_match,
|
||||
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
||||
.index = -1,
|
||||
@@ -1007,14 +1016,18 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
uart->port.unthrottle = up->port.unthrottle;
|
||||
uart->port.rs485_config = up->port.rs485_config;
|
||||
uart->port.rs485 = up->port.rs485;
|
||||
uart->rs485_start_tx = up->rs485_start_tx;
|
||||
uart->rs485_stop_tx = up->rs485_stop_tx;
|
||||
uart->dma = up->dma;
|
||||
|
||||
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
||||
if (uart->port.fifosize && !uart->tx_loadsz)
|
||||
uart->tx_loadsz = uart->port.fifosize;
|
||||
|
||||
if (up->port.dev)
|
||||
if (up->port.dev) {
|
||||
uart->port.dev = up->port.dev;
|
||||
uart_get_rs485_mode(uart->port.dev, &uart->port.rs485);
|
||||
}
|
||||
|
||||
if (up->port.flags & UPF_FIXED_TYPE)
|
||||
uart->port.type = up->port.type;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/* Synopsys DesignWare 8250 library header file. */
|
||||
|
||||
#include <linux/types.h>
|
||||
|
@@ -135,7 +135,7 @@ struct exar8250 {
|
||||
unsigned int nr;
|
||||
struct exar8250_board *board;
|
||||
void __iomem *virt;
|
||||
int line[0];
|
||||
int line[];
|
||||
};
|
||||
|
||||
static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
|
@@ -156,6 +156,11 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static const struct dw_dma_platform_data qrk_serial_dma_pdata = {
|
||||
.nr_channels = 2,
|
||||
@@ -356,6 +361,7 @@ static const struct lpss8250_board byt_board = {
|
||||
static const struct lpss8250_board ehl_board = {
|
||||
.freq = 200000000,
|
||||
.base_baud = 12500000,
|
||||
.setup = ehl_serial_setup,
|
||||
};
|
||||
|
||||
static const struct lpss8250_board qrk_board = {
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */
|
||||
#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */
|
||||
#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */
|
||||
#define MTK_UART_DEBUG0 0x18
|
||||
#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */
|
||||
#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */
|
||||
#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */
|
||||
@@ -388,9 +389,18 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
static int __maybe_unused mtk8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(data->line);
|
||||
|
||||
clk_disable_unprepare(data->uart_clk);
|
||||
clk_disable_unprepare(data->bus_clk);
|
||||
/* wait until UART in idle status */
|
||||
while
|
||||
(serial_in(up, MTK_UART_DEBUG0));
|
||||
|
||||
if (data->clk_count == 0U) {
|
||||
dev_dbg(dev, "%s clock count is 0\n", __func__);
|
||||
} else {
|
||||
clk_disable_unprepare(data->bus_clk);
|
||||
data->clk_count--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -400,16 +410,16 @@ static int __maybe_unused mtk8250_runtime_resume(struct device *dev)
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(data->uart_clk);
|
||||
if (err) {
|
||||
dev_warn(dev, "Can't enable clock\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(data->bus_clk);
|
||||
if (err) {
|
||||
dev_warn(dev, "Can't enable bus clock\n");
|
||||
return err;
|
||||
if (data->clk_count > 0U) {
|
||||
dev_dbg(dev, "%s clock count is %d\n", __func__,
|
||||
data->clk_count);
|
||||
} else {
|
||||
err = clk_prepare_enable(data->bus_clk);
|
||||
if (err) {
|
||||
dev_warn(dev, "Can't enable bus clock\n");
|
||||
return err;
|
||||
}
|
||||
data->clk_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -419,12 +429,14 @@ static void
|
||||
mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
{
|
||||
if (!state)
|
||||
pm_runtime_get_sync(port->dev);
|
||||
if (!mtk8250_runtime_resume(port->dev))
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
serial8250_do_pm(port, state, old);
|
||||
|
||||
if (state)
|
||||
pm_runtime_put_sync_suspend(port->dev);
|
||||
if (!pm_runtime_put_sync_suspend(port->dev))
|
||||
mtk8250_runtime_suspend(port->dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
@@ -501,6 +513,8 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk_count = 0;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
err = mtk8250_probe_of(pdev, &uart.port, data);
|
||||
if (err)
|
||||
@@ -533,6 +547,7 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
err = mtk8250_runtime_resume(&pdev->dev);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -541,9 +556,6 @@ static int mtk8250_probe(struct platform_device *pdev)
|
||||
if (data->line < 0)
|
||||
return data->line;
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
data->rx_wakeup_irq = platform_get_irq_optional(pdev, 1);
|
||||
|
||||
return 0;
|
||||
@@ -556,11 +568,13 @@ static int mtk8250_remove(struct platform_device *pdev)
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
mtk8250_runtime_suspend(&pdev->dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
if (!pm_runtime_status_suspended(&pdev->dev))
|
||||
mtk8250_runtime_suspend(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -7,7 +7,6 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of_address.h>
|
||||
@@ -26,67 +25,16 @@ struct of_serial_info {
|
||||
int line;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ARCH_TEGRA
|
||||
static void tegra_serial_handle_break(struct uart_port *p)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
|
||||
do {
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||
status = p->serial_in(p, UART_RX);
|
||||
else
|
||||
break;
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
#else
|
||||
static inline void tegra_serial_handle_break(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static int of_8250_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* Clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init and serial8250_em485_destroy
|
||||
* are idempotent
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
int ret = serial8250_em485_init(up);
|
||||
|
||||
if (ret) {
|
||||
rs485->flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial8250_em485_destroy(up);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill a struct uart_port for a given device node
|
||||
*/
|
||||
static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
int type, struct uart_port *port,
|
||||
int type, struct uart_8250_port *up,
|
||||
struct of_serial_info *info)
|
||||
{
|
||||
struct resource resource;
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
struct uart_port *port = &up->port;
|
||||
u32 clk, spd, prop;
|
||||
int ret, irq;
|
||||
|
||||
@@ -207,13 +155,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
port->flags |= UPF_SKIP_TEST;
|
||||
|
||||
port->dev = &ofdev->dev;
|
||||
port->rs485_config = of_8250_rs485_config;
|
||||
port->rs485_config = serial8250_em485_config;
|
||||
up->rs485_start_tx = serial8250_em485_start_tx;
|
||||
up->rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
|
||||
switch (type) {
|
||||
case PORT_TEGRA:
|
||||
port->handle_break = tegra_serial_handle_break;
|
||||
break;
|
||||
|
||||
case PORT_RT2880:
|
||||
port->iotype = UPIO_AU;
|
||||
break;
|
||||
@@ -258,7 +204,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
|
||||
ret = of_platform_serial_setup(ofdev, port_type, &port8250, info);
|
||||
if (ret)
|
||||
goto err_free;
|
||||
|
||||
@@ -358,7 +304,6 @@ static const struct of_device_id of_platform_serial_table[] = {
|
||||
{ .compatible = "ns16550", .data = (void *)PORT_16550, },
|
||||
{ .compatible = "ns16750", .data = (void *)PORT_16750, },
|
||||
{ .compatible = "ns16850", .data = (void *)PORT_16850, },
|
||||
{ .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, },
|
||||
{ .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, },
|
||||
{ .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, },
|
||||
{ .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, },
|
||||
|
@@ -40,6 +40,7 @@
|
||||
* The same errata is applicable to AM335x and DRA7x processors too.
|
||||
*/
|
||||
#define UART_ERRATA_CLOCK_DISABLE (1 << 3)
|
||||
#define UART_HAS_EFR2 BIT(4)
|
||||
|
||||
#define OMAP_UART_FCR_RX_TRIG 6
|
||||
#define OMAP_UART_FCR_TX_TRIG 4
|
||||
@@ -93,6 +94,10 @@
|
||||
#define OMAP_UART_REV_52 0x0502
|
||||
#define OMAP_UART_REV_63 0x0603
|
||||
|
||||
/* Enhanced features register 2 */
|
||||
#define UART_OMAP_EFR2 0x23
|
||||
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
|
||||
|
||||
struct omap8250_priv {
|
||||
int line;
|
||||
u8 habit;
|
||||
@@ -105,6 +110,8 @@ struct omap8250_priv {
|
||||
u8 delayed_restore;
|
||||
u16 quot;
|
||||
|
||||
u8 tx_trigger;
|
||||
u8 rx_trigger;
|
||||
bool is_suspending;
|
||||
int wakeirq;
|
||||
int wakeups_enabled;
|
||||
@@ -118,6 +125,17 @@ struct omap8250_priv {
|
||||
bool throttled;
|
||||
};
|
||||
|
||||
struct omap8250_dma_params {
|
||||
u32 rx_size;
|
||||
u8 rx_trigger;
|
||||
u8 tx_trigger;
|
||||
};
|
||||
|
||||
struct omap8250_platdata {
|
||||
struct omap8250_dma_params *dma_params;
|
||||
u8 habit;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static void omap_8250_rx_dma_flush(struct uart_8250_port *p);
|
||||
#else
|
||||
@@ -295,8 +313,8 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
||||
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_RESTORE(16) |
|
||||
OMAP_UART_TCR_HALT(52));
|
||||
serial_out(up, UART_TI752_TLR,
|
||||
TRIGGER_TLR_MASK(TX_TRIGGER) << UART_TI752_TLR_TX |
|
||||
TRIGGER_TLR_MASK(RX_TRIGGER) << UART_TI752_TLR_RX);
|
||||
TRIGGER_TLR_MASK(priv->tx_trigger) << UART_TI752_TLR_TX |
|
||||
TRIGGER_TLR_MASK(priv->rx_trigger) << UART_TI752_TLR_RX);
|
||||
|
||||
serial_out(up, UART_LCR, 0);
|
||||
|
||||
@@ -435,8 +453,8 @@ static void omap_8250_set_termios(struct uart_port *port,
|
||||
* This is because threshold and trigger values are the same.
|
||||
*/
|
||||
up->fcr = UART_FCR_ENABLE_FIFO;
|
||||
up->fcr |= TRIGGER_FCR_MASK(TX_TRIGGER) << OMAP_UART_FCR_TX_TRIG;
|
||||
up->fcr |= TRIGGER_FCR_MASK(RX_TRIGGER) << OMAP_UART_FCR_RX_TRIG;
|
||||
up->fcr |= TRIGGER_FCR_MASK(priv->tx_trigger) << OMAP_UART_FCR_TX_TRIG;
|
||||
up->fcr |= TRIGGER_FCR_MASK(priv->rx_trigger) << OMAP_UART_FCR_RX_TRIG;
|
||||
|
||||
priv->scr = OMAP_UART_SCR_RX_TRIG_GRANU1_MASK | OMAP_UART_SCR_TX_EMPTY |
|
||||
OMAP_UART_SCR_TX_TRIG_GRANU1_MASK;
|
||||
@@ -651,7 +669,7 @@ static int omap_8250_startup(struct uart_port *port)
|
||||
priv->wer |= OMAP_UART_TX_WAKEUP_EN;
|
||||
serial_out(up, UART_OMAP_WER, priv->wer);
|
||||
|
||||
if (up->dma)
|
||||
if (up->dma && !(priv->habit & UART_HAS_EFR2))
|
||||
up->dma->rx_dma(up);
|
||||
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
@@ -676,6 +694,8 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
serial_out(up, UART_OMAP_WER, 0);
|
||||
if (priv->habit & UART_HAS_EFR2)
|
||||
serial_out(up, UART_OMAP_EFR2, 0x0);
|
||||
|
||||
up->ier = 0;
|
||||
serial_out(up, UART_IER, 0);
|
||||
@@ -699,14 +719,12 @@ static void omap_8250_shutdown(struct uart_port *port)
|
||||
static void omap_8250_throttle(struct uart_port *port)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
port->ops->stop_rx(port);
|
||||
priv->throttled = true;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
@@ -714,36 +732,6 @@ static void omap_8250_throttle(struct uart_port *port)
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static int omap_8250_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* Clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init and serial8250_em485_destroy
|
||||
* are idempotent
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
int ret = serial8250_em485_init(up);
|
||||
|
||||
if (ret) {
|
||||
rs485->flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial8250_em485_destroy(up);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_8250_unthrottle(struct uart_port *port)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
@@ -757,6 +745,7 @@ 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);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
@@ -767,32 +756,50 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p);
|
||||
|
||||
/* Must be called while priv->rx_dma_lock is held */
|
||||
static void __dma_rx_do_complete(struct uart_8250_port *p)
|
||||
{
|
||||
struct omap8250_priv *priv = p->port.private_data;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_chan *rxchan = dma->rxchan;
|
||||
dma_cookie_t cookie;
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (!dma->rx_running)
|
||||
goto unlock;
|
||||
goto out;
|
||||
|
||||
cookie = dma->rx_cookie;
|
||||
dma->rx_running = 0;
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
dmaengine_tx_status(rxchan, cookie, &state);
|
||||
|
||||
count = dma->rx_size - state.residue;
|
||||
count = dma->rx_size - state.residue + state.in_flight_bytes;
|
||||
if (count < dma->rx_size) {
|
||||
dmaengine_terminate_async(rxchan);
|
||||
|
||||
/*
|
||||
* Poll for teardown to complete which guarantees in
|
||||
* flight data is drained.
|
||||
*/
|
||||
if (state.in_flight_bytes) {
|
||||
int poll_count = 25;
|
||||
|
||||
while (dmaengine_tx_status(rxchan, cookie, NULL) &&
|
||||
poll_count--)
|
||||
cpu_relax();
|
||||
|
||||
if (!poll_count)
|
||||
dev_err(p->port.dev, "teardown incomplete\n");
|
||||
}
|
||||
}
|
||||
if (!count)
|
||||
goto out;
|
||||
ret = tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
|
||||
p->port.icount.rx += ret;
|
||||
p->port.icount.buf_overrun += count - ret;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
out:
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
@@ -818,8 +825,12 @@ static void __dma_rx_complete(void *param)
|
||||
return;
|
||||
}
|
||||
__dma_rx_do_complete(p);
|
||||
if (!priv->throttled)
|
||||
omap_8250_rx_dma(p);
|
||||
if (!priv->throttled) {
|
||||
p->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
if (!(priv->habit & UART_HAS_EFR2))
|
||||
omap_8250_rx_dma(p);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
@@ -845,10 +856,8 @@ static void omap_8250_rx_dma_flush(struct uart_8250_port *p)
|
||||
if (WARN_ON_ONCE(ret))
|
||||
priv->rx_dma_broken = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
|
||||
__dma_rx_do_complete(p);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
spin_unlock_irqrestore(&priv->rx_dma_lock, flags);
|
||||
}
|
||||
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p)
|
||||
@@ -864,8 +873,20 @@ static int omap_8250_rx_dma(struct uart_8250_port *p)
|
||||
|
||||
spin_lock_irqsave(&priv->rx_dma_lock, flags);
|
||||
|
||||
if (dma->rx_running)
|
||||
if (dma->rx_running) {
|
||||
enum dma_status state;
|
||||
|
||||
state = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, NULL);
|
||||
if (state == DMA_COMPLETE) {
|
||||
/*
|
||||
* Disable RX interrupts to allow RX DMA completion
|
||||
* callback to run.
|
||||
*/
|
||||
p->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
@@ -1036,6 +1057,46 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
return omap_8250_rx_dma(up);
|
||||
}
|
||||
|
||||
static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up,
|
||||
u8 iir, unsigned char status)
|
||||
{
|
||||
if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(iir & UART_IIR_RDI)) {
|
||||
if (handle_rx_dma(up, iir)) {
|
||||
status = serial8250_rx_chars(up, status);
|
||||
omap_8250_rx_dma(up);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
|
||||
unsigned char status)
|
||||
{
|
||||
/*
|
||||
* Queue a new transfer if FIFO has data.
|
||||
*/
|
||||
if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(up->ier & UART_IER_RDI)) {
|
||||
omap_8250_rx_dma(up);
|
||||
serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
|
||||
} else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
|
||||
/*
|
||||
* Disable RX timeout, read IIR to clear
|
||||
* current timeout condition, clear EFR2 to
|
||||
* periodic timeouts, re-enable interrupts.
|
||||
*/
|
||||
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
omap_8250_rx_dma_flush(up);
|
||||
serial_in(up, UART_IIR);
|
||||
serial_out(up, UART_OMAP_EFR2, 0x0);
|
||||
up->ier |= UART_IER_RLSI | UART_IER_RDI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is mostly serial8250_handle_irq(). We have a slightly different DMA
|
||||
* hoook for RX/TX and need different logic for them in the ISR. Therefore we
|
||||
@@ -1044,6 +1105,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct omap8250_priv *priv = up->port.private_data;
|
||||
unsigned char status;
|
||||
unsigned long flags;
|
||||
u8 iir;
|
||||
@@ -1053,19 +1115,18 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
iir = serial_port_in(port, UART_IIR);
|
||||
if (iir & UART_IIR_NO_INT) {
|
||||
serial8250_rpm_put(up);
|
||||
return 0;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
status = serial_port_in(port, UART_LSR);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (handle_rx_dma(up, iir)) {
|
||||
status = serial8250_rx_chars(up, status);
|
||||
omap_8250_rx_dma(up);
|
||||
}
|
||||
}
|
||||
if (priv->habit & UART_HAS_EFR2)
|
||||
am654_8250_handle_rx_dma(up, iir, status);
|
||||
else
|
||||
status = omap_8250_handle_rx_dma(up, iir, status);
|
||||
|
||||
serial8250_modem_status(up);
|
||||
if (status & UART_LSR_THRE && up->dma->tx_err) {
|
||||
if (uart_tx_stopped(&up->port) ||
|
||||
@@ -1107,18 +1168,41 @@ static int omap8250_no_handle_irq(struct uart_port *port)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE;
|
||||
static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE;
|
||||
static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE;
|
||||
static struct omap8250_dma_params am654_dma = {
|
||||
.rx_size = SZ_2K,
|
||||
.rx_trigger = 1,
|
||||
.tx_trigger = TX_TRIGGER,
|
||||
};
|
||||
|
||||
static struct omap8250_dma_params am33xx_dma = {
|
||||
.rx_size = RX_TRIGGER,
|
||||
.rx_trigger = RX_TRIGGER,
|
||||
.tx_trigger = TX_TRIGGER,
|
||||
};
|
||||
|
||||
static struct omap8250_platdata am654_platdata = {
|
||||
.dma_params = &am654_dma,
|
||||
.habit = UART_HAS_EFR2,
|
||||
};
|
||||
|
||||
static struct omap8250_platdata am33xx_platdata = {
|
||||
.dma_params = &am33xx_dma,
|
||||
.habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE,
|
||||
};
|
||||
|
||||
static struct omap8250_platdata omap4_platdata = {
|
||||
.dma_params = &am33xx_dma,
|
||||
.habit = UART_ERRATA_CLOCK_DISABLE,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap8250_dt_ids[] = {
|
||||
{ .compatible = "ti,am654-uart" },
|
||||
{ .compatible = "ti,am654-uart", .data = &am654_platdata, },
|
||||
{ .compatible = "ti,omap2-uart" },
|
||||
{ .compatible = "ti,omap3-uart" },
|
||||
{ .compatible = "ti,omap4-uart", .data = &omap4_habit, },
|
||||
{ .compatible = "ti,am3352-uart", .data = &am3352_habit, },
|
||||
{ .compatible = "ti,am4372-uart", .data = &am3352_habit, },
|
||||
{ .compatible = "ti,dra742-uart", .data = &dra742_habit, },
|
||||
{ .compatible = "ti,omap4-uart", .data = &omap4_platdata, },
|
||||
{ .compatible = "ti,am3352-uart", .data = &am33xx_platdata, },
|
||||
{ .compatible = "ti,am4372-uart", .data = &am33xx_platdata, },
|
||||
{ .compatible = "ti,dra742-uart", .data = &omap4_platdata, },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap8250_dt_ids);
|
||||
@@ -1129,10 +1213,10 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct omap8250_priv *priv;
|
||||
const struct omap8250_platdata *pdata;
|
||||
struct uart_8250_port up;
|
||||
int ret;
|
||||
void __iomem *membase;
|
||||
const struct of_device_id *id;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "missing registers or irq\n");
|
||||
@@ -1187,7 +1271,9 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
up.port.shutdown = omap_8250_shutdown;
|
||||
up.port.throttle = omap_8250_throttle;
|
||||
up.port.unthrottle = omap_8250_unthrottle;
|
||||
up.port.rs485_config = omap_8250_rs485_config;
|
||||
up.port.rs485_config = serial8250_em485_config;
|
||||
up.rs485_start_tx = serial8250_em485_start_tx;
|
||||
up.rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
up.port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
@@ -1211,9 +1297,9 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
|
||||
priv->wakeirq = irq_of_parse_and_map(np, 1);
|
||||
|
||||
id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev);
|
||||
if (id && id->data)
|
||||
priv->habit |= *(u8 *)id->data;
|
||||
pdata = of_device_get_match_data(&pdev->dev);
|
||||
if (pdata)
|
||||
priv->habit |= pdata->habit;
|
||||
|
||||
if (!up.port.uartclk) {
|
||||
up.port.uartclk = DEFAULT_CLK_SPEED;
|
||||
@@ -1230,6 +1316,7 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
spin_lock_init(&priv->rx_dma_lock);
|
||||
|
||||
device_init_wakeup(&pdev->dev, true);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
|
||||
/*
|
||||
@@ -1243,12 +1330,13 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, -1);
|
||||
|
||||
pm_runtime_irq_safe(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
omap_serial_fill_features_erratas(&up, priv);
|
||||
up.port.handle_irq = omap8250_no_handle_irq;
|
||||
priv->rx_trigger = RX_TRIGGER;
|
||||
priv->tx_trigger = TX_TRIGGER;
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
/*
|
||||
* Oh DMA support. If there are no DMA properties in the DT then
|
||||
@@ -1260,13 +1348,26 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
*/
|
||||
ret = of_property_count_strings(np, "dma-names");
|
||||
if (ret == 2) {
|
||||
struct omap8250_dma_params *dma_params = NULL;
|
||||
|
||||
up.dma = &priv->omap8250_dma;
|
||||
priv->omap8250_dma.fn = the_no_dma_filter_fn;
|
||||
priv->omap8250_dma.tx_dma = omap_8250_tx_dma;
|
||||
priv->omap8250_dma.rx_dma = omap_8250_rx_dma;
|
||||
priv->omap8250_dma.rx_size = RX_TRIGGER;
|
||||
priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER;
|
||||
priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER;
|
||||
up.dma->fn = the_no_dma_filter_fn;
|
||||
up.dma->tx_dma = omap_8250_tx_dma;
|
||||
up.dma->rx_dma = omap_8250_rx_dma;
|
||||
if (pdata)
|
||||
dma_params = pdata->dma_params;
|
||||
|
||||
if (dma_params) {
|
||||
up.dma->rx_size = dma_params->rx_size;
|
||||
up.dma->rxconf.src_maxburst = dma_params->rx_trigger;
|
||||
up.dma->txconf.dst_maxburst = dma_params->tx_trigger;
|
||||
priv->rx_trigger = dma_params->rx_trigger;
|
||||
priv->tx_trigger = dma_params->tx_trigger;
|
||||
} else {
|
||||
up.dma->rx_size = RX_TRIGGER;
|
||||
up.dma->rxconf.src_maxburst = RX_TRIGGER;
|
||||
up.dma->txconf.dst_maxburst = TX_TRIGGER;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ret = serial8250_register_8250_port(&up);
|
||||
@@ -1464,7 +1565,7 @@ static int omap8250_runtime_resume(struct device *dev)
|
||||
if (omap8250_lost_context(up))
|
||||
omap8250_restore_regs(up);
|
||||
|
||||
if (up->dma && up->dma->rxchan)
|
||||
if (up->dma && up->dma->rxchan && !(priv->habit & UART_HAS_EFR2))
|
||||
omap_8250_rx_dma(up);
|
||||
|
||||
priv->latency = priv->calc_latency;
|
||||
|
@@ -53,7 +53,7 @@ struct serial_private {
|
||||
unsigned int nr;
|
||||
struct pci_serial_quirk *quirk;
|
||||
const struct pciserial_board *board;
|
||||
int line[0];
|
||||
int line[];
|
||||
};
|
||||
|
||||
static const struct pci_device_id pci_use_msi[] = {
|
||||
|
@@ -557,17 +557,6 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p)
|
||||
{
|
||||
unsigned char mcr = serial8250_in_MCR(p);
|
||||
|
||||
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial8250_out_MCR(p, mcr);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
|
||||
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
|
||||
|
||||
@@ -615,7 +604,7 @@ EXPORT_SYMBOL_GPL(serial8250_rpm_put);
|
||||
*
|
||||
* Return 0 - success, -errno - otherwise
|
||||
*/
|
||||
int serial8250_em485_init(struct uart_8250_port *p)
|
||||
static int serial8250_em485_init(struct uart_8250_port *p)
|
||||
{
|
||||
if (p->em485)
|
||||
return 0;
|
||||
@@ -632,11 +621,12 @@ int serial8250_em485_init(struct uart_8250_port *p)
|
||||
p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
|
||||
p->em485->port = p;
|
||||
p->em485->active_timer = NULL;
|
||||
serial8250_em485_rts_after_send(p);
|
||||
p->em485->tx_stopped = true;
|
||||
|
||||
p->rs485_stop_tx(p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_init);
|
||||
|
||||
/**
|
||||
* serial8250_em485_destroy() - put uart_8250_port into normal state
|
||||
@@ -664,6 +654,52 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
|
||||
|
||||
/**
|
||||
* serial8250_em485_config() - generic ->rs485_config() callback
|
||||
* @port: uart port
|
||||
* @rs485: rs485 settings
|
||||
*
|
||||
* Generic callback usable by 8250 uart drivers to activate rs485 settings
|
||||
* if the uart is incapable of driving RTS as a Transmit Enable signal in
|
||||
* hardware, relying on software emulation instead.
|
||||
*/
|
||||
int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
/* pick sane settings if the user hasn't */
|
||||
if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
|
||||
rs485->flags |= SER_RS485_RTS_ON_SEND;
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
|
||||
/* clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
port->rs485 = *rs485;
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init() and serial8250_em485_destroy()
|
||||
* are idempotent.
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
int ret = serial8250_em485_init(up);
|
||||
|
||||
if (ret) {
|
||||
rs485->flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
serial8250_em485_destroy(up);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_config);
|
||||
|
||||
/*
|
||||
* These two wrappers ensure that enable_runtime_pm_tx() can be called more than
|
||||
* once and disable_runtime_pm_tx() will still disable RPM because the fifo is
|
||||
@@ -1318,8 +1354,8 @@ out_lock:
|
||||
fintek_8250_probe(up);
|
||||
|
||||
if (up->capabilities != old_capabilities) {
|
||||
pr_warn("%s: detected caps %08x should be %08x\n",
|
||||
port->name, old_capabilities, up->capabilities);
|
||||
dev_warn(port->dev, "detected caps %08x should be %08x\n",
|
||||
old_capabilities, up->capabilities);
|
||||
}
|
||||
out:
|
||||
DEBUG_AUTOCONF("iir=%d ", scratch);
|
||||
@@ -1394,9 +1430,21 @@ static void serial8250_stop_rx(struct uart_port *port)
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static void __do_stop_tx_rs485(struct uart_8250_port *p)
|
||||
/**
|
||||
* serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
|
||||
* @up: uart 8250 port
|
||||
*
|
||||
* Generic callback usable by 8250 uart drivers to stop rs485 transmission.
|
||||
*/
|
||||
void serial8250_em485_stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
serial8250_em485_rts_after_send(p);
|
||||
unsigned char mcr = serial8250_in_MCR(p);
|
||||
|
||||
if (p->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial8250_out_MCR(p, mcr);
|
||||
|
||||
/*
|
||||
* Empty the RX FIFO, we are not interested in anything
|
||||
@@ -1410,6 +1458,8 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
|
||||
serial_port_out(&p->port, UART_IER, p->ier);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
|
||||
|
||||
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
|
||||
{
|
||||
struct uart_8250_em485 *em485;
|
||||
@@ -1422,8 +1472,9 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
|
||||
serial8250_rpm_get(p);
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
if (em485->active_timer == &em485->stop_tx_timer) {
|
||||
__do_stop_tx_rs485(p);
|
||||
p->rs485_stop_tx(p);
|
||||
em485->active_timer = NULL;
|
||||
em485->tx_stopped = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
serial8250_rpm_put(p);
|
||||
@@ -1444,7 +1495,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
|
||||
struct uart_8250_em485 *em485 = p->em485;
|
||||
|
||||
/*
|
||||
* __do_stop_tx_rs485 is going to set RTS according to config
|
||||
* rs485_stop_tx() is going to set RTS according to config
|
||||
* AND flush RX FIFO if required.
|
||||
*/
|
||||
if (p->port.rs485.delay_rts_after_send > 0) {
|
||||
@@ -1452,7 +1503,9 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
|
||||
start_hrtimer_ms(&em485->stop_tx_timer,
|
||||
p->port.rs485.delay_rts_after_send);
|
||||
} else {
|
||||
__do_stop_tx_rs485(p);
|
||||
p->rs485_stop_tx(p);
|
||||
em485->active_timer = NULL;
|
||||
em485->tx_stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1477,8 +1530,6 @@ static inline void __stop_tx(struct uart_8250_port *p)
|
||||
if ((lsr & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
return;
|
||||
|
||||
em485->active_timer = NULL;
|
||||
|
||||
__stop_tx_rs485(p);
|
||||
}
|
||||
__do_stop_tx(p);
|
||||
@@ -1528,25 +1579,42 @@ static inline void __start_tx(struct uart_port *port)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void start_tx_rs485(struct uart_port *port)
|
||||
/**
|
||||
* serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
|
||||
* @up: uart 8250 port
|
||||
*
|
||||
* 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.
|
||||
* (Some chips use inverse semantics.) Further assumes that reception is
|
||||
* 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)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
unsigned char mcr;
|
||||
unsigned char mcr = serial8250_in_MCR(up);
|
||||
|
||||
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
serial8250_stop_rx(&up->port);
|
||||
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial8250_out_MCR(up, mcr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_start_tx);
|
||||
|
||||
static inline void start_tx_rs485(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
|
||||
em485->active_timer = NULL;
|
||||
|
||||
mcr = serial8250_in_MCR(up);
|
||||
if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) !=
|
||||
!!(mcr & UART_MCR_RTS)) {
|
||||
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
|
||||
mcr |= UART_MCR_RTS;
|
||||
else
|
||||
mcr &= ~UART_MCR_RTS;
|
||||
serial8250_out_MCR(up, mcr);
|
||||
if (em485->tx_stopped) {
|
||||
em485->tx_stopped = false;
|
||||
|
||||
up->rs485_start_tx(up);
|
||||
|
||||
if (up->port.rs485.delay_rts_before_send > 0) {
|
||||
em485->active_timer = &em485->start_tx_timer;
|
||||
@@ -1683,7 +1751,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||
lsr &= port->read_status_mask;
|
||||
|
||||
if (lsr & UART_LSR_BI) {
|
||||
pr_debug("%s: handling break\n", __func__);
|
||||
dev_dbg(port->dev, "handling break\n");
|
||||
flag = TTY_BREAK;
|
||||
} else if (lsr & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
@@ -1815,6 +1883,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
unsigned char status;
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
bool skip_rx = false;
|
||||
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return 0;
|
||||
@@ -1823,7 +1892,20 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
|
||||
status = serial_port_in(port, UART_LSR);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
/*
|
||||
* If port is stopped and there are no error conditions in the
|
||||
* FIFO, then don't drain the FIFO, as this may lead to TTY buffer
|
||||
* overflow. Not servicing, RX FIFO would trigger auto HW flow
|
||||
* control when FIFO occupancy reaches preset threshold, thus
|
||||
* halting RX. This only works when auto HW flow control is
|
||||
* available.
|
||||
*/
|
||||
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
|
||||
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
|
||||
!(port->read_status_mask & UART_LSR_DR))
|
||||
skip_rx = true;
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
|
||||
if (!up->dma || handle_rx_dma(up, iir))
|
||||
status = serial8250_rx_chars(up, status);
|
||||
}
|
||||
@@ -1924,6 +2006,13 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned char mcr;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
if (serial8250_in_MCR(up) & UART_MCR_RTS)
|
||||
mctrl |= TIOCM_RTS;
|
||||
else
|
||||
mctrl &= ~TIOCM_RTS;
|
||||
}
|
||||
|
||||
mcr = serial8250_TIOCM_to_MCR(mctrl);
|
||||
|
||||
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
|
||||
@@ -2134,7 +2223,7 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
*/
|
||||
if (!(port->flags & UPF_BUGGY_UART) &&
|
||||
(serial_port_in(port, UART_LSR) == 0xff)) {
|
||||
pr_info_ratelimited("%s: LSR safety check engaged!\n", port->name);
|
||||
dev_info_ratelimited(port->dev, "LSR safety check engaged!\n");
|
||||
retval = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
@@ -2166,8 +2255,7 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
(port->type == PORT_ALTR_16550_F128)) && (port->fifosize > 1)) {
|
||||
/* Bounds checking of TX threshold (valid 0 to fifosize-2) */
|
||||
if ((up->tx_loadsz < 2) || (up->tx_loadsz > port->fifosize)) {
|
||||
pr_err("%s TX FIFO Threshold errors, skipping\n",
|
||||
port->name);
|
||||
dev_err(port->dev, "TX FIFO Threshold errors, skipping\n");
|
||||
} else {
|
||||
serial_port_out(port, UART_ALTR_AFR,
|
||||
UART_ALTR_EN_TXFIFO_LW);
|
||||
@@ -2268,8 +2356,7 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
|
||||
if (!(up->bugs & UART_BUG_TXEN)) {
|
||||
up->bugs |= UART_BUG_TXEN;
|
||||
pr_debug("%s - enabling bad tx status workarounds\n",
|
||||
port->name);
|
||||
dev_dbg(port->dev, "enabling bad tx status workarounds\n");
|
||||
}
|
||||
} else {
|
||||
up->bugs &= ~UART_BUG_TXEN;
|
||||
@@ -2294,10 +2381,14 @@ dont_test_tx_en:
|
||||
* Request DMA channels for both RX and TX.
|
||||
*/
|
||||
if (up->dma) {
|
||||
retval = serial8250_request_dma(up);
|
||||
if (retval) {
|
||||
pr_warn_ratelimited("%s - failed to request DMA\n",
|
||||
port->name);
|
||||
const char *msg = NULL;
|
||||
|
||||
if (uart_console(port))
|
||||
msg = "forbid DMA for kernel console";
|
||||
else if (serial8250_request_dma(up))
|
||||
msg = "failed to request DMA";
|
||||
if (msg) {
|
||||
dev_warn_ratelimited(port->dev, "%s\n", msg);
|
||||
up->dma = NULL;
|
||||
}
|
||||
}
|
||||
@@ -2880,7 +2971,7 @@ static int do_serial8250_get_rxtrig(struct tty_port *port)
|
||||
return rxtrig_bytes;
|
||||
}
|
||||
|
||||
static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev,
|
||||
static ssize_t rx_trig_bytes_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tty_port *port = dev_get_drvdata(dev);
|
||||
@@ -2926,7 +3017,7 @@ static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
|
||||
static ssize_t rx_trig_bytes_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct tty_port *port = dev_get_drvdata(dev);
|
||||
@@ -2947,18 +3038,16 @@ static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP,
|
||||
serial8250_get_attr_rx_trig_bytes,
|
||||
serial8250_set_attr_rx_trig_bytes);
|
||||
static DEVICE_ATTR_RW(rx_trig_bytes);
|
||||
|
||||
static struct attribute *serial8250_dev_attrs[] = {
|
||||
&dev_attr_rx_trig_bytes.attr,
|
||||
NULL,
|
||||
};
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group serial8250_dev_attr_group = {
|
||||
.attrs = serial8250_dev_attrs,
|
||||
};
|
||||
};
|
||||
|
||||
static void register_dev_spec_attr_grp(struct uart_8250_port *up)
|
||||
{
|
||||
@@ -2987,6 +3076,9 @@ static void serial8250_config_port(struct uart_port *port, int flags)
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
autoconfig(up);
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
port->rs485_config(port, &port->rs485);
|
||||
|
||||
/* if access method is AU, it is a 16550 with a quirk */
|
||||
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
|
||||
up->bugs |= UART_BUG_NOMSR;
|
||||
@@ -3127,10 +3219,14 @@ static void serial8250_console_restore(struct uart_8250_port *up)
|
||||
* any possible real use of the port...
|
||||
*
|
||||
* The console_lock must be held when we get here.
|
||||
*
|
||||
* Doing runtime PM is really a bad idea for the kernel console.
|
||||
* Thus, we assume the function is called when device is powered up.
|
||||
*/
|
||||
void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned long flags;
|
||||
unsigned int ier;
|
||||
@@ -3138,8 +3234,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
|
||||
touch_nmi_watchdog();
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&port->lock, flags);
|
||||
else
|
||||
@@ -3161,6 +3255,12 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
up->canary = 0;
|
||||
}
|
||||
|
||||
if (em485) {
|
||||
if (em485->tx_stopped)
|
||||
up->rs485_start_tx(up);
|
||||
mdelay(port->rs485.delay_rts_before_send);
|
||||
}
|
||||
|
||||
uart_console_write(port, s, count, serial8250_console_putchar);
|
||||
|
||||
/*
|
||||
@@ -3168,6 +3268,13 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
|
||||
if (em485) {
|
||||
mdelay(port->rs485.delay_rts_after_send);
|
||||
if (em485->tx_stopped)
|
||||
up->rs485_stop_tx(up);
|
||||
}
|
||||
|
||||
serial_port_out(port, UART_IER, ier);
|
||||
|
||||
/*
|
||||
@@ -3182,7 +3289,6 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
static unsigned int probe_baud(struct uart_port *port)
|
||||
@@ -3206,6 +3312,7 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int ret;
|
||||
|
||||
if (!port->iobase && !port->membase)
|
||||
return -ENODEV;
|
||||
@@ -3215,7 +3322,22 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
|
||||
else if (probe)
|
||||
baud = probe_baud(port);
|
||||
|
||||
return uart_set_options(port, port->cons, baud, parity, bits, flow);
|
||||
ret = uart_set_options(port, port->cons, baud, parity, bits, flow);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (port->dev)
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serial8250_console_exit(struct uart_port *port)
|
||||
{
|
||||
if (port->dev)
|
||||
pm_runtime_put_sync(port->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SERIAL_8250_CONSOLE */
|
||||
|
@@ -123,7 +123,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
|
||||
uart.port.regshift = 2;
|
||||
uart.port.irq = irqres->start;
|
||||
uart.port.fifosize = 64;
|
||||
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST;
|
||||
uart.port.flags = UPF_IOREMAP | UPF_SKIP_TEST | UPF_FIXED_TYPE;
|
||||
uart.port.dev = &pdev->dev;
|
||||
uart.port.uartclk = clk_get_rate(data->clk);
|
||||
uart.port.pm = serial_pxa_pm;
|
||||
|
198
drivers/tty/serial/8250/8250_tegra.c
Normal file
198
drivers/tty/serial/8250/8250_tegra.c
Normal file
@@ -0,0 +1,198 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Serial Port driver for Tegra devices
|
||||
*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
struct tegra_uart {
|
||||
struct clk *clk;
|
||||
struct reset_control *rst;
|
||||
int line;
|
||||
};
|
||||
|
||||
static void tegra_uart_handle_break(struct uart_port *p)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
|
||||
do {
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
|
||||
status = p->serial_in(p, UART_RX);
|
||||
else
|
||||
break;
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static int tegra_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port port8250;
|
||||
struct tegra_uart *uart;
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
uart = devm_kzalloc(&pdev->dev, sizeof(*uart), GFP_KERNEL);
|
||||
if (!uart)
|
||||
return -ENOMEM;
|
||||
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
|
||||
port = &port8250.port;
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT |
|
||||
UPF_FIXED_TYPE;
|
||||
port->iotype = UPIO_MEM32;
|
||||
port->regshift = 2;
|
||||
port->type = PORT_TEGRA;
|
||||
port->irqflags |= IRQF_SHARED;
|
||||
port->dev = &pdev->dev;
|
||||
port->handle_break = tegra_uart_handle_break;
|
||||
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (ret >= 0)
|
||||
port->line = ret;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->irq = ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
port->membase = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!port->membase)
|
||||
return -ENOMEM;
|
||||
|
||||
port->mapbase = res->start;
|
||||
port->mapsize = resource_size(res);
|
||||
|
||||
uart->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
|
||||
if (IS_ERR(uart->rst))
|
||||
return PTR_ERR(uart->rst);
|
||||
|
||||
if (device_property_read_u32(&pdev->dev, "clock-frequency",
|
||||
&port->uartclk)) {
|
||||
uart->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(uart->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(uart->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->uartclk = clk_get_rate(uart->clk);
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(uart->rst);
|
||||
if (ret)
|
||||
goto err_clkdisable;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
if (ret < 0)
|
||||
goto err_clkdisable;
|
||||
|
||||
platform_set_drvdata(pdev, uart);
|
||||
uart->line = ret;
|
||||
|
||||
return 0;
|
||||
|
||||
err_clkdisable:
|
||||
clk_disable_unprepare(uart->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_uart_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_uart *uart = platform_get_drvdata(pdev);
|
||||
|
||||
serial8250_unregister_port(uart->line);
|
||||
reset_control_assert(uart->rst);
|
||||
clk_disable_unprepare(uart->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_uart_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_uart *uart = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
|
||||
struct uart_port *port = &port8250->port;
|
||||
|
||||
serial8250_suspend_port(uart->line);
|
||||
|
||||
if (!uart_console(port) || console_suspend_enabled)
|
||||
clk_disable_unprepare(uart->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_uart_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_uart *uart = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *port8250 = serial8250_get_port(uart->line);
|
||||
struct uart_port *port = &port8250->port;
|
||||
|
||||
if (!uart_console(port) || console_suspend_enabled)
|
||||
clk_prepare_enable(uart->clk);
|
||||
|
||||
serial8250_resume_port(uart->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(tegra_uart_pm_ops, tegra_uart_suspend,
|
||||
tegra_uart_resume);
|
||||
|
||||
static const struct of_device_id tegra_uart_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra20-uart", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_uart_of_match);
|
||||
|
||||
static const struct acpi_device_id tegra_uart_acpi_match[] = {
|
||||
{ "NVDA0100", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, tegra_uart_acpi_match);
|
||||
|
||||
static struct platform_driver tegra_uart_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-uart",
|
||||
.pm = &tegra_uart_pm_ops,
|
||||
.of_match_table = tegra_uart_of_match,
|
||||
.acpi_match_table = ACPI_PTR(tegra_uart_acpi_match),
|
||||
},
|
||||
.probe = tegra_uart_probe,
|
||||
.remove = tegra_uart_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(tegra_uart_driver);
|
||||
|
||||
MODULE_AUTHOR("Jeff Brasen <jbrasen@nvidia.com>");
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra 8250 Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -500,6 +500,15 @@ config SERIAL_8250_PXA
|
||||
applicable to both devicetree and legacy boards, and early console is
|
||||
part of its support.
|
||||
|
||||
config SERIAL_8250_TEGRA
|
||||
tristate "8250 support for Tegra serial ports"
|
||||
default SERIAL_8250
|
||||
depends on SERIAL_8250
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
help
|
||||
Select this option if you have machine with an NVIDIA Tegra SoC and
|
||||
wish to enable 8250 serial driver for the Tegra serial interfaces.
|
||||
|
||||
config SERIAL_OF_PLATFORM
|
||||
tristate "Devicetree based probing for 8250 ports"
|
||||
depends on SERIAL_8250 && OF
|
||||
|
@@ -37,6 +37,7 @@ obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o
|
||||
obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
|
||||
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
|
||||
obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o
|
||||
obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o
|
||||
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
|
||||
|
||||
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
|
||||
|
@@ -260,15 +260,6 @@ config SERIAL_SAMSUNG_UARTS
|
||||
help
|
||||
Select the number of available UART ports for the Samsung S3C
|
||||
serial driver
|
||||
|
||||
config SERIAL_SAMSUNG_DEBUG
|
||||
bool "Samsung SoC serial debug"
|
||||
depends on SERIAL_SAMSUNG && DEBUG_LL
|
||||
help
|
||||
Add support for debugging the serial driver. Since this is
|
||||
generally being used as a console, we use our own output
|
||||
routines that go via the low-level debug printascii()
|
||||
function.
|
||||
|
||||
config SERIAL_SAMSUNG_CONSOLE
|
||||
bool "Support for console on Samsung SoC serial port"
|
||||
@@ -1111,7 +1102,7 @@ config SERIAL_SC16IS7XX_SPI
|
||||
help
|
||||
Enable SC16IS7xx driver on SPI bus,
|
||||
If required say y, and say n to spi if not required,
|
||||
This is additional support to exsisting driver.
|
||||
This is additional support to existing driver.
|
||||
You must select at least one bus for the driver to be built.
|
||||
|
||||
config SERIAL_TIMBERDALE
|
||||
@@ -1279,6 +1270,7 @@ config SERIAL_AR933X
|
||||
tristate "AR933X serial port support"
|
||||
depends on HAVE_CLK && ATH79
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
help
|
||||
If you have an Atheros AR933X SOC based board and want to use the
|
||||
built-in UART of the SoC, say Y to this option.
|
||||
@@ -1452,8 +1444,8 @@ config SERIAL_MEN_Z135
|
||||
|
||||
config SERIAL_SPRD
|
||||
tristate "Support for Spreadtrum serial"
|
||||
depends on ARCH_SPRD
|
||||
select SERIAL_CORE
|
||||
depends on COMMON_CLK
|
||||
help
|
||||
This enables the driver for the Spreadtrum's serial.
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
@@ -29,6 +30,8 @@
|
||||
|
||||
#include <asm/mach-ath79/ar933x_uart.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
#define DRIVER_NAME "ar933x-uart"
|
||||
|
||||
#define AR933X_UART_MAX_SCALE 0xff
|
||||
@@ -47,6 +50,8 @@ struct ar933x_uart_port {
|
||||
unsigned int min_baud;
|
||||
unsigned int max_baud;
|
||||
struct clk *clk;
|
||||
struct mctrl_gpios *gpios;
|
||||
struct gpio_desc *rts_gpiod;
|
||||
};
|
||||
|
||||
static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
|
||||
@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
}
|
||||
|
||||
static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up)
|
||||
{
|
||||
up->ier |= AR933X_UART_INT_RX_VALID;
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
}
|
||||
|
||||
static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up)
|
||||
{
|
||||
up->ier &= ~AR933X_UART_INT_RX_VALID;
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
}
|
||||
|
||||
static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
|
||||
{
|
||||
unsigned int rdata;
|
||||
@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
|
||||
|
||||
static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return TIOCM_CAR;
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
|
||||
mctrl_gpio_get(up->gpios, &ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
mctrl_gpio_set(up->gpios, mctrl);
|
||||
}
|
||||
|
||||
static void ar933x_uart_start_tx(struct uart_port *port)
|
||||
@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port)
|
||||
ar933x_uart_start_tx_interrupt(up);
|
||||
}
|
||||
|
||||
static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int timeout = 60000;
|
||||
|
||||
/* Wait up to 60ms for the character(s) to be sent. */
|
||||
do {
|
||||
status = ar933x_uart_read(up, AR933X_UART_CS_REG);
|
||||
if (--timeout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while (status & AR933X_UART_CS_TX_BUSY);
|
||||
|
||||
if (timeout == 0)
|
||||
dev_err(up->port.dev, "waiting for TX timed out\n");
|
||||
}
|
||||
|
||||
static void ar933x_uart_rx_flush(struct ar933x_uart_port *up)
|
||||
{
|
||||
unsigned int status;
|
||||
|
||||
/* clear RX_VALID interrupt */
|
||||
ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID);
|
||||
|
||||
/* remove characters from the RX FIFO */
|
||||
do {
|
||||
ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
|
||||
status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
|
||||
} while (status & AR933X_UART_DATA_RX_CSR);
|
||||
}
|
||||
|
||||
static void ar933x_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct ar933x_uart_port *up =
|
||||
@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port)
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
up->ier &= ~AR933X_UART_INT_RX_VALID;
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
ar933x_uart_stop_rx_interrupt(up);
|
||||
}
|
||||
|
||||
static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
|
||||
@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
|
||||
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
struct serial_rs485 *rs485conf = &up->port.rs485;
|
||||
int count;
|
||||
bool half_duplex_send = false;
|
||||
|
||||
if (uart_tx_stopped(&up->port))
|
||||
return;
|
||||
|
||||
if ((rs485conf->flags & SER_RS485_ENABLED) &&
|
||||
(up->port.x_char || !uart_circ_empty(xmit))) {
|
||||
ar933x_uart_stop_rx_interrupt(up);
|
||||
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
|
||||
half_duplex_send = true;
|
||||
}
|
||||
|
||||
count = up->port.fifosize;
|
||||
do {
|
||||
unsigned int rdata;
|
||||
@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
if (!uart_circ_empty(xmit))
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
ar933x_uart_start_tx_interrupt(up);
|
||||
} else if (half_duplex_send) {
|
||||
ar933x_uart_wait_tx_complete(up);
|
||||
ar933x_uart_rx_flush(up);
|
||||
ar933x_uart_start_rx_interrupt(up);
|
||||
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
|
||||
@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port)
|
||||
AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
|
||||
|
||||
/* Enable RX interrupts */
|
||||
up->ier = AR933X_UART_INT_RX_VALID;
|
||||
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
|
||||
ar933x_uart_start_rx_interrupt(up);
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = {
|
||||
.verify_port = ar933x_uart_verify_port,
|
||||
};
|
||||
|
||||
static int ar933x_config_rs485(struct uart_port *port,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
if ((rs485conf->flags & SER_RS485_ENABLED) &&
|
||||
!up->rts_gpiod) {
|
||||
dev_err(port->dev, "RS485 needs rts-gpio\n");
|
||||
return 1;
|
||||
}
|
||||
port->rs485 = *rs485conf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_AR933X_CONSOLE
|
||||
static struct ar933x_uart_port *
|
||||
ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
|
||||
@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
goto err_disable_clk;
|
||||
}
|
||||
|
||||
uart_get_rs485_mode(&pdev->dev, &port->rs485);
|
||||
|
||||
port->mapbase = mem_res->start;
|
||||
port->line = id;
|
||||
port->irq = irq_res->start;
|
||||
@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
port->regshift = 2;
|
||||
port->fifosize = AR933X_UART_FIFO_SIZE;
|
||||
port->ops = &ar933x_uart_ops;
|
||||
port->rs485_config = ar933x_config_rs485;
|
||||
|
||||
baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
|
||||
up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
|
||||
@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
|
||||
up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
|
||||
|
||||
up->gpios = mctrl_gpio_init(port, 0);
|
||||
if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS)
|
||||
return PTR_ERR(up->gpios);
|
||||
|
||||
up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
|
||||
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!up->rts_gpiod) {
|
||||
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_AR933X_CONSOLE
|
||||
ar933x_console_ports[up->port.line] = up;
|
||||
#endif
|
||||
|
@@ -20,15 +20,12 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/atmel_pdc.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/platform_data/atmel.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/suspend.h>
|
||||
@@ -2679,18 +2676,8 @@ static struct console atmel_console = {
|
||||
|
||||
#define ATMEL_CONSOLE_DEVICE (&atmel_console)
|
||||
|
||||
static inline bool atmel_is_console_port(struct uart_port *port)
|
||||
{
|
||||
return port->cons && port->cons->index == port->line;
|
||||
}
|
||||
|
||||
#else
|
||||
#define ATMEL_CONSOLE_DEVICE NULL
|
||||
|
||||
static inline bool atmel_is_console_port(struct uart_port *port)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct uart_driver atmel_uart = {
|
||||
@@ -2719,14 +2706,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (atmel_is_console_port(port) && console_suspend_enabled) {
|
||||
if (uart_console(port) && console_suspend_enabled) {
|
||||
/* Drain the TX shifter */
|
||||
while (!(atmel_uart_readl(port, ATMEL_US_CSR) &
|
||||
ATMEL_US_TXEMPTY))
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
if (atmel_is_console_port(port) && !console_suspend_enabled) {
|
||||
if (uart_console(port) && !console_suspend_enabled) {
|
||||
/* Cache register values as we won't get a full shutdown/startup
|
||||
* cycle
|
||||
*/
|
||||
@@ -2762,7 +2749,7 @@ static int atmel_serial_resume(struct platform_device *pdev)
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned long flags;
|
||||
|
||||
if (atmel_is_console_port(port) && !console_suspend_enabled) {
|
||||
if (uart_console(port) && !console_suspend_enabled) {
|
||||
atmel_uart_writel(port, ATMEL_US_MR, atmel_port->cache.mr);
|
||||
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->cache.imr);
|
||||
atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->cache.brgr);
|
||||
@@ -2916,7 +2903,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
goto err_add_port;
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||
if (atmel_is_console_port(&atmel_port->uart)
|
||||
if (uart_console(&atmel_port->uart)
|
||||
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
|
||||
/*
|
||||
* The serial core enabled the clock for us, so undo
|
||||
@@ -2959,7 +2946,7 @@ err_add_port:
|
||||
kfree(atmel_port->rx_ring.buf);
|
||||
atmel_port->rx_ring.buf = NULL;
|
||||
err_alloc_ring:
|
||||
if (!atmel_is_console_port(&atmel_port->uart)) {
|
||||
if (!uart_console(&atmel_port->uart)) {
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* include/linux/atmel_serial.h
|
||||
*
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Driver for CPM (SCC/SMC) serial ports
|
||||
*
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fs_uart_pd.h>
|
||||
|
||||
struct gpio_desc;
|
||||
|
||||
#if defined(CONFIG_CPM2)
|
||||
#include "cpm_uart_cpm2.h"
|
||||
#elif defined(CONFIG_CPM1)
|
||||
@@ -80,7 +82,7 @@ struct uart_cpm_port {
|
||||
int wait_closing;
|
||||
/* value to combine with opcode to form cpm command */
|
||||
u32 command;
|
||||
int gpios[NUM_GPIOS];
|
||||
struct gpio_desc *gpios[NUM_GPIOS];
|
||||
};
|
||||
|
||||
extern int cpm_uart_nr;
|
||||
|
@@ -30,8 +30,7 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@@ -88,11 +87,11 @@ static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
struct uart_cpm_port *pinfo =
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
|
||||
if (pinfo->gpios[GPIO_RTS] >= 0)
|
||||
gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
|
||||
if (pinfo->gpios[GPIO_RTS])
|
||||
gpiod_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
|
||||
|
||||
if (pinfo->gpios[GPIO_DTR] >= 0)
|
||||
gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
|
||||
if (pinfo->gpios[GPIO_DTR])
|
||||
gpiod_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
|
||||
}
|
||||
|
||||
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
|
||||
@@ -101,23 +100,23 @@ static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
|
||||
container_of(port, struct uart_cpm_port, port);
|
||||
unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
|
||||
if (pinfo->gpios[GPIO_CTS] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
|
||||
if (pinfo->gpios[GPIO_CTS]) {
|
||||
if (gpiod_get_value(pinfo->gpios[GPIO_CTS]))
|
||||
mctrl &= ~TIOCM_CTS;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_DSR] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
|
||||
if (pinfo->gpios[GPIO_DSR]) {
|
||||
if (gpiod_get_value(pinfo->gpios[GPIO_DSR]))
|
||||
mctrl &= ~TIOCM_DSR;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_DCD] >= 0) {
|
||||
if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
|
||||
if (pinfo->gpios[GPIO_DCD]) {
|
||||
if (gpiod_get_value(pinfo->gpios[GPIO_DCD]))
|
||||
mctrl &= ~TIOCM_CAR;
|
||||
}
|
||||
|
||||
if (pinfo->gpios[GPIO_RI] >= 0) {
|
||||
if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
|
||||
if (pinfo->gpios[GPIO_RI]) {
|
||||
if (!gpiod_get_value(pinfo->gpios[GPIO_RI]))
|
||||
mctrl |= TIOCM_RNG;
|
||||
}
|
||||
|
||||
@@ -1139,6 +1138,7 @@ static int cpm_uart_init_port(struct device_node *np,
|
||||
{
|
||||
const u32 *data;
|
||||
void __iomem *mem, *pram;
|
||||
struct device *dev = pinfo->port.dev;
|
||||
int len;
|
||||
int ret;
|
||||
int i;
|
||||
@@ -1211,29 +1211,23 @@ static int cpm_uart_init_port(struct device_node *np,
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_GPIOS; i++) {
|
||||
int gpio;
|
||||
struct gpio_desc *gpiod;
|
||||
|
||||
pinfo->gpios[i] = -1;
|
||||
pinfo->gpios[i] = NULL;
|
||||
|
||||
gpio = of_get_gpio(np, i);
|
||||
gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_ASIS);
|
||||
|
||||
if (gpio_is_valid(gpio)) {
|
||||
ret = gpio_request(gpio, "cpm_uart");
|
||||
if (ret) {
|
||||
pr_err("can't request gpio #%d: %d\n", i, ret);
|
||||
continue;
|
||||
}
|
||||
if (gpiod) {
|
||||
if (i == GPIO_RTS || i == GPIO_DTR)
|
||||
ret = gpio_direction_output(gpio, 0);
|
||||
ret = gpiod_direction_output(gpiod, 0);
|
||||
else
|
||||
ret = gpio_direction_input(gpio);
|
||||
ret = gpiod_direction_input(gpiod);
|
||||
if (ret) {
|
||||
pr_err("can't set direction for gpio #%d: %d\n",
|
||||
i, ret);
|
||||
gpio_free(gpio);
|
||||
continue;
|
||||
}
|
||||
pinfo->gpios[i] = gpio;
|
||||
pinfo->gpios[i] = gpiod;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -170,6 +170,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
|
||||
int __init setup_earlycon(char *buf)
|
||||
{
|
||||
const struct earlycon_id **p_match;
|
||||
bool empty_compatible = true;
|
||||
|
||||
if (!buf || !buf[0])
|
||||
return -EINVAL;
|
||||
@@ -177,6 +178,7 @@ int __init setup_earlycon(char *buf)
|
||||
if (early_con.flags & CON_ENABLED)
|
||||
return -EALREADY;
|
||||
|
||||
again:
|
||||
for (p_match = __earlycon_table; p_match < __earlycon_table_end;
|
||||
p_match++) {
|
||||
const struct earlycon_id *match = *p_match;
|
||||
@@ -185,6 +187,10 @@ int __init setup_earlycon(char *buf)
|
||||
if (strncmp(buf, match->name, len))
|
||||
continue;
|
||||
|
||||
/* prefer entries with empty compatible */
|
||||
if (empty_compatible && *match->compatible)
|
||||
continue;
|
||||
|
||||
if (buf[len]) {
|
||||
if (buf[len] != ',')
|
||||
continue;
|
||||
@@ -195,6 +201,11 @@ int __init setup_earlycon(char *buf)
|
||||
return register_earlycon(buf, match);
|
||||
}
|
||||
|
||||
if (empty_compatible) {
|
||||
empty_compatible = false;
|
||||
goto again;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
@@ -200,7 +200,7 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port)
|
||||
/*
|
||||
* This is a reserved bit and I only saw it read as 0. But to be
|
||||
* sure not to be confused too much by new devices adhere to the
|
||||
* warning in the reference manual that reserverd bits might
|
||||
* warning in the reference manual that reserved bits might
|
||||
* read as 1 in the future.
|
||||
*/
|
||||
rxdata &= ~SW_UARTn_RXDATAX_BERR;
|
||||
|
@@ -234,6 +234,7 @@ static DEFINE_IDA(fsl_lpuart_ida);
|
||||
enum lpuart_type {
|
||||
VF610_LPUART,
|
||||
LS1021A_LPUART,
|
||||
LS1028A_LPUART,
|
||||
IMX7ULP_LPUART,
|
||||
IMX8QXP_LPUART,
|
||||
};
|
||||
@@ -278,11 +279,16 @@ static const struct lpuart_soc_data vf_data = {
|
||||
.iotype = UPIO_MEM,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls_data = {
|
||||
static const struct lpuart_soc_data ls1021a_data = {
|
||||
.devtype = LS1021A_LPUART,
|
||||
.iotype = UPIO_MEM32BE,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls1028a_data = {
|
||||
.devtype = LS1028A_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx7ulp_data = {
|
||||
.devtype = IMX7ULP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
@@ -297,7 +303,8 @@ static struct lpuart_soc_data imx8qxp_data = {
|
||||
|
||||
static const struct of_device_id lpuart_dt_ids[] = {
|
||||
{ .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls_data, },
|
||||
{ .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, },
|
||||
{ .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
|
||||
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
|
||||
{ /* sentinel */ }
|
||||
@@ -307,6 +314,11 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
/* Forward declare this for the dma callbacks*/
|
||||
static void lpuart_dma_tx_complete(void *arg);
|
||||
|
||||
static inline bool is_ls1028a_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == LS1028A_LPUART;
|
||||
}
|
||||
|
||||
static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == IMX8QXP_LPUART;
|
||||
@@ -409,6 +421,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct scatterlist *sgl = sport->tx_sgl;
|
||||
struct device *dev = sport->port.dev;
|
||||
struct dma_chan *chan = sport->dma_tx_chan;
|
||||
int ret;
|
||||
|
||||
if (sport->dma_tx_in_progress)
|
||||
@@ -427,17 +440,19 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
sg_set_buf(sgl + 1, xmit->buf, xmit->head);
|
||||
}
|
||||
|
||||
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents,
|
||||
DMA_TO_DEVICE);
|
||||
if (!ret) {
|
||||
dev_err(dev, "DMA mapping error for TX.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl,
|
||||
sport->dma_tx_desc = dmaengine_prep_slave_sg(chan, sgl,
|
||||
ret, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT);
|
||||
if (!sport->dma_tx_desc) {
|
||||
dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
|
||||
DMA_TO_DEVICE);
|
||||
dev_err(dev, "Cannot prepare TX slave DMA!\n");
|
||||
return;
|
||||
}
|
||||
@@ -446,7 +461,7 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
|
||||
sport->dma_tx_desc->callback_param = sport;
|
||||
sport->dma_tx_in_progress = true;
|
||||
sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
|
||||
dma_async_issue_pending(sport->dma_tx_chan);
|
||||
dma_async_issue_pending(chan);
|
||||
}
|
||||
|
||||
static bool lpuart_stopped_or_empty(struct uart_port *port)
|
||||
@@ -459,11 +474,13 @@ static void lpuart_dma_tx_complete(void *arg)
|
||||
struct lpuart_port *sport = arg;
|
||||
struct scatterlist *sgl = &sport->tx_sgl[0];
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct dma_chan *chan = sport->dma_tx_chan;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
@@ -529,15 +546,16 @@ static bool lpuart_is_32(struct lpuart_port *sport)
|
||||
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;
|
||||
|
||||
if (sport->lpuart_dma_tx_use) {
|
||||
if (sport->dma_tx_in_progress) {
|
||||
dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0],
|
||||
dma_unmap_sg(chan->device->dev, &sport->tx_sgl[0],
|
||||
sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
sport->dma_tx_in_progress = false;
|
||||
}
|
||||
dmaengine_terminate_all(sport->dma_tx_chan);
|
||||
dmaengine_terminate_all(chan);
|
||||
}
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
@@ -993,6 +1011,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
enum dma_status dmastat;
|
||||
struct dma_chan *chan = sport->dma_rx_chan;
|
||||
struct circ_buf *ring = &sport->rx_ring;
|
||||
unsigned long flags;
|
||||
int count = 0;
|
||||
@@ -1053,10 +1072,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
dmastat = dmaengine_tx_status(sport->dma_rx_chan,
|
||||
sport->dma_rx_cookie,
|
||||
&state);
|
||||
|
||||
dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state);
|
||||
if (dmastat == DMA_ERROR) {
|
||||
dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@@ -1064,7 +1080,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
}
|
||||
|
||||
/* CPU claims ownership of RX DMA buffer */
|
||||
dma_sync_sg_for_cpu(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
|
||||
dma_sync_sg_for_cpu(chan->device->dev, &sport->rx_sgl, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
/*
|
||||
* ring->head points to the end of data already written by the DMA.
|
||||
@@ -1106,7 +1123,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
sport->port.icount.rx += count;
|
||||
}
|
||||
|
||||
dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1,
|
||||
dma_sync_sg_for_device(chan->device->dev, &sport->rx_sgl, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
@@ -1138,6 +1155,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
struct tty_struct *tty = port->tty;
|
||||
struct ktermios *termios = &tty->termios;
|
||||
struct dma_chan *chan = sport->dma_rx_chan;
|
||||
|
||||
baud = tty_get_baud_rate(tty);
|
||||
|
||||
@@ -1159,7 +1177,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
|
||||
nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
|
||||
nent = dma_map_sg(chan->device->dev, &sport->rx_sgl, 1,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
if (!nent) {
|
||||
dev_err(sport->port.dev, "DMA Rx mapping error\n");
|
||||
@@ -1170,7 +1189,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
||||
dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma_rx_sconfig.src_maxburst = 1;
|
||||
dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
|
||||
ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
|
||||
ret = dmaengine_slave_config(chan, &dma_rx_sconfig);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(sport->port.dev,
|
||||
@@ -1178,7 +1197,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
||||
return ret;
|
||||
}
|
||||
|
||||
sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan,
|
||||
sport->dma_rx_desc = dmaengine_prep_dma_cyclic(chan,
|
||||
sg_dma_address(&sport->rx_sgl),
|
||||
sport->rx_sgl.length,
|
||||
sport->rx_sgl.length / 2,
|
||||
@@ -1192,7 +1211,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
||||
sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
|
||||
sport->dma_rx_desc->callback_param = sport;
|
||||
sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
|
||||
dma_async_issue_pending(sport->dma_rx_chan);
|
||||
dma_async_issue_pending(chan);
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
@@ -1210,11 +1229,12 @@ static void lpuart_dma_rx_free(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
struct lpuart_port, port);
|
||||
struct dma_chan *chan = sport->dma_rx_chan;
|
||||
|
||||
if (sport->dma_rx_chan)
|
||||
dmaengine_terminate_all(sport->dma_rx_chan);
|
||||
if (chan)
|
||||
dmaengine_terminate_all(chan);
|
||||
|
||||
dma_unmap_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
|
||||
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
|
||||
kfree(sport->rx_ring.buf);
|
||||
sport->rx_ring.tail = 0;
|
||||
sport->rx_ring.head = 0;
|
||||
@@ -1490,39 +1510,77 @@ static void rx_dma_timer_init(struct lpuart_port *sport)
|
||||
add_timer(&sport->lpuart_timer);
|
||||
}
|
||||
|
||||
static void lpuart_request_dma(struct lpuart_port *sport)
|
||||
{
|
||||
sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx");
|
||||
if (IS_ERR(sport->dma_tx_chan)) {
|
||||
dev_info_once(sport->port.dev,
|
||||
"DMA tx channel request failed, operating without tx DMA (%ld)\n",
|
||||
PTR_ERR(sport->dma_tx_chan));
|
||||
sport->dma_tx_chan = NULL;
|
||||
}
|
||||
|
||||
sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx");
|
||||
if (IS_ERR(sport->dma_rx_chan)) {
|
||||
dev_info_once(sport->port.dev,
|
||||
"DMA rx channel request failed, operating without rx DMA (%ld)\n",
|
||||
PTR_ERR(sport->dma_rx_chan));
|
||||
sport->dma_rx_chan = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void lpuart_tx_dma_startup(struct lpuart_port *sport)
|
||||
{
|
||||
u32 uartbaud;
|
||||
int ret;
|
||||
|
||||
if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) {
|
||||
init_waitqueue_head(&sport->dma_wait);
|
||||
sport->lpuart_dma_tx_use = true;
|
||||
if (lpuart_is_32(sport)) {
|
||||
uartbaud = lpuart32_read(&sport->port, UARTBAUD);
|
||||
lpuart32_write(&sport->port,
|
||||
uartbaud | UARTBAUD_TDMAE, UARTBAUD);
|
||||
} else {
|
||||
writeb(readb(sport->port.membase + UARTCR5) |
|
||||
UARTCR5_TDMAS, sport->port.membase + UARTCR5);
|
||||
}
|
||||
if (!sport->dma_tx_chan)
|
||||
goto err;
|
||||
|
||||
ret = lpuart_dma_tx_request(&sport->port);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
init_waitqueue_head(&sport->dma_wait);
|
||||
sport->lpuart_dma_tx_use = true;
|
||||
if (lpuart_is_32(sport)) {
|
||||
uartbaud = lpuart32_read(&sport->port, UARTBAUD);
|
||||
lpuart32_write(&sport->port,
|
||||
uartbaud | UARTBAUD_TDMAE, UARTBAUD);
|
||||
} else {
|
||||
sport->lpuart_dma_tx_use = false;
|
||||
writeb(readb(sport->port.membase + UARTCR5) |
|
||||
UARTCR5_TDMAS, sport->port.membase + UARTCR5);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
sport->lpuart_dma_tx_use = false;
|
||||
}
|
||||
|
||||
static void lpuart_rx_dma_startup(struct lpuart_port *sport)
|
||||
{
|
||||
if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) {
|
||||
/* set Rx DMA timeout */
|
||||
sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
|
||||
if (!sport->dma_rx_timeout)
|
||||
sport->dma_rx_timeout = 1;
|
||||
int ret;
|
||||
|
||||
sport->lpuart_dma_rx_use = true;
|
||||
rx_dma_timer_init(sport);
|
||||
} else {
|
||||
sport->lpuart_dma_rx_use = false;
|
||||
}
|
||||
if (!sport->dma_rx_chan)
|
||||
goto err;
|
||||
|
||||
ret = lpuart_start_rx_dma(sport);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* set Rx DMA timeout */
|
||||
sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT);
|
||||
if (!sport->dma_rx_timeout)
|
||||
sport->dma_rx_timeout = 1;
|
||||
|
||||
sport->lpuart_dma_rx_use = true;
|
||||
rx_dma_timer_init(sport);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
sport->lpuart_dma_rx_use = false;
|
||||
}
|
||||
|
||||
static int lpuart_startup(struct uart_port *port)
|
||||
@@ -1541,6 +1599,8 @@ static int lpuart_startup(struct uart_port *port)
|
||||
sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
|
||||
UARTPFIFO_FIFOSIZE_MASK);
|
||||
|
||||
lpuart_request_dma(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart_setup_watermark_enable(sport);
|
||||
@@ -1587,11 +1647,23 @@ static int lpuart32_startup(struct uart_port *port)
|
||||
sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
|
||||
UARTFIFO_FIFOSIZE_MASK);
|
||||
|
||||
/*
|
||||
* The LS1028A has a fixed length of 16 words. Although it supports the
|
||||
* RX/TXSIZE fields their encoding is different. Eg the reference manual
|
||||
* states 0b101 is 16 words.
|
||||
*/
|
||||
if (is_ls1028a_lpuart(sport)) {
|
||||
sport->rxfifo_size = 16;
|
||||
sport->txfifo_size = 16;
|
||||
sport->port.fifosize = sport->txfifo_size;
|
||||
}
|
||||
|
||||
lpuart_request_dma(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
@@ -1615,6 +1687,11 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
|
||||
dmaengine_terminate_all(sport->dma_tx_chan);
|
||||
}
|
||||
}
|
||||
|
||||
if (sport->dma_tx_chan)
|
||||
dma_release_channel(sport->dma_tx_chan);
|
||||
if (sport->dma_rx_chan)
|
||||
dma_release_channel(sport->dma_rx_chan);
|
||||
}
|
||||
|
||||
static void lpuart_shutdown(struct uart_port *port)
|
||||
@@ -1811,11 +1888,12 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
||||
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 clk = sport->port.uartclk;
|
||||
u32 clk = port->uartclk;
|
||||
|
||||
/*
|
||||
* The idea is to use the best OSR (over-sampling rate) possible.
|
||||
@@ -1861,10 +1939,10 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
||||
|
||||
/* handle buadrate outside acceptable rate */
|
||||
if (baud_diff > ((baudrate / 100) * 3))
|
||||
dev_warn(sport->port.dev,
|
||||
dev_warn(port->dev,
|
||||
"unacceptable baud rate difference of more than 3%%\n");
|
||||
|
||||
tmp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
tmp = lpuart32_read(port, UARTBAUD);
|
||||
|
||||
if ((osr > 3) && (osr < 8))
|
||||
tmp |= UARTBAUD_BOTHEDGE;
|
||||
@@ -1875,14 +1953,23 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate)
|
||||
tmp &= ~UARTBAUD_SBR_MASK;
|
||||
tmp |= sbr & UARTBAUD_SBR_MASK;
|
||||
|
||||
if (!sport->lpuart_dma_rx_use)
|
||||
if (!use_rx_dma)
|
||||
tmp &= ~UARTBAUD_RDMAE;
|
||||
if (!sport->lpuart_dma_tx_use)
|
||||
if (!use_tx_dma)
|
||||
tmp &= ~UARTBAUD_TDMAE;
|
||||
|
||||
lpuart32_write(&sport->port, tmp, UARTBAUD);
|
||||
lpuart32_write(port, tmp, UARTBAUD);
|
||||
}
|
||||
|
||||
static void lpuart32_serial_setbrg(struct lpuart_port *sport,
|
||||
unsigned int baudrate)
|
||||
{
|
||||
__lpuart32_serial_setbrg(&sport->port, baudrate,
|
||||
sport->lpuart_dma_rx_use,
|
||||
sport->lpuart_dma_tx_use);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
@@ -2376,6 +2463,30 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init ls1028a_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
u32 cr;
|
||||
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
|
||||
device->port.iotype = UPIO_MEM32;
|
||||
device->con->write = lpuart32_early_write;
|
||||
|
||||
/* set the baudrate */
|
||||
if (device->port.uartclk && device->baud)
|
||||
__lpuart32_serial_setbrg(&device->port, device->baud,
|
||||
false, false);
|
||||
|
||||
/* enable transmitter */
|
||||
cr = lpuart32_read(&device->port, UARTCTRL);
|
||||
cr |= UARTCTRL_TE;
|
||||
lpuart32_write(&device->port, cr, UARTCTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init lpuart32_imx_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
@@ -2390,6 +2501,7 @@ static int __init lpuart32_imx_early_console_setup(struct earlycon_device *devic
|
||||
}
|
||||
OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup);
|
||||
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
|
||||
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);
|
||||
@@ -2520,16 +2632,6 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
|
||||
sport->port.rs485_config(&sport->port, &sport->port.rs485);
|
||||
|
||||
sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
|
||||
if (!sport->dma_tx_chan)
|
||||
dev_info(sport->port.dev, "DMA tx channel request failed, "
|
||||
"operating without tx DMA\n");
|
||||
|
||||
sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
|
||||
if (!sport->dma_rx_chan)
|
||||
dev_info(sport->port.dev, "DMA rx channel request failed, "
|
||||
"operating without rx DMA\n");
|
||||
|
||||
return 0;
|
||||
|
||||
failed_attach_port:
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* icom.h
|
||||
*
|
||||
|
@@ -39,7 +39,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/wait.h>
|
||||
@@ -61,7 +61,6 @@
|
||||
#define IFX_SPI_HEADER_F (-2)
|
||||
|
||||
#define PO_POST_DELAY 200
|
||||
#define IFX_MDM_RST_PMU 4
|
||||
|
||||
/* forward reference */
|
||||
static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev);
|
||||
@@ -81,7 +80,7 @@ static struct notifier_block ifx_modem_reboot_notifier_block = {
|
||||
|
||||
static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
gpio_set_value(IFX_MDM_RST_PMU, 1);
|
||||
gpiod_set_value(ifx_dev->gpio.pmu_reset, 1);
|
||||
msleep(PO_POST_DELAY);
|
||||
|
||||
return 0;
|
||||
@@ -107,7 +106,7 @@ static int ifx_modem_reboot_callback(struct notifier_block *nfb,
|
||||
*/
|
||||
static inline void mrdy_set_high(struct ifx_spi_device *ifx)
|
||||
{
|
||||
gpio_set_value(ifx->gpio.mrdy, 1);
|
||||
gpiod_set_value(ifx->gpio.mrdy, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +116,7 @@ static inline void mrdy_set_high(struct ifx_spi_device *ifx)
|
||||
*/
|
||||
static inline void mrdy_set_low(struct ifx_spi_device *ifx)
|
||||
{
|
||||
gpio_set_value(ifx->gpio.mrdy, 0);
|
||||
gpiod_set_value(ifx->gpio.mrdy, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -244,7 +243,7 @@ static inline void swap_buf_32(unsigned char *buf, int len, void *end)
|
||||
*/
|
||||
static void mrdy_assert(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
int val = gpio_get_value(ifx_dev->gpio.srdy);
|
||||
int val = gpiod_get_value(ifx_dev->gpio.srdy);
|
||||
if (!val) {
|
||||
if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING,
|
||||
&ifx_dev->flags)) {
|
||||
@@ -691,7 +690,7 @@ complete_exit:
|
||||
clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags));
|
||||
|
||||
queue_length = kfifo_len(&ifx_dev->tx_fifo);
|
||||
srdy = gpio_get_value(ifx_dev->gpio.srdy);
|
||||
srdy = gpiod_get_value(ifx_dev->gpio.srdy);
|
||||
if (!srdy)
|
||||
ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY);
|
||||
|
||||
@@ -898,7 +897,7 @@ static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev)
|
||||
static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
|
||||
{
|
||||
struct ifx_spi_device *ifx_dev = dev;
|
||||
int val = gpio_get_value(ifx_dev->gpio.reset_out);
|
||||
int val = gpiod_get_value(ifx_dev->gpio.reset_out);
|
||||
int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state);
|
||||
|
||||
if (val == 0) {
|
||||
@@ -954,14 +953,14 @@ static int ifx_spi_reset(struct ifx_spi_device *ifx_dev)
|
||||
* to reset properly
|
||||
*/
|
||||
set_bit(MR_START, &ifx_dev->mdm_reset_state);
|
||||
gpio_set_value(ifx_dev->gpio.po, 0);
|
||||
gpio_set_value(ifx_dev->gpio.reset, 0);
|
||||
gpiod_set_value(ifx_dev->gpio.po, 0);
|
||||
gpiod_set_value(ifx_dev->gpio.reset, 0);
|
||||
msleep(25);
|
||||
gpio_set_value(ifx_dev->gpio.reset, 1);
|
||||
gpiod_set_value(ifx_dev->gpio.reset, 1);
|
||||
msleep(1);
|
||||
gpio_set_value(ifx_dev->gpio.po, 1);
|
||||
gpiod_set_value(ifx_dev->gpio.po, 1);
|
||||
msleep(1);
|
||||
gpio_set_value(ifx_dev->gpio.po, 0);
|
||||
gpiod_set_value(ifx_dev->gpio.po, 0);
|
||||
ret = wait_event_timeout(ifx_dev->mdm_reset_wait,
|
||||
test_bit(MR_COMPLETE,
|
||||
&ifx_dev->mdm_reset_state),
|
||||
@@ -992,22 +991,23 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
int srdy;
|
||||
struct ifx_modem_platform_data *pl_data;
|
||||
struct ifx_spi_device *ifx_dev;
|
||||
struct device *dev = &spi->dev;
|
||||
|
||||
if (saved_ifx_dev) {
|
||||
dev_dbg(&spi->dev, "ignoring subsequent detection");
|
||||
dev_dbg(dev, "ignoring subsequent detection");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pl_data = dev_get_platdata(&spi->dev);
|
||||
pl_data = dev_get_platdata(dev);
|
||||
if (!pl_data) {
|
||||
dev_err(&spi->dev, "missing platform data!");
|
||||
dev_err(dev, "missing platform data!");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* initialize structure to hold our device variables */
|
||||
ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL);
|
||||
if (!ifx_dev) {
|
||||
dev_err(&spi->dev, "spi device allocation failed");
|
||||
dev_err(dev, "spi device allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
saved_ifx_dev = ifx_dev;
|
||||
@@ -1026,7 +1026,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
spi->bits_per_word = spi_bpw;
|
||||
ret = spi_setup(spi);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "SPI setup wasn't successful %d", ret);
|
||||
dev_err(dev, "SPI setup wasn't successful %d", ret);
|
||||
kfree(ifx_dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
&ifx_dev->tx_bus,
|
||||
GFP_KERNEL);
|
||||
if (!ifx_dev->tx_buffer) {
|
||||
dev_err(&spi->dev, "DMA-TX buffer allocation failed");
|
||||
dev_err(dev, "DMA-TX buffer allocation failed");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
@@ -1058,7 +1058,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
&ifx_dev->rx_bus,
|
||||
GFP_KERNEL);
|
||||
if (!ifx_dev->rx_buffer) {
|
||||
dev_err(&spi->dev, "DMA-RX buffer allocation failed");
|
||||
dev_err(dev, "DMA-RX buffer allocation failed");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
@@ -1075,122 +1075,83 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
/* create our tty port */
|
||||
ret = ifx_spi_create_port(ifx_dev);
|
||||
if (ret != 0) {
|
||||
dev_err(&spi->dev, "create default tty port failed");
|
||||
dev_err(dev, "create default tty port failed");
|
||||
goto error_ret;
|
||||
}
|
||||
|
||||
ifx_dev->gpio.reset = pl_data->rst_pmu;
|
||||
ifx_dev->gpio.po = pl_data->pwr_on;
|
||||
ifx_dev->gpio.mrdy = pl_data->mrdy;
|
||||
ifx_dev->gpio.srdy = pl_data->srdy;
|
||||
ifx_dev->gpio.reset_out = pl_data->rst_out;
|
||||
|
||||
dev_info(&spi->dev, "gpios %d, %d, %d, %d, %d",
|
||||
ifx_dev->gpio.reset, ifx_dev->gpio.po, ifx_dev->gpio.mrdy,
|
||||
ifx_dev->gpio.srdy, ifx_dev->gpio.reset_out);
|
||||
|
||||
/* Configure gpios */
|
||||
ret = gpio_request(ifx_dev->gpio.reset, "ifxModem");
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET)",
|
||||
ifx_dev->gpio.reset);
|
||||
ifx_dev->gpio.reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ifx_dev->gpio.reset)) {
|
||||
dev_err(dev, "could not obtain reset GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.reset);
|
||||
goto error_ret;
|
||||
}
|
||||
ret += gpio_direction_output(ifx_dev->gpio.reset, 0);
|
||||
ret += gpio_export(ifx_dev->gpio.reset, 1);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to configure GPIO%d (RESET)",
|
||||
ifx_dev->gpio.reset);
|
||||
ret = -EBUSY;
|
||||
goto error_ret2;
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.reset, "ifxModem reset");
|
||||
ifx_dev->gpio.po = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ifx_dev->gpio.po)) {
|
||||
dev_err(dev, "could not obtain power GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.po);
|
||||
goto error_ret;
|
||||
}
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.po, "ifxModem power");
|
||||
ifx_dev->gpio.mrdy = devm_gpiod_get(dev, "mrdy", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(ifx_dev->gpio.mrdy)) {
|
||||
dev_err(dev, "could not obtain mrdy GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.mrdy);
|
||||
goto error_ret;
|
||||
}
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.mrdy, "ifxModem mrdy");
|
||||
ifx_dev->gpio.srdy = devm_gpiod_get(dev, "srdy", GPIOD_IN);
|
||||
if (IS_ERR(ifx_dev->gpio.srdy)) {
|
||||
dev_err(dev, "could not obtain srdy GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.srdy);
|
||||
goto error_ret;
|
||||
}
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.srdy, "ifxModem srdy");
|
||||
ifx_dev->gpio.reset_out = devm_gpiod_get(dev, "rst_out", GPIOD_IN);
|
||||
if (IS_ERR(ifx_dev->gpio.reset_out)) {
|
||||
dev_err(dev, "could not obtain rst_out GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.reset_out);
|
||||
goto error_ret;
|
||||
}
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.reset_out, "ifxModem reset out");
|
||||
ifx_dev->gpio.pmu_reset = devm_gpiod_get(dev, "pmu_reset", GPIOD_ASIS);
|
||||
if (IS_ERR(ifx_dev->gpio.pmu_reset)) {
|
||||
dev_err(dev, "could not obtain pmu_reset GPIO\n");
|
||||
ret = PTR_ERR(ifx_dev->gpio.pmu_reset);
|
||||
goto error_ret;
|
||||
}
|
||||
gpiod_set_consumer_name(ifx_dev->gpio.pmu_reset, "ifxModem PMU reset");
|
||||
|
||||
ret = gpio_request(ifx_dev->gpio.po, "ifxModem");
|
||||
ret += gpio_direction_output(ifx_dev->gpio.po, 0);
|
||||
ret += gpio_export(ifx_dev->gpio.po, 1);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to configure GPIO%d (ON)",
|
||||
ifx_dev->gpio.po);
|
||||
ret = -EBUSY;
|
||||
goto error_ret3;
|
||||
}
|
||||
|
||||
ret = gpio_request(ifx_dev->gpio.mrdy, "ifxModem");
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to allocate GPIO%d (MRDY)",
|
||||
ifx_dev->gpio.mrdy);
|
||||
goto error_ret3;
|
||||
}
|
||||
ret += gpio_export(ifx_dev->gpio.mrdy, 1);
|
||||
ret += gpio_direction_output(ifx_dev->gpio.mrdy, 0);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to configure GPIO%d (MRDY)",
|
||||
ifx_dev->gpio.mrdy);
|
||||
ret = -EBUSY;
|
||||
goto error_ret4;
|
||||
}
|
||||
|
||||
ret = gpio_request(ifx_dev->gpio.srdy, "ifxModem");
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to allocate GPIO%d (SRDY)",
|
||||
ifx_dev->gpio.srdy);
|
||||
ret = -EBUSY;
|
||||
goto error_ret4;
|
||||
}
|
||||
ret += gpio_export(ifx_dev->gpio.srdy, 1);
|
||||
ret += gpio_direction_input(ifx_dev->gpio.srdy);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to configure GPIO%d (SRDY)",
|
||||
ifx_dev->gpio.srdy);
|
||||
ret = -EBUSY;
|
||||
goto error_ret5;
|
||||
}
|
||||
|
||||
ret = gpio_request(ifx_dev->gpio.reset_out, "ifxModem");
|
||||
if (ret < 0) {
|
||||
dev_err(&spi->dev, "Unable to allocate GPIO%d (RESET_OUT)",
|
||||
ifx_dev->gpio.reset_out);
|
||||
goto error_ret5;
|
||||
}
|
||||
ret += gpio_export(ifx_dev->gpio.reset_out, 1);
|
||||
ret += gpio_direction_input(ifx_dev->gpio.reset_out);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to configure GPIO%d (RESET_OUT)",
|
||||
ifx_dev->gpio.reset_out);
|
||||
ret = -EBUSY;
|
||||
goto error_ret6;
|
||||
}
|
||||
|
||||
ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out),
|
||||
ret = request_irq(gpiod_to_irq(ifx_dev->gpio.reset_out),
|
||||
ifx_spi_reset_interrupt,
|
||||
IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME,
|
||||
ifx_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to get irq %x\n",
|
||||
gpio_to_irq(ifx_dev->gpio.reset_out));
|
||||
goto error_ret6;
|
||||
dev_err(dev, "Unable to get irq %x\n",
|
||||
gpiod_to_irq(ifx_dev->gpio.reset_out));
|
||||
goto error_ret;
|
||||
}
|
||||
|
||||
ret = ifx_spi_reset(ifx_dev);
|
||||
|
||||
ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy),
|
||||
ret = request_irq(gpiod_to_irq(ifx_dev->gpio.srdy),
|
||||
ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME,
|
||||
ifx_dev);
|
||||
if (ret) {
|
||||
dev_err(&spi->dev, "Unable to get irq %x",
|
||||
gpio_to_irq(ifx_dev->gpio.srdy));
|
||||
goto error_ret7;
|
||||
dev_err(dev, "Unable to get irq %x",
|
||||
gpiod_to_irq(ifx_dev->gpio.srdy));
|
||||
goto error_ret2;
|
||||
}
|
||||
|
||||
/* set pm runtime power state and register with power system */
|
||||
pm_runtime_set_active(&spi->dev);
|
||||
pm_runtime_enable(&spi->dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
|
||||
/* handle case that modem is already signaling SRDY */
|
||||
/* no outgoing tty open at this point, this just satisfies the
|
||||
* modem's read and should reset communication properly
|
||||
*/
|
||||
srdy = gpio_get_value(ifx_dev->gpio.srdy);
|
||||
srdy = gpiod_get_value(ifx_dev->gpio.srdy);
|
||||
|
||||
if (srdy) {
|
||||
mrdy_assert(ifx_dev);
|
||||
@@ -1199,18 +1160,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi)
|
||||
mrdy_set_low(ifx_dev);
|
||||
return 0;
|
||||
|
||||
error_ret7:
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
error_ret6:
|
||||
gpio_free(ifx_dev->gpio.srdy);
|
||||
error_ret5:
|
||||
gpio_free(ifx_dev->gpio.mrdy);
|
||||
error_ret4:
|
||||
gpio_free(ifx_dev->gpio.reset);
|
||||
error_ret3:
|
||||
gpio_free(ifx_dev->gpio.po);
|
||||
error_ret2:
|
||||
gpio_free(ifx_dev->gpio.reset_out);
|
||||
free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
error_ret:
|
||||
ifx_spi_free_device(ifx_dev);
|
||||
saved_ifx_dev = NULL;
|
||||
@@ -1234,14 +1185,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi)
|
||||
pm_runtime_disable(&spi->dev);
|
||||
|
||||
/* free irq */
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev);
|
||||
|
||||
gpio_free(ifx_dev->gpio.srdy);
|
||||
gpio_free(ifx_dev->gpio.mrdy);
|
||||
gpio_free(ifx_dev->gpio.reset);
|
||||
gpio_free(ifx_dev->gpio.po);
|
||||
gpio_free(ifx_dev->gpio.reset_out);
|
||||
free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev);
|
||||
free_irq(gpiod_to_irq(ifx_dev->gpio.srdy), ifx_dev);
|
||||
|
||||
/* free allocations */
|
||||
ifx_spi_free_device(ifx_dev);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/****************************************************************************
|
||||
*
|
||||
* Driver for the IFX spi modem.
|
||||
@@ -10,6 +10,8 @@
|
||||
#ifndef _IFX6X60_H
|
||||
#define _IFX6X60_H
|
||||
|
||||
struct gpio_desc;
|
||||
|
||||
#define DRVNAME "ifx6x60"
|
||||
#define TTYNAME "ttyIFX"
|
||||
|
||||
@@ -94,11 +96,12 @@ struct ifx_spi_device {
|
||||
|
||||
struct {
|
||||
/* gpio lines */
|
||||
unsigned short srdy; /* slave-ready gpio */
|
||||
unsigned short mrdy; /* master-ready gpio */
|
||||
unsigned short reset; /* modem-reset gpio */
|
||||
unsigned short po; /* modem-on gpio */
|
||||
unsigned short reset_out; /* modem-in-reset gpio */
|
||||
struct gpio_desc *srdy; /* slave-ready gpio */
|
||||
struct gpio_desc *mrdy; /* master-ready gpio */
|
||||
struct gpio_desc *reset; /* modem-reset gpio */
|
||||
struct gpio_desc *po; /* modem-on gpio */
|
||||
struct gpio_desc *reset_out; /* modem-in-reset gpio */
|
||||
struct gpio_desc *pmu_reset; /* PMU reset gpio */
|
||||
/* state/stats */
|
||||
int unack_srdy_int_nb;
|
||||
} gpio;
|
||||
|
@@ -195,6 +195,8 @@ struct imx_port {
|
||||
unsigned int have_rtscts:1;
|
||||
unsigned int have_rtsgpio:1;
|
||||
unsigned int dte_mode:1;
|
||||
unsigned int inverted_tx:1;
|
||||
unsigned int inverted_rx:1;
|
||||
struct clk *clk_ipg;
|
||||
struct clk *clk_per;
|
||||
const struct imx_uart_data *devdata;
|
||||
@@ -1335,7 +1337,7 @@ static int imx_uart_startup(struct uart_port *port)
|
||||
int retval, i;
|
||||
unsigned long flags;
|
||||
int dma_is_inited = 0;
|
||||
u32 ucr1, ucr2, ucr4;
|
||||
u32 ucr1, ucr2, ucr3, ucr4;
|
||||
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
if (retval)
|
||||
@@ -1387,11 +1389,29 @@ static int imx_uart_startup(struct uart_port *port)
|
||||
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
ucr4 = imx_uart_readl(sport, UCR4) & ~UCR4_OREN;
|
||||
ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR);
|
||||
if (!sport->dma_is_enabled)
|
||||
ucr4 |= UCR4_OREN;
|
||||
if (sport->inverted_rx)
|
||||
ucr4 |= UCR4_INVR;
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
|
||||
ucr3 = imx_uart_readl(sport, UCR3) & ~UCR3_INVT;
|
||||
/*
|
||||
* configure tx polarity before enabling tx
|
||||
*/
|
||||
if (sport->inverted_tx)
|
||||
ucr3 |= UCR3_INVT;
|
||||
|
||||
if (!imx_uart_is_imx1(sport)) {
|
||||
ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
|
||||
|
||||
if (sport->dte_mode)
|
||||
/* disable broken interrupts */
|
||||
ucr3 &= ~(UCR3_RI | UCR3_DCD);
|
||||
}
|
||||
imx_uart_writel(sport, ucr3, UCR3);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN;
|
||||
ucr2 |= (UCR2_RXEN | UCR2_TXEN);
|
||||
if (!sport->have_rtscts)
|
||||
@@ -1404,20 +1424,6 @@ static int imx_uart_startup(struct uart_port *port)
|
||||
ucr2 &= ~UCR2_RTSEN;
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
if (!imx_uart_is_imx1(sport)) {
|
||||
u32 ucr3;
|
||||
|
||||
ucr3 = imx_uart_readl(sport, UCR3);
|
||||
|
||||
ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD;
|
||||
|
||||
if (sport->dte_mode)
|
||||
/* disable broken interrupts */
|
||||
ucr3 &= ~(UCR3_RI | UCR3_DCD);
|
||||
|
||||
imx_uart_writel(sport, ucr3, UCR3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable modem status interrupts
|
||||
*/
|
||||
@@ -2184,6 +2190,12 @@ static int imx_uart_probe_dt(struct imx_port *sport,
|
||||
if (of_get_property(np, "rts-gpios", NULL))
|
||||
sport->have_rtsgpio = 1;
|
||||
|
||||
if (of_get_property(np, "fsl,inverted-tx", NULL))
|
||||
sport->inverted_tx = 1;
|
||||
|
||||
if (of_get_property(np, "fsl,inverted-rx", NULL))
|
||||
sport->inverted_rx = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/************************************************************************
|
||||
* Copyright 2003 Digi International (www.digi.com)
|
||||
*
|
||||
|
@@ -169,15 +169,13 @@ static int configure_kgdboc(void)
|
||||
if (!p)
|
||||
goto noconfig;
|
||||
|
||||
cons = console_drivers;
|
||||
while (cons) {
|
||||
for_each_console(cons) {
|
||||
int idx;
|
||||
if (cons->device && cons->device(cons, &idx) == p &&
|
||||
idx == tty_line) {
|
||||
kgdboc_io_ops.is_console = 1;
|
||||
break;
|
||||
}
|
||||
cons = cons->next;
|
||||
}
|
||||
|
||||
kgdb_tty_driver = p;
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
|
@@ -37,8 +37,6 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_data/serial-omap.h>
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
#define OMAP_MAX_HSUART_PORTS 10
|
||||
|
||||
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
|
||||
|
@@ -310,32 +310,32 @@ static ssize_t port_show_regs(struct file *file, char __user *user_buf,
|
||||
if (!buf)
|
||||
return 0;
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"PCH EG20T port[%d] regs:\n", priv->port.line);
|
||||
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"=================================\n");
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IER: \t0x%02x\n", ioread8(priv->membase + UART_IER));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"IIR: \t0x%02x\n", ioread8(priv->membase + UART_IIR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LCR: \t0x%02x\n", ioread8(priv->membase + UART_LCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MCR: \t0x%02x\n", ioread8(priv->membase + UART_MCR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"LSR: \t0x%02x\n", ioread8(priv->membase + UART_LSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"MSR: \t0x%02x\n", ioread8(priv->membase + UART_MSR));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"BRCSR: \t0x%02x\n",
|
||||
ioread8(priv->membase + PCH_UART_BRCSR));
|
||||
|
||||
lcr = ioread8(priv->membase + UART_LCR);
|
||||
iowrite8(PCH_UART_LCR_DLAB, priv->membase + UART_LCR);
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLL: \t0x%02x\n", ioread8(priv->membase + UART_DLL));
|
||||
len += snprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
len += scnprintf(buf + len, PCH_REGS_BUFSIZE - len,
|
||||
"DLM: \t0x%02x\n", ioread8(priv->membase + UART_DLM));
|
||||
iowrite8(lcr, priv->membase + UART_LCR);
|
||||
|
||||
|
@@ -768,11 +768,6 @@ static int __init pic32_console_init(void)
|
||||
}
|
||||
console_initcall(pic32_console_init);
|
||||
|
||||
static inline bool is_pic32_console_port(struct uart_port *port)
|
||||
{
|
||||
return port->cons && port->cons->index == port->line;
|
||||
}
|
||||
|
||||
/*
|
||||
* Late console initialization.
|
||||
*/
|
||||
@@ -873,8 +868,7 @@ static int pic32_uart_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_PIC32_CONSOLE
|
||||
if (is_pic32_console_port(port) &&
|
||||
(pic32_console.flags & CON_ENABLED)) {
|
||||
if (uart_console(port) && (pic32_console.flags & CON_ENABLED)) {
|
||||
/* The peripheral clock has been enabled by console_setup,
|
||||
* so disable it till the port is used.
|
||||
*/
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* PIC32 Integrated Serial Driver.
|
||||
*
|
||||
|
@@ -21,6 +21,7 @@
|
||||
|
||||
/* UART specific GENI registers */
|
||||
#define SE_UART_LOOPBACK_CFG 0x22c
|
||||
#define SE_UART_IO_MACRO_CTRL 0x240
|
||||
#define SE_UART_TX_TRANS_CFG 0x25c
|
||||
#define SE_UART_TX_WORD_LEN 0x268
|
||||
#define SE_UART_TX_STOP_BIT_LEN 0x26c
|
||||
@@ -95,6 +96,12 @@
|
||||
#define CTS_RTS_SORTED BIT(1)
|
||||
#define RX_TX_CTS_RTS_SORTED (RX_TX_SORTED | CTS_RTS_SORTED)
|
||||
|
||||
/* UART pin swap value */
|
||||
#define DEFAULT_IO_MACRO_IO0_IO1_MASK GENMASK(3, 0)
|
||||
#define IO_MACRO_IO0_SEL 0x3
|
||||
#define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4)
|
||||
#define IO_MACRO_IO2_IO3_SWAP 0x4640
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#define CONSOLE_RX_BYTES_PW 1
|
||||
#else
|
||||
@@ -113,12 +120,14 @@ struct qcom_geni_serial_port {
|
||||
unsigned int baud;
|
||||
unsigned int tx_bytes_pw;
|
||||
unsigned int rx_bytes_pw;
|
||||
u32 *rx_fifo;
|
||||
void *rx_fifo;
|
||||
u32 loopback;
|
||||
bool brk;
|
||||
|
||||
unsigned int tx_remaining;
|
||||
int wakeup_irq;
|
||||
bool rx_tx_swap;
|
||||
bool cts_rts_swap;
|
||||
};
|
||||
|
||||
static const struct uart_ops qcom_geni_console_pops;
|
||||
@@ -505,7 +514,6 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
|
||||
|
||||
static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
||||
{
|
||||
unsigned char *buf;
|
||||
struct tty_port *tport;
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
|
||||
u32 num_bytes_pw = port->tx_fifo_width / BITS_PER_BYTE;
|
||||
@@ -517,8 +525,7 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
|
||||
if (drop)
|
||||
return 0;
|
||||
|
||||
buf = (unsigned char *)port->rx_fifo;
|
||||
ret = tty_insert_flip_string(tport, buf, bytes);
|
||||
ret = tty_insert_flip_string(tport, port->rx_fifo, bytes);
|
||||
if (ret != bytes) {
|
||||
dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
|
||||
__func__, ret, bytes);
|
||||
@@ -818,17 +825,7 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port)
|
||||
|
||||
static void qcom_geni_serial_shutdown(struct uart_port *uport)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
/* Stop the console before stopping the current tx */
|
||||
if (uart_console(uport))
|
||||
console_stop(uport->cons);
|
||||
|
||||
disable_irq(uport->irq);
|
||||
spin_lock_irqsave(&uport->lock, flags);
|
||||
qcom_geni_serial_stop_tx(uport);
|
||||
qcom_geni_serial_stop_rx(uport);
|
||||
spin_unlock_irqrestore(&uport->lock, flags);
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
||||
@@ -836,6 +833,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
||||
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
|
||||
u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
|
||||
u32 proto;
|
||||
u32 pin_swap;
|
||||
|
||||
if (uart_console(uport)) {
|
||||
port->tx_bytes_pw = 1;
|
||||
@@ -856,6 +854,20 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
||||
get_tx_fifo_size(port);
|
||||
|
||||
writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
|
||||
|
||||
pin_swap = readl(uport->membase + SE_UART_IO_MACRO_CTRL);
|
||||
if (port->rx_tx_swap) {
|
||||
pin_swap &= ~DEFAULT_IO_MACRO_IO2_IO3_MASK;
|
||||
pin_swap |= IO_MACRO_IO2_IO3_SWAP;
|
||||
}
|
||||
if (port->cts_rts_swap) {
|
||||
pin_swap &= ~DEFAULT_IO_MACRO_IO0_IO1_MASK;
|
||||
pin_swap |= IO_MACRO_IO0_SEL;
|
||||
}
|
||||
/* Configure this register if RX-TX, CTS-RTS pins are swapped */
|
||||
if (port->rx_tx_swap || port->cts_rts_swap)
|
||||
writel(pin_swap, uport->membase + SE_UART_IO_MACRO_CTRL);
|
||||
|
||||
/*
|
||||
* Make an unconditional cancel on the main sequencer to reset
|
||||
* it else we could end up in data loss scenarios.
|
||||
@@ -868,12 +880,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
||||
false, false, true);
|
||||
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
||||
geni_se_select_mode(&port->se, GENI_SE_FIFO);
|
||||
if (!uart_console(uport)) {
|
||||
port->rx_fifo = devm_kcalloc(uport->dev,
|
||||
port->rx_fifo_depth, sizeof(u32), GFP_KERNEL);
|
||||
if (!port->rx_fifo)
|
||||
return -ENOMEM;
|
||||
}
|
||||
port->setup = true;
|
||||
|
||||
return 0;
|
||||
@@ -1284,6 +1290,13 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
|
||||
port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
|
||||
|
||||
if (!console) {
|
||||
port->rx_fifo = devm_kcalloc(uport->dev,
|
||||
port->rx_fifo_depth, sizeof(u32), GFP_KERNEL);
|
||||
if (!port->rx_fifo)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
port->name = devm_kasprintf(uport->dev, GFP_KERNEL,
|
||||
"qcom_geni_serial_%s%d",
|
||||
uart_console(uport) ? "console" : "uart", uport->line);
|
||||
@@ -1299,6 +1312,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
if (!console)
|
||||
port->wakeup_irq = platform_get_irq_optional(pdev, 1);
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "rx-tx-swap"))
|
||||
port->rx_tx_swap = true;
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
|
||||
port->cts_rts_swap = true;
|
||||
|
||||
uport->private_data = drv;
|
||||
platform_set_drvdata(pdev, port);
|
||||
port->handle_rx = console ? handle_rx_console : handle_rx_uart;
|
||||
|
@@ -329,7 +329,7 @@ struct sc16is7xx_port {
|
||||
struct task_struct *kworker_task;
|
||||
struct kthread_work irq_work;
|
||||
struct mutex efr_lock;
|
||||
struct sc16is7xx_one p[0];
|
||||
struct sc16is7xx_one p[];
|
||||
};
|
||||
|
||||
static unsigned long sc16is7xx_lines;
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/security.h>
|
||||
@@ -40,6 +41,8 @@ static struct lock_class_key port_lock_key;
|
||||
|
||||
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
|
||||
|
||||
#define SYSRQ_TIMEOUT (HZ * 5)
|
||||
|
||||
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
|
||||
struct ktermios *old_termios);
|
||||
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
|
||||
@@ -1908,6 +1911,24 @@ static int uart_proc_show(struct seq_file *m, void *v)
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline bool uart_console_enabled(struct uart_port *port)
|
||||
{
|
||||
return uart_console(port) && (port->cons->flags & CON_ENABLED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure that the serial console lock is initialised early.
|
||||
* If this port is a console, then the spinlock is already initialised.
|
||||
*/
|
||||
static inline void uart_port_spin_lock_init(struct uart_port *port)
|
||||
{
|
||||
if (uart_console(port))
|
||||
return;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
lockdep_set_class(&port->lock, &port_lock_key);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
|
||||
/**
|
||||
* uart_console_write - write a console message to a serial port
|
||||
@@ -2060,16 +2081,7 @@ uart_set_options(struct uart_port *port, struct console *co,
|
||||
struct ktermios termios;
|
||||
static struct ktermios dummy;
|
||||
|
||||
/*
|
||||
* Ensure that the serial console lock is initialised
|
||||
* early.
|
||||
* If this port is a console, then the spinlock is already
|
||||
* initialised.
|
||||
*/
|
||||
if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
|
||||
spin_lock_init(&port->lock);
|
||||
lockdep_set_class(&port->lock, &port_lock_key);
|
||||
}
|
||||
uart_port_spin_lock_init(port);
|
||||
|
||||
memset(&termios, 0, sizeof(struct ktermios));
|
||||
|
||||
@@ -2605,7 +2617,7 @@ struct tty_driver *uart_console_device(struct console *co, int *index)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_console_device);
|
||||
|
||||
static ssize_t uart_get_attr_uartclk(struct device *dev,
|
||||
static ssize_t uartclk_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2615,7 +2627,7 @@ static ssize_t uart_get_attr_uartclk(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_type(struct device *dev,
|
||||
static ssize_t type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2624,7 +2636,8 @@ static ssize_t uart_get_attr_type(struct device *dev,
|
||||
uart_get_info(port, &tmp);
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type);
|
||||
}
|
||||
static ssize_t uart_get_attr_line(struct device *dev,
|
||||
|
||||
static ssize_t line_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2634,7 +2647,7 @@ static ssize_t uart_get_attr_line(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_port(struct device *dev,
|
||||
static ssize_t port_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2648,7 +2661,7 @@ static ssize_t uart_get_attr_port(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_irq(struct device *dev,
|
||||
static ssize_t irq_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2658,7 +2671,7 @@ static ssize_t uart_get_attr_irq(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_flags(struct device *dev,
|
||||
static ssize_t flags_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2668,7 +2681,7 @@ static ssize_t uart_get_attr_flags(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev,
|
||||
static ssize_t xmit_fifo_size_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2678,8 +2691,7 @@ static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uart_get_attr_close_delay(struct device *dev,
|
||||
static ssize_t close_delay_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2689,8 +2701,7 @@ static ssize_t uart_get_attr_close_delay(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay);
|
||||
}
|
||||
|
||||
|
||||
static ssize_t uart_get_attr_closing_wait(struct device *dev,
|
||||
static ssize_t closing_wait_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2700,7 +2711,7 @@ static ssize_t uart_get_attr_closing_wait(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_custom_divisor(struct device *dev,
|
||||
static ssize_t custom_divisor_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2710,7 +2721,7 @@ static ssize_t uart_get_attr_custom_divisor(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_io_type(struct device *dev,
|
||||
static ssize_t io_type_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2720,7 +2731,7 @@ static ssize_t uart_get_attr_io_type(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_iomem_base(struct device *dev,
|
||||
static ssize_t iomem_base_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2730,7 +2741,7 @@ static ssize_t uart_get_attr_iomem_base(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base);
|
||||
}
|
||||
|
||||
static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev,
|
||||
static ssize_t iomem_reg_shift_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct serial_struct tmp;
|
||||
@@ -2740,40 +2751,92 @@ static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL);
|
||||
static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL);
|
||||
static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL);
|
||||
static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL);
|
||||
static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL);
|
||||
static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL);
|
||||
static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL);
|
||||
static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL);
|
||||
static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL);
|
||||
static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL);
|
||||
static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL);
|
||||
static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL);
|
||||
static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL);
|
||||
static ssize_t console_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct tty_port *port = dev_get_drvdata(dev);
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
bool console = false;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
uport = uart_port_check(state);
|
||||
if (uport)
|
||||
console = uart_console_enabled(uport);
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
return sprintf(buf, "%c\n", console ? 'Y' : 'N');
|
||||
}
|
||||
|
||||
static ssize_t console_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct tty_port *port = dev_get_drvdata(dev);
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
bool oldconsole, newconsole;
|
||||
int ret;
|
||||
|
||||
ret = kstrtobool(buf, &newconsole);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
uport = uart_port_check(state);
|
||||
if (uport) {
|
||||
oldconsole = uart_console_enabled(uport);
|
||||
if (oldconsole && !newconsole) {
|
||||
ret = unregister_console(uport->cons);
|
||||
} else if (!oldconsole && newconsole) {
|
||||
if (uart_console(uport))
|
||||
register_console(uport->cons);
|
||||
else
|
||||
ret = -ENOENT;
|
||||
}
|
||||
} else {
|
||||
ret = -ENXIO;
|
||||
}
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
return ret < 0 ? ret : count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(uartclk);
|
||||
static DEVICE_ATTR_RO(type);
|
||||
static DEVICE_ATTR_RO(line);
|
||||
static DEVICE_ATTR_RO(port);
|
||||
static DEVICE_ATTR_RO(irq);
|
||||
static DEVICE_ATTR_RO(flags);
|
||||
static DEVICE_ATTR_RO(xmit_fifo_size);
|
||||
static DEVICE_ATTR_RO(close_delay);
|
||||
static DEVICE_ATTR_RO(closing_wait);
|
||||
static DEVICE_ATTR_RO(custom_divisor);
|
||||
static DEVICE_ATTR_RO(io_type);
|
||||
static DEVICE_ATTR_RO(iomem_base);
|
||||
static DEVICE_ATTR_RO(iomem_reg_shift);
|
||||
static DEVICE_ATTR_RW(console);
|
||||
|
||||
static struct attribute *tty_dev_attrs[] = {
|
||||
&dev_attr_uartclk.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_line.attr,
|
||||
&dev_attr_port.attr,
|
||||
&dev_attr_irq.attr,
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_xmit_fifo_size.attr,
|
||||
&dev_attr_uartclk.attr,
|
||||
&dev_attr_close_delay.attr,
|
||||
&dev_attr_closing_wait.attr,
|
||||
&dev_attr_custom_divisor.attr,
|
||||
&dev_attr_io_type.attr,
|
||||
&dev_attr_iomem_base.attr,
|
||||
&dev_attr_iomem_reg_shift.attr,
|
||||
NULL,
|
||||
};
|
||||
&dev_attr_console.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tty_dev_attr_group = {
|
||||
.attrs = tty_dev_attrs,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* uart_add_one_port - attach a driver-defined port structure
|
||||
@@ -2824,14 +2887,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this port is a console, then the spinlock is already
|
||||
* initialised.
|
||||
*/
|
||||
if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
|
||||
spin_lock_init(&uport->lock);
|
||||
lockdep_set_class(&uport->lock, &port_lock_key);
|
||||
}
|
||||
uart_port_spin_lock_init(uport);
|
||||
|
||||
if (uport->cons && uport->dev)
|
||||
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
|
||||
|
||||
@@ -3082,6 +3139,60 @@ void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_insert_char);
|
||||
|
||||
#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
|
||||
static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE;
|
||||
|
||||
static void uart_sysrq_on(struct work_struct *w)
|
||||
{
|
||||
int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq);
|
||||
|
||||
sysrq_toggle_support(1);
|
||||
pr_info("SysRq is enabled by magic sequence '%*pE' on serial\n",
|
||||
sysrq_toggle_seq_len, sysrq_toggle_seq);
|
||||
}
|
||||
static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
|
||||
|
||||
/**
|
||||
* uart_try_toggle_sysrq - Enables SysRq from serial line
|
||||
* @port: uart_port structure where char(s) after BREAK met
|
||||
* @ch: new character in the sequence after received BREAK
|
||||
*
|
||||
* Enables magic SysRq when the required sequence is met on port
|
||||
* (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
|
||||
*
|
||||
* Returns false if @ch is out of enabling sequence and should be
|
||||
* handled some other way, true if @ch was consumed.
|
||||
*/
|
||||
static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq);
|
||||
|
||||
if (!sysrq_toggle_seq_len)
|
||||
return false;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX);
|
||||
if (sysrq_toggle_seq[port->sysrq_seq] != ch) {
|
||||
port->sysrq_seq = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (++port->sysrq_seq < sysrq_toggle_seq_len) {
|
||||
port->sysrq = jiffies + SYSRQ_TIMEOUT;
|
||||
return true;
|
||||
}
|
||||
|
||||
schedule_work(&sysrq_enable_work);
|
||||
|
||||
port->sysrq = 0;
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
|
||||
@@ -3091,9 +3202,13 @@ int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
return 0;
|
||||
|
||||
if (ch && time_before(jiffies, port->sysrq)) {
|
||||
handle_sysrq(ch);
|
||||
port->sysrq = 0;
|
||||
return 1;
|
||||
if (sysrq_mask()) {
|
||||
handle_sysrq(ch);
|
||||
port->sysrq = 0;
|
||||
return 1;
|
||||
}
|
||||
if (uart_try_toggle_sysrq(port, ch))
|
||||
return 1;
|
||||
}
|
||||
port->sysrq = 0;
|
||||
|
||||
@@ -3110,9 +3225,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
return 0;
|
||||
|
||||
if (ch && time_before(jiffies, port->sysrq)) {
|
||||
port->sysrq_ch = ch;
|
||||
port->sysrq = 0;
|
||||
return 1;
|
||||
if (sysrq_mask()) {
|
||||
port->sysrq_ch = ch;
|
||||
port->sysrq = 0;
|
||||
return 1;
|
||||
}
|
||||
if (uart_try_toggle_sysrq(port, ch))
|
||||
return 1;
|
||||
}
|
||||
port->sysrq = 0;
|
||||
|
||||
@@ -3120,22 +3239,19 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_prepare_sysrq_char);
|
||||
|
||||
void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long irqflags)
|
||||
void uart_unlock_and_check_sysrq(struct uart_port *port, unsigned long flags)
|
||||
__releases(&port->lock)
|
||||
{
|
||||
int sysrq_ch;
|
||||
if (port->has_sysrq) {
|
||||
int sysrq_ch = port->sysrq_ch;
|
||||
|
||||
if (!port->has_sysrq) {
|
||||
spin_unlock_irqrestore(&port->lock, irqflags);
|
||||
return;
|
||||
port->sysrq_ch = 0;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
if (sysrq_ch)
|
||||
handle_sysrq(sysrq_ch);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
sysrq_ch = port->sysrq_ch;
|
||||
port->sysrq_ch = 0;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, irqflags);
|
||||
|
||||
if (sysrq_ch)
|
||||
handle_sysrq(sysrq_ch);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_unlock_and_check_sysrq);
|
||||
|
||||
@@ -3149,14 +3265,12 @@ int uart_handle_break(struct uart_port *port)
|
||||
if (port->handle_break)
|
||||
port->handle_break(port);
|
||||
|
||||
if (port->has_sysrq) {
|
||||
if (port->cons && port->cons->index == port->line) {
|
||||
if (!port->sysrq) {
|
||||
port->sysrq = jiffies + HZ*5;
|
||||
return 1;
|
||||
}
|
||||
port->sysrq = 0;
|
||||
if (port->has_sysrq && uart_console(port)) {
|
||||
if (!port->sysrq) {
|
||||
port->sysrq = jiffies + SYSRQ_TIMEOUT;
|
||||
return 1;
|
||||
}
|
||||
port->sysrq = 0;
|
||||
}
|
||||
|
||||
if (port->flags & UPF_SAK)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Helpers for controlling modem lines via GPIO
|
||||
*
|
||||
|
@@ -618,10 +618,10 @@ static void sifive_serial_shutdown(struct uart_port *port)
|
||||
*
|
||||
* On the V0 SoC, the UART IP block is derived from the CPU clock source
|
||||
* after a synchronous divide-by-two divider, so any CPU clock rate change
|
||||
* requires the UART baud rate to be updated. This presumably could corrupt any
|
||||
* serial word currently being transmitted or received. It would probably
|
||||
* be better to stop receives and transmits, then complete the baud rate
|
||||
* change, then re-enable them.
|
||||
* requires the UART baud rate to be updated. This presumably corrupts any
|
||||
* serial word currently being transmitted or received. In order to avoid
|
||||
* corrupting the output data stream, we drain the transmit queue before
|
||||
* allowing the clock's rate to be changed.
|
||||
*/
|
||||
static int sifive_serial_clk_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *data)
|
||||
@@ -629,6 +629,26 @@ static int sifive_serial_clk_notifier(struct notifier_block *nb,
|
||||
struct clk_notifier_data *cnd = data;
|
||||
struct sifive_serial_port *ssp = notifier_to_sifive_serial_port(nb);
|
||||
|
||||
if (event == PRE_RATE_CHANGE) {
|
||||
/*
|
||||
* The TX watermark is always set to 1 by this driver, which
|
||||
* means that the TX busy bit will lower when there are 0 bytes
|
||||
* left in the TX queue -- in other words, when the TX FIFO is
|
||||
* empty.
|
||||
*/
|
||||
__ssp_wait_for_xmitr(ssp);
|
||||
/*
|
||||
* On the cycle the TX FIFO goes empty there is still a full
|
||||
* UART frame left to be transmitted in the shift register.
|
||||
* The UART provides no way for software to directly determine
|
||||
* when that last frame has been transmitted, so we just sleep
|
||||
* here instead. As we're not tracking the number of stop bits
|
||||
* they're just worst cased here. The rest of the serial
|
||||
* framing parameters aren't configurable by software.
|
||||
*/
|
||||
udelay(DIV_ROUND_UP(12 * 1000 * 1000, ssp->baud_rate));
|
||||
}
|
||||
|
||||
if (event == POST_RATE_CHANGE && ssp->clkin_rate != cnd->new_rate) {
|
||||
ssp->clkin_rate = cnd->new_rate;
|
||||
__ssp_update_div(ssp);
|
||||
@@ -709,6 +729,29 @@ static const char *sifive_serial_type(struct uart_port *port)
|
||||
return port->type == PORT_SIFIVE_V0 ? "SiFive UART v0" : NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int sifive_serial_poll_get_char(struct uart_port *port)
|
||||
{
|
||||
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
|
||||
char is_empty, ch;
|
||||
|
||||
ch = __ssp_receive_char(ssp, &is_empty);
|
||||
if (is_empty)
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void sifive_serial_poll_put_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
|
||||
|
||||
__ssp_wait_for_xmitr(ssp);
|
||||
__ssp_transmit_char(ssp, c);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
/*
|
||||
* Early console support
|
||||
*/
|
||||
@@ -877,6 +920,10 @@ static const struct uart_ops sifive_serial_uops = {
|
||||
.request_port = sifive_serial_request_port,
|
||||
.config_port = sifive_serial_config_port,
|
||||
.verify_port = sifive_serial_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = sifive_serial_poll_get_char,
|
||||
.poll_put_char = sifive_serial_poll_put_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct uart_driver sifive_serial_uart_driver = {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Drivers for CSR SiRFprimaII onboard UARTs.
|
||||
*
|
||||
|
@@ -1013,7 +1013,7 @@ static void sprd_console_write(struct console *co, const char *s,
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int __init sprd_console_setup(struct console *co, char *options)
|
||||
static int sprd_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct sprd_uart_port *sprd_uart_port;
|
||||
int baud = 115200;
|
||||
@@ -1102,29 +1102,6 @@ static struct uart_driver sprd_uart_driver = {
|
||||
.cons = SPRD_CONSOLE,
|
||||
};
|
||||
|
||||
static int sprd_probe_dt_alias(int index, struct device *dev)
|
||||
{
|
||||
struct device_node *np;
|
||||
int ret = index;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF))
|
||||
return ret;
|
||||
|
||||
np = dev->of_node;
|
||||
if (!np)
|
||||
return ret;
|
||||
|
||||
ret = of_alias_get_id(np, "serial");
|
||||
if (ret < 0)
|
||||
ret = index;
|
||||
else if (ret >= ARRAY_SIZE(sprd_port) || sprd_port[ret] != NULL) {
|
||||
dev_warn(dev, "requested serial port %d not available.\n", ret);
|
||||
ret = index;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sprd_remove(struct platform_device *dev)
|
||||
{
|
||||
struct sprd_uart_port *sup = platform_get_drvdata(dev);
|
||||
@@ -1132,14 +1109,13 @@ static int sprd_remove(struct platform_device *dev)
|
||||
if (sup) {
|
||||
uart_remove_one_port(&sprd_uart_driver, &sup->port);
|
||||
sprd_port[sup->port.line] = NULL;
|
||||
sprd_rx_free_buf(sup);
|
||||
sprd_ports_num--;
|
||||
}
|
||||
|
||||
if (!sprd_ports_num)
|
||||
uart_unregister_driver(&sprd_uart_driver);
|
||||
|
||||
sprd_rx_free_buf(sup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1147,7 +1123,8 @@ static bool sprd_uart_is_console(struct uart_port *uport)
|
||||
{
|
||||
struct console *cons = sprd_uart_driver.cons;
|
||||
|
||||
if (cons && cons->index >= 0 && cons->index == uport->line)
|
||||
if ((cons && cons->index >= 0 && cons->index == uport->line) ||
|
||||
of_console_check(uport->dev->of_node, SPRD_TTY_NAME, uport->line))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -1203,14 +1180,11 @@ static int sprd_probe(struct platform_device *pdev)
|
||||
int index;
|
||||
int ret;
|
||||
|
||||
for (index = 0; index < ARRAY_SIZE(sprd_port); index++)
|
||||
if (sprd_port[index] == NULL)
|
||||
break;
|
||||
|
||||
if (index == ARRAY_SIZE(sprd_port))
|
||||
return -EBUSY;
|
||||
|
||||
index = sprd_probe_dt_alias(index, &pdev->dev);
|
||||
index = of_alias_get_id(pdev->dev.of_node, "serial");
|
||||
if (index < 0 || index >= ARRAY_SIZE(sprd_port)) {
|
||||
dev_err(&pdev->dev, "got a wrong serial alias id %d\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
|
||||
GFP_KERNEL);
|
||||
@@ -1262,10 +1236,8 @@ static int sprd_probe(struct platform_device *pdev)
|
||||
sprd_ports_num++;
|
||||
|
||||
ret = uart_add_one_port(&sprd_uart_driver, up);
|
||||
if (ret) {
|
||||
sprd_port[index] = NULL;
|
||||
if (ret)
|
||||
sprd_remove(pdev);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, up);
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) Maxime Coquelin 2015
|
||||
* Copyright (C) STMicroelectronics SA 2017
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* timbuart.c timberdale FPGA GPIO driver
|
||||
* Copyright (c) 2009 Intel Corporation
|
||||
|
@@ -650,8 +650,8 @@ static unsigned int cdns_uart_tx_empty(struct uart_port *port)
|
||||
unsigned int status;
|
||||
|
||||
status = readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_TXEMPTY;
|
||||
return status ? TIOCSER_TEMT : 0;
|
||||
(CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE);
|
||||
return (status == CDNS_UART_SR_TXEMPTY) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -693,20 +693,8 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
||||
u32 cval = 0;
|
||||
unsigned int baud, minbaud, maxbaud;
|
||||
unsigned long flags;
|
||||
unsigned int ctrl_reg, mode_reg, val;
|
||||
int err;
|
||||
unsigned int ctrl_reg, mode_reg;
|
||||
|
||||
/* Wait for the transmit FIFO to empty before making changes */
|
||||
if (!(readl(port->membase + CDNS_UART_CR) &
|
||||
CDNS_UART_CR_TX_DIS)) {
|
||||
err = readl_poll_timeout(port->membase + CDNS_UART_SR,
|
||||
val, (val & CDNS_UART_SR_TXEMPTY),
|
||||
1000, TX_TIMEOUT);
|
||||
if (err) {
|
||||
dev_err(port->dev, "timed out waiting for tx empty");
|
||||
return;
|
||||
}
|
||||
}
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable the TX and RX to set baud rate */
|
||||
|
Reference in New Issue
Block a user