TTY / Serial driver updates for 5.3-rc1
Here is the "large" TTY and Serial driver update for 5.3-rc1. It's in the negative number of lines overall as we removed an obsolete serial driver that was causing problems for some people who were trying to clean up some apis (the mpsc.c driver, which only worked for some pre-production hardware that no one has anymore.) Other than that, lots of tiny changes, cleaning up small things along with some platform-specific serial driver updates. All of these have been in linux-next for a while now with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXSXkOA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynidwCgoCX5L3zayZ7pZTWmtLsTOy0O0WYAn1gzleNg sSRApC0DGfxOIrco7urV =0KJa -----END PGP SIGNATURE----- Merge tag 'tty-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty / serial driver updates from Greg KH: "Here is the "large" TTY and Serial driver update for 5.3-rc1. It's in the negative number of lines overall as we removed an obsolete serial driver that was causing problems for some people who were trying to clean up some apis (the mpsc.c driver, which only worked for some pre-production hardware that no one has anymore.) Other than that, lots of tiny changes, cleaning up small things along with some platform-specific serial driver updates. All of these have been in linux-next for a while now with no reported issues" * tag 'tty-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (68 commits) tty: serial: fsl_lpuart: add imx8qxp support serial: imx: set_termios(): preserve RTS state serial: imx: set_termios(): clarify RTS/CTS bits calculation serial: imx: set_termios(): factor-out 'ucr2' initial value serial: sh-sci: Terminate TX DMA during buffer flushing serial: sh-sci: Fix TX DMA buffer flushing and workqueue races serial: mpsc: Remove obsolete MPSC driver serial: 8250: 8250_core: Fix missing unlock on error in serial8250_register_8250_port() serial: stm32: add RX and TX FIFO flush serial: stm32: add support of RX FIFO threshold serial: stm32: add support of TX FIFO threshold serial: stm32: update PIO transmission serial: stm32: add support of timeout interrupt for RX Revert "serial: 8250: Don't service RX FIFO if interrupts are disabled" tty/serial/8250: use mctrl_gpio helpers serial: mctrl_gpio: Check if GPIO property exisits before requesting it serial: 8250: pericom_do_set_divisor can be static tty: serial_core: Set port active bit in uart_port_activate serial: 8250: Add MSR/MCR TIOCM conversion wrapper functions serial: 8250: factor out serial8250_{set,clear}_THRI() helpers ...
This commit is contained in:
Коммит
d72619706a
|
@ -2693,8 +2693,8 @@
|
|||
41 = /dev/ttySMX0 Motorola i.MX - port 0
|
||||
42 = /dev/ttySMX1 Motorola i.MX - port 1
|
||||
43 = /dev/ttySMX2 Motorola i.MX - port 2
|
||||
44 = /dev/ttyMM0 Marvell MPSC - port 0
|
||||
45 = /dev/ttyMM1 Marvell MPSC - port 1
|
||||
44 = /dev/ttyMM0 Marvell MPSC - port 0 (obsolete unused)
|
||||
45 = /dev/ttyMM1 Marvell MPSC - port 1 (obsolete unused)
|
||||
46 = /dev/ttyCPM0 PPC CPM (SCC or SMC) - port 0
|
||||
...
|
||||
47 = /dev/ttyCPM5 PPC CPM (SCC or SMC) - port 5
|
||||
|
|
|
@ -53,6 +53,9 @@ Optional properties:
|
|||
programmable TX FIFO thresholds.
|
||||
- resets : phandle + reset specifier pairs
|
||||
- overrun-throttle-ms : how long to pause uart rx when input overrun is encountered.
|
||||
- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
|
||||
line respectively. It will use specified GPIO instead of the peripheral
|
||||
function pin for the UART feature. If unsure, don't specify this property.
|
||||
|
||||
Note:
|
||||
* fsl,ns16550:
|
||||
|
@ -74,3 +77,19 @@ Example:
|
|||
interrupts = <10>;
|
||||
reg-shift = <2>;
|
||||
};
|
||||
|
||||
Example for OMAP UART using GPIO-based modem control signals:
|
||||
|
||||
uart4: serial@49042000 {
|
||||
compatible = "ti,omap3-uart";
|
||||
reg = <0x49042000 0x400>;
|
||||
interrupts = <80>;
|
||||
ti,hwmods = "uart4";
|
||||
clock-frequency = <48000000>;
|
||||
cts-gpios = <&gpio3 5 GPIO_ACTIVE_LOW>;
|
||||
rts-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>;
|
||||
dtr-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
|
||||
dsr-gpios = <&gpio1 13 GPIO_ACTIVE_LOW>;
|
||||
dcd-gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
|
||||
rng-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
|
|
|
@ -324,8 +324,6 @@ static int rs_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
|||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
|
||||
/*
|
||||
* This routine will shutdown a serial port; interrupts are disabled, and
|
||||
* DTR is dropped if the hangup on close termio flag is on.
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#define NR_CHANNELS 8
|
||||
#define IPOCTAL_MAX_BOARDS 16
|
||||
#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS)
|
||||
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
|
||||
/**
|
||||
* struct ipoctal_stats -- Stats since last reset
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include <linux/serial_reg.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include "../serial_mctrl_gpio.h"
|
||||
|
||||
struct uart_8250_dma {
|
||||
int (*tx_dma)(struct uart_8250_port *p);
|
||||
int (*rx_dma)(struct uart_8250_port *p);
|
||||
|
@ -128,6 +130,24 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
|||
up->dl_write(up, value);
|
||||
}
|
||||
|
||||
static inline bool serial8250_set_THRI(struct uart_8250_port *up)
|
||||
{
|
||||
if (up->ier & UART_IER_THRI)
|
||||
return false;
|
||||
up->ier |= UART_IER_THRI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
|
||||
{
|
||||
if (!(up->ier & UART_IER_THRI))
|
||||
return false;
|
||||
up->ier &= ~UART_IER_THRI;
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct uart_8250_port *serial8250_get_port(int line);
|
||||
|
||||
void serial8250_rpm_get(struct uart_8250_port *p);
|
||||
|
@ -139,14 +159,82 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p);
|
|||
int serial8250_em485_init(struct uart_8250_port *p);
|
||||
void serial8250_em485_destroy(struct uart_8250_port *p);
|
||||
|
||||
/* MCR <-> TIOCM conversion */
|
||||
static inline int serial8250_TIOCM_to_MCR(int tiocm)
|
||||
{
|
||||
int mcr = 0;
|
||||
|
||||
if (tiocm & TIOCM_RTS)
|
||||
mcr |= UART_MCR_RTS;
|
||||
if (tiocm & TIOCM_DTR)
|
||||
mcr |= UART_MCR_DTR;
|
||||
if (tiocm & TIOCM_OUT1)
|
||||
mcr |= UART_MCR_OUT1;
|
||||
if (tiocm & TIOCM_OUT2)
|
||||
mcr |= UART_MCR_OUT2;
|
||||
if (tiocm & TIOCM_LOOP)
|
||||
mcr |= UART_MCR_LOOP;
|
||||
|
||||
return mcr;
|
||||
}
|
||||
|
||||
static inline int serial8250_MCR_to_TIOCM(int mcr)
|
||||
{
|
||||
int tiocm = 0;
|
||||
|
||||
if (mcr & UART_MCR_RTS)
|
||||
tiocm |= TIOCM_RTS;
|
||||
if (mcr & UART_MCR_DTR)
|
||||
tiocm |= TIOCM_DTR;
|
||||
if (mcr & UART_MCR_OUT1)
|
||||
tiocm |= TIOCM_OUT1;
|
||||
if (mcr & UART_MCR_OUT2)
|
||||
tiocm |= TIOCM_OUT2;
|
||||
if (mcr & UART_MCR_LOOP)
|
||||
tiocm |= TIOCM_LOOP;
|
||||
|
||||
return tiocm;
|
||||
}
|
||||
|
||||
/* MSR <-> TIOCM conversion */
|
||||
static inline int serial8250_MSR_to_TIOCM(int msr)
|
||||
{
|
||||
int tiocm = 0;
|
||||
|
||||
if (msr & UART_MSR_DCD)
|
||||
tiocm |= TIOCM_CAR;
|
||||
if (msr & UART_MSR_RI)
|
||||
tiocm |= TIOCM_RNG;
|
||||
if (msr & UART_MSR_DSR)
|
||||
tiocm |= TIOCM_DSR;
|
||||
if (msr & UART_MSR_CTS)
|
||||
tiocm |= TIOCM_CTS;
|
||||
|
||||
return tiocm;
|
||||
}
|
||||
|
||||
static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
|
||||
{
|
||||
serial_out(up, UART_MCR, value);
|
||||
|
||||
if (up->gpios)
|
||||
mctrl_gpio_set(up->gpios, serial8250_MCR_to_TIOCM(value));
|
||||
}
|
||||
|
||||
static inline int serial8250_in_MCR(struct uart_8250_port *up)
|
||||
{
|
||||
return serial_in(up, UART_MCR);
|
||||
int mctrl;
|
||||
|
||||
mctrl = serial_in(up, UART_MCR);
|
||||
|
||||
if (up->gpios) {
|
||||
unsigned int mctrl_gpio = 0;
|
||||
|
||||
mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, &mctrl_gpio);
|
||||
mctrl |= serial8250_TIOCM_to_MCR(mctrl_gpio);
|
||||
}
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
#if defined(__alpha__) && !defined(CONFIG_PCI)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* serial8250_register_8250_port() ports
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/ioport.h>
|
||||
|
@ -982,6 +983,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
|
||||
uart = serial8250_find_match_or_unused(&up->port);
|
||||
if (uart && uart->port.type != PORT_8250_CIR) {
|
||||
struct mctrl_gpios *gpios;
|
||||
|
||||
if (uart->port.dev)
|
||||
uart_remove_one_port(&serial8250_reg, &uart->port);
|
||||
|
||||
|
@ -1016,6 +1019,22 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
if (up->port.flags & UPF_FIXED_TYPE)
|
||||
uart->port.type = up->port.type;
|
||||
|
||||
/*
|
||||
* Only call mctrl_gpio_init(), if the device has no ACPI
|
||||
* companion device
|
||||
*/
|
||||
if (!has_acpi_companion(uart->port.dev)) {
|
||||
gpios = mctrl_gpio_init(&uart->port, 0);
|
||||
if (IS_ERR(gpios)) {
|
||||
if (PTR_ERR(gpios) != -ENOSYS) {
|
||||
ret = PTR_ERR(gpios);
|
||||
goto out_unlock;
|
||||
}
|
||||
} else {
|
||||
uart->gpios = gpios;
|
||||
}
|
||||
}
|
||||
|
||||
serial8250_set_defaults(uart);
|
||||
|
||||
/* Possibly override default I/O functions. */
|
||||
|
@ -1082,6 +1101,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
}
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&serial_mutex);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -34,10 +34,8 @@ static void __dma_tx_complete(void *param)
|
|||
uart_write_wakeup(&p->port);
|
||||
|
||||
ret = serial8250_tx_dma(p);
|
||||
if (ret) {
|
||||
p->ier |= UART_IER_THRI;
|
||||
serial_port_out(&p->port, UART_IER, p->ier);
|
||||
}
|
||||
if (ret)
|
||||
serial8250_set_THRI(p);
|
||||
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
@ -100,10 +98,7 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
dma_async_issue_pending(dma->txchan);
|
||||
if (dma->tx_err) {
|
||||
dma->tx_err = 0;
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
}
|
||||
serial8250_clear_THRI(p);
|
||||
}
|
||||
return 0;
|
||||
err:
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serial_8250.h>
|
||||
|
@ -47,7 +48,6 @@
|
|||
#define MTK_UART_DMA_EN_RX 0x5
|
||||
|
||||
#define MTK_UART_ESCAPE_CHAR 0x77 /* Escape char added under sw fc */
|
||||
#define MTK_UART_TX_SIZE UART_XMIT_SIZE
|
||||
#define MTK_UART_RX_SIZE 0x8000
|
||||
#define MTK_UART_TX_TRIGGER 1
|
||||
#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE
|
||||
|
@ -70,6 +70,7 @@ struct mtk8250_data {
|
|||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
enum dma_rx_status rx_status;
|
||||
#endif
|
||||
int rx_wakeup_irq;
|
||||
};
|
||||
|
||||
/* flow control mode */
|
||||
|
@ -89,28 +90,30 @@ static void mtk8250_dma_rx_complete(void *param)
|
|||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct tty_port *tty_port = &up->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
int copied, total, cnt;
|
||||
unsigned char *ptr;
|
||||
int copied;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
if (data->rx_status == DMA_RX_SHUTDOWN)
|
||||
return;
|
||||
|
||||
if ((data->rx_pos + state.residue) <= dma->rx_size) {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr, state.residue);
|
||||
} else {
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr,
|
||||
dma->rx_size - data->rx_pos);
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
total = dma->rx_size - state.residue;
|
||||
cnt = total;
|
||||
|
||||
if ((data->rx_pos + cnt) > dma->rx_size)
|
||||
cnt = dma->rx_size - data->rx_pos;
|
||||
|
||||
ptr = (unsigned char *)(data->rx_pos + dma->rx_buf);
|
||||
copied = tty_insert_flip_string(tty_port, ptr, cnt);
|
||||
data->rx_pos += cnt;
|
||||
|
||||
if (total > cnt) {
|
||||
ptr = (unsigned char *)(dma->rx_buf);
|
||||
copied += tty_insert_flip_string(tty_port, ptr,
|
||||
data->rx_pos + state.residue - dma->rx_size);
|
||||
cnt = total - cnt;
|
||||
copied += tty_insert_flip_string(tty_port, ptr, cnt);
|
||||
data->rx_pos = cnt;
|
||||
}
|
||||
|
||||
up->port.icount.rx += copied;
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
|
@ -121,9 +124,7 @@ static void mtk8250_dma_rx_complete(void *param)
|
|||
static void mtk8250_rx_dma(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_8250_dma *dma = up->dma;
|
||||
struct mtk8250_data *data = up->port.private_data;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_tx_state state;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
|
@ -138,12 +139,6 @@ static void mtk8250_rx_dma(struct uart_8250_port *up)
|
|||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
data->rx_pos = state.residue;
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
}
|
||||
|
||||
|
@ -156,13 +151,11 @@ static void mtk8250_dma_enable(struct uart_8250_port *up)
|
|||
if (data->rx_status != DMA_RX_START)
|
||||
return;
|
||||
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = dma->rx_size / 1024;
|
||||
dma->rxconf.src_addr = dma->rx_addr;
|
||||
dma->rxconf.src_port_window_size = dma->rx_size;
|
||||
dma->rxconf.src_addr = dma->rx_addr;
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024;
|
||||
dma->txconf.dst_addr = dma->tx_addr;
|
||||
dma->txconf.dst_port_window_size = UART_XMIT_SIZE;
|
||||
dma->txconf.dst_addr = dma->tx_addr;
|
||||
|
||||
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
|
||||
UART_FCR_CLEAR_XMIT);
|
||||
|
@ -551,6 +544,8 @@ static int mtk8250_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
data->rx_wakeup_irq = platform_get_irq(pdev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -572,15 +567,35 @@ static int mtk8250_remove(struct platform_device *pdev)
|
|||
static int __maybe_unused mtk8250_suspend(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
int irq = data->rx_wakeup_irq;
|
||||
int err;
|
||||
|
||||
serial8250_suspend_port(data->line);
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
if (irq >= 0) {
|
||||
err = enable_irq_wake(irq);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"failed to enable irq wake on IRQ %d: %d\n",
|
||||
irq, err);
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
serial8250_resume_port(data->line);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused mtk8250_resume(struct device *dev)
|
||||
{
|
||||
struct mtk8250_data *data = dev_get_drvdata(dev);
|
||||
int irq = data->rx_wakeup_irq;
|
||||
|
||||
if (irq >= 0)
|
||||
disable_irq_wake(irq);
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
serial8250_resume_port(data->line);
|
||||
|
||||
|
|
|
@ -70,9 +70,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
/* Get clk rate through clk driver if present */
|
||||
info->clk = devm_clk_get(&ofdev->dev, NULL);
|
||||
if (IS_ERR(info->clk)) {
|
||||
dev_warn(&ofdev->dev,
|
||||
"clk or clock-frequency not defined\n");
|
||||
ret = PTR_ERR(info->clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_warn(&ofdev->dev,
|
||||
"failed to get clock: %d\n", ret);
|
||||
goto err_pmruntime;
|
||||
}
|
||||
|
||||
|
@ -205,18 +206,16 @@ err_pmruntime:
|
|||
/*
|
||||
* Try to register a serial port
|
||||
*/
|
||||
static const struct of_device_id of_platform_serial_table[];
|
||||
static int of_platform_serial_probe(struct platform_device *ofdev)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct of_serial_info *info;
|
||||
struct uart_8250_port port8250;
|
||||
unsigned int port_type;
|
||||
u32 tx_threshold;
|
||||
int port_type;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(of_platform_serial_table, &ofdev->dev);
|
||||
if (!match)
|
||||
port_type = (unsigned long)of_device_get_match_data(&ofdev->dev);
|
||||
if (port_type == PORT_UNKNOWN)
|
||||
return -EINVAL;
|
||||
|
||||
if (of_property_read_bool(ofdev->dev.of_node, "used-by-rtas"))
|
||||
|
@ -226,7 +225,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
|||
if (info == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
port_type = (unsigned long)match->data;
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info);
|
||||
if (ret)
|
||||
|
|
|
@ -141,18 +141,20 @@ static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
|||
|
||||
serial8250_do_set_mctrl(port, mctrl);
|
||||
|
||||
/*
|
||||
* Turn off autoRTS if RTS is lowered and restore autoRTS setting
|
||||
* if RTS is raised
|
||||
*/
|
||||
lcr = serial_in(up, UART_LCR);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
|
||||
priv->efr |= UART_EFR_RTS;
|
||||
else
|
||||
priv->efr &= ~UART_EFR_RTS;
|
||||
serial_out(up, UART_EFR, priv->efr);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
if (!up->gpios) {
|
||||
/*
|
||||
* Turn off autoRTS if RTS is lowered and restore autoRTS
|
||||
* setting if RTS is raised
|
||||
*/
|
||||
lcr = serial_in(up, UART_LCR);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
|
||||
priv->efr |= UART_EFR_RTS;
|
||||
else
|
||||
priv->efr &= ~UART_EFR_RTS;
|
||||
serial_out(up, UART_EFR, priv->efr);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -453,7 +455,8 @@ static void omap_8250_set_termios(struct uart_port *port,
|
|||
priv->efr = 0;
|
||||
up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
|
||||
|
||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
|
||||
if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW &&
|
||||
!up->gpios) {
|
||||
/* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
|
||||
up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
|
||||
priv->efr |= UART_EFR_CTS;
|
||||
|
@ -923,15 +926,13 @@ static void omap_8250_dma_tx_complete(void *param)
|
|||
ret = omap_8250_tx_dma(p);
|
||||
if (ret)
|
||||
en_thri = true;
|
||||
|
||||
} else if (p->capabilities & UART_CAP_RPM) {
|
||||
en_thri = true;
|
||||
}
|
||||
|
||||
if (en_thri) {
|
||||
dma->tx_err = 1;
|
||||
p->ier |= UART_IER_THRI;
|
||||
serial_port_out(&p->port, UART_IER, p->ier);
|
||||
serial8250_set_THRI(p);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
|
@ -959,10 +960,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
|||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
}
|
||||
serial8250_clear_THRI(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1020,10 +1018,7 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
|
|||
if (dma->tx_err)
|
||||
dma->tx_err = 0;
|
||||
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
}
|
||||
serial8250_clear_THRI(p);
|
||||
if (skip_byte)
|
||||
serial_out(p, UART_TX, xmit->buf[xmit->tail]);
|
||||
return 0;
|
||||
|
|
|
@ -1326,13 +1326,66 @@ static int pci_default_setup(struct serial_private *priv,
|
|||
|
||||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
static void
|
||||
pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
unsigned int quot, unsigned int quot_frac)
|
||||
{
|
||||
int scr;
|
||||
int lcr;
|
||||
int actual_baud;
|
||||
int tolerance;
|
||||
|
||||
for (scr = 5 ; scr <= 15 ; scr++) {
|
||||
actual_baud = 921600 * 16 / scr;
|
||||
tolerance = actual_baud / 50;
|
||||
|
||||
if ((baud < actual_baud + tolerance) &&
|
||||
(baud > actual_baud - tolerance)) {
|
||||
|
||||
lcr = serial_port_in(port, UART_LCR);
|
||||
serial_port_out(port, UART_LCR, lcr | 0x80);
|
||||
|
||||
serial_port_out(port, UART_DLL, 1);
|
||||
serial_port_out(port, UART_DLM, 0);
|
||||
serial_port_out(port, 2, 16 - scr);
|
||||
serial_port_out(port, UART_LCR, lcr);
|
||||
return;
|
||||
} else if (baud > actual_baud) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
serial8250_do_set_divisor(port, baud, quot, quot_frac);
|
||||
}
|
||||
static int pci_pericom_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
unsigned int bar, offset = board->first_offset, maxnr;
|
||||
|
||||
bar = FL_GET_BASE(board->flags);
|
||||
if (board->flags & FL_BASE_BARS)
|
||||
bar += idx;
|
||||
else
|
||||
offset += idx * board->uart_offset;
|
||||
|
||||
|
||||
maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
|
||||
(board->reg_shift + 3);
|
||||
|
||||
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
|
||||
return 1;
|
||||
|
||||
port->port.set_divisor = pericom_do_set_divisor;
|
||||
|
||||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
|
||||
static int pci_pericom_setup_four_at_eight(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
unsigned int bar, offset = board->first_offset, maxnr;
|
||||
|
||||
bar = FL_GET_BASE(board->flags);
|
||||
if (board->flags & FL_BASE_BARS)
|
||||
bar += idx;
|
||||
|
@ -1348,6 +1401,8 @@ static int pci_pericom_setup(struct serial_private *priv,
|
|||
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
|
||||
return 1;
|
||||
|
||||
port->port.set_divisor = pericom_do_set_divisor;
|
||||
|
||||
return setup_port(priv, port, bar, offset, board->reg_shift);
|
||||
}
|
||||
|
||||
|
@ -1995,7 +2050,7 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.device = PCI_DEVICE_ID_PERICOM_PI7C9X7954,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
/*
|
||||
* PLX
|
||||
|
@ -2032,107 +2087,113 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
.setup = pci_pericom_setup_four_at_eight,
|
||||
},
|
||||
/*
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_ACCESIO,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_pericom_setup,
|
||||
}, /*
|
||||
* SBS Technologies, Inc., PMC-OCTALPRO 232
|
||||
*/
|
||||
{
|
||||
|
|
|
@ -462,8 +462,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
|||
return -ENODEV;
|
||||
|
||||
dev_dbg(&dev->dev,
|
||||
"Setup PNP port: port %lx, mem %pa, irq %d, type %d\n",
|
||||
uart.port.iobase, &uart.port.mapbase,
|
||||
"Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
|
||||
uart.port.iobase, (unsigned long long)uart.port.mapbase,
|
||||
uart.port.irq, uart.port.iotype);
|
||||
|
||||
if (flags & CIR_PORT) {
|
||||
|
|
|
@ -1502,11 +1502,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p)
|
|||
|
||||
static inline void __do_stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
if (p->ier & UART_IER_THRI) {
|
||||
p->ier &= ~UART_IER_THRI;
|
||||
serial_out(p, UART_IER, p->ier);
|
||||
if (serial8250_clear_THRI(p))
|
||||
serial8250_rpm_put_tx(p);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __stop_tx(struct uart_8250_port *p)
|
||||
|
@ -1555,10 +1552,7 @@ static inline void __start_tx(struct uart_port *port)
|
|||
if (up->dma && !up->dma->tx_dma(up))
|
||||
return;
|
||||
|
||||
if (!(up->ier & UART_IER_THRI)) {
|
||||
up->ier |= UART_IER_THRI;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
|
||||
if (serial8250_set_THRI(up)) {
|
||||
if (up->bugs & UART_BUG_TXEN) {
|
||||
unsigned char lsr;
|
||||
|
||||
|
@ -1662,6 +1656,8 @@ static void serial8250_disable_ms(struct uart_port *port)
|
|||
if (up->bugs & UART_BUG_NOMSR)
|
||||
return;
|
||||
|
||||
mctrl_gpio_disable_ms(up->gpios);
|
||||
|
||||
up->ier &= ~UART_IER_MSI;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
}
|
||||
|
@ -1674,6 +1670,8 @@ static void serial8250_enable_ms(struct uart_port *port)
|
|||
if (up->bugs & UART_BUG_NOMSR)
|
||||
return;
|
||||
|
||||
mctrl_gpio_enable_ms(up->gpios);
|
||||
|
||||
up->ier |= UART_IER_MSI;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
@ -1869,13 +1867,13 @@ 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) &&
|
||||
iir & UART_IIR_RDI) {
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (!up->dma || handle_rx_dma(up, iir))
|
||||
status = serial8250_rx_chars(up, status);
|
||||
}
|
||||
serial8250_modem_status(up);
|
||||
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE))
|
||||
if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE) &&
|
||||
(up->ier & UART_IER_THRI))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
uart_unlock_and_check_sysrq(port, flags);
|
||||
|
@ -1944,22 +1942,17 @@ unsigned int serial8250_do_get_mctrl(struct uart_port *port)
|
|||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned int status;
|
||||
unsigned int ret;
|
||||
unsigned int val;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
status = serial8250_modem_status(up);
|
||||
serial8250_rpm_put(up);
|
||||
|
||||
ret = 0;
|
||||
if (status & UART_MSR_DCD)
|
||||
ret |= TIOCM_CAR;
|
||||
if (status & UART_MSR_RI)
|
||||
ret |= TIOCM_RNG;
|
||||
if (status & UART_MSR_DSR)
|
||||
ret |= TIOCM_DSR;
|
||||
if (status & UART_MSR_CTS)
|
||||
ret |= TIOCM_CTS;
|
||||
return ret;
|
||||
val = serial8250_MSR_to_TIOCM(status);
|
||||
if (up->gpios)
|
||||
return mctrl_gpio_get(up->gpios, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_do_get_mctrl);
|
||||
|
||||
|
@ -1973,18 +1966,9 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
|
|||
void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned char mcr = 0;
|
||||
unsigned char mcr;
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
mcr |= UART_MCR_RTS;
|
||||
if (mctrl & TIOCM_DTR)
|
||||
mcr |= UART_MCR_DTR;
|
||||
if (mctrl & TIOCM_OUT1)
|
||||
mcr |= UART_MCR_OUT1;
|
||||
if (mctrl & TIOCM_OUT2)
|
||||
mcr |= UART_MCR_OUT2;
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
mcr |= UART_MCR_LOOP;
|
||||
mcr = serial8250_TIOCM_to_MCR(mctrl);
|
||||
|
||||
mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ config SERIAL_8250
|
|||
tristate "8250/16550 and compatible serial support"
|
||||
depends on !S390
|
||||
select SERIAL_CORE
|
||||
select SERIAL_MCTRL_GPIO if GPIOLIB
|
||||
---help---
|
||||
This selects whether you want to include the driver for the standard
|
||||
serial ports. The standard answer is Y. People who might say N
|
||||
|
|
|
@ -457,20 +457,6 @@ config SERIAL_21285_CONSOLE
|
|||
your boot loader (lilo or loadlin) about how to pass options to the
|
||||
kernel at boot time.)
|
||||
|
||||
config SERIAL_MPSC
|
||||
bool "Marvell MPSC serial port support"
|
||||
depends on MV64X60
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Say Y here if you want to use the Marvell MPSC serial controller.
|
||||
|
||||
config SERIAL_MPSC_CONSOLE
|
||||
bool "Support for console on Marvell MPSC serial port"
|
||||
depends on SERIAL_MPSC
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Say Y here if you want to support a serial console on a Marvell MPSC.
|
||||
|
||||
config SERIAL_PXA
|
||||
bool "PXA serial port support (DEPRECATED)"
|
||||
depends on ARCH_PXA || ARCH_MMP
|
||||
|
|
|
@ -46,7 +46,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
|
|||
obj-$(CONFIG_SERIAL_IMX) += imx.o
|
||||
obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
|
||||
obj-$(CONFIG_SERIAL_ICOM) += icom.o
|
||||
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
|
||||
obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
|
||||
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
|
||||
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
|
||||
|
|
|
@ -1717,7 +1717,7 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
|
|||
{
|
||||
pl011_write(uap->im, uap, REG_IMSC);
|
||||
|
||||
return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
|
||||
return request_irq(uap->port.irq, pl011_int, IRQF_SHARED, "uart-pl011", uap);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -407,7 +407,16 @@ static int cpm_uart_startup(struct uart_port *port)
|
|||
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
|
||||
}
|
||||
cpm_uart_initbd(pinfo);
|
||||
cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
|
||||
if (IS_SMC(pinfo)) {
|
||||
out_be32(&pinfo->smcup->smc_rstate, 0);
|
||||
out_be32(&pinfo->smcup->smc_tstate, 0);
|
||||
out_be16(&pinfo->smcup->smc_rbptr,
|
||||
in_be16(&pinfo->smcup->smc_rbase));
|
||||
out_be16(&pinfo->smcup->smc_tbptr,
|
||||
in_be16(&pinfo->smcup->smc_tbase));
|
||||
} else {
|
||||
cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
|
||||
}
|
||||
}
|
||||
/* Install interrupt handler. */
|
||||
retval = request_irq(port->irq, cpm_uart_int, 0, "cpm_uart", port);
|
||||
|
@ -567,8 +576,6 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
|||
/*
|
||||
* Set up parity check flag
|
||||
*/
|
||||
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
|
||||
port->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= BD_SC_FR | BD_SC_PR;
|
||||
|
@ -861,16 +868,14 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
|
|||
(u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
|
||||
|
||||
/*
|
||||
* In case SMC1 is being relocated...
|
||||
* In case SMC is being relocated...
|
||||
*/
|
||||
#if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
|
||||
out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
|
||||
out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
|
||||
out_be32(&up->smc_rstate, 0);
|
||||
out_be32(&up->smc_tstate, 0);
|
||||
out_be16(&up->smc_brkcr, 1); /* number of break chars */
|
||||
out_be16(&up->smc_brkec, 0);
|
||||
#endif
|
||||
|
||||
/* Set up the uart parameters in the
|
||||
* parameter ram.
|
||||
|
@ -884,8 +889,6 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
|
|||
out_be16(&up->smc_brkec, 0);
|
||||
out_be16(&up->smc_brkcr, 1);
|
||||
|
||||
cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
|
||||
|
||||
/* Set UART mode, 8 bit, no parity, one stop.
|
||||
* Enable receive and transmit.
|
||||
*/
|
||||
|
|
|
@ -541,7 +541,11 @@ static int __init digicolor_uart_init(void)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
return platform_driver_register(&digicolor_uart_platform);
|
||||
ret = platform_driver_register(&digicolor_uart_platform);
|
||||
if (ret)
|
||||
uart_unregister_driver(&digicolor_uart);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(digicolor_uart_init);
|
||||
|
||||
|
|
|
@ -234,9 +234,18 @@
|
|||
|
||||
static DEFINE_IDA(fsl_lpuart_ida);
|
||||
|
||||
enum lpuart_type {
|
||||
VF610_LPUART,
|
||||
LS1021A_LPUART,
|
||||
IMX7ULP_LPUART,
|
||||
IMX8QXP_LPUART,
|
||||
};
|
||||
|
||||
struct lpuart_port {
|
||||
struct uart_port port;
|
||||
struct clk *clk;
|
||||
enum lpuart_type devtype;
|
||||
struct clk *ipg_clk;
|
||||
struct clk *baud_clk;
|
||||
unsigned int txfifo_size;
|
||||
unsigned int rxfifo_size;
|
||||
|
||||
|
@ -261,19 +270,29 @@ struct lpuart_port {
|
|||
};
|
||||
|
||||
struct lpuart_soc_data {
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
enum lpuart_type devtype;
|
||||
char iotype;
|
||||
u8 reg_off;
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data vf_data = {
|
||||
.devtype = VF610_LPUART,
|
||||
.iotype = UPIO_MEM,
|
||||
};
|
||||
|
||||
static const struct lpuart_soc_data ls_data = {
|
||||
.devtype = LS1021A_LPUART,
|
||||
.iotype = UPIO_MEM32BE,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx_data = {
|
||||
static struct lpuart_soc_data imx7ulp_data = {
|
||||
.devtype = IMX7ULP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
};
|
||||
|
||||
static struct lpuart_soc_data imx8qxp_data = {
|
||||
.devtype = IMX8QXP_LPUART,
|
||||
.iotype = UPIO_MEM32,
|
||||
.reg_off = IMX_REG_OFF,
|
||||
};
|
||||
|
@ -281,7 +300,8 @@ static struct lpuart_soc_data imx_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,imx7ulp-lpuart", .data = &imx_data, },
|
||||
{ .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
|
||||
{ .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
|
||||
|
@ -289,6 +309,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_imx8qxp_lpuart(struct lpuart_port *sport)
|
||||
{
|
||||
return sport->devtype == IMX8QXP_LPUART;
|
||||
}
|
||||
|
||||
static inline u32 lpuart32_read(struct uart_port *port, u32 off)
|
||||
{
|
||||
switch (port->iotype) {
|
||||
|
@ -314,6 +339,39 @@ static inline void lpuart32_write(struct uart_port *port, u32 val,
|
|||
}
|
||||
}
|
||||
|
||||
static int __lpuart_enable_clks(struct lpuart_port *sport, bool is_en)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (is_en) {
|
||||
ret = clk_prepare_enable(sport->ipg_clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(sport->baud_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clk_disable_unprepare(sport->baud_clk);
|
||||
clk_disable_unprepare(sport->ipg_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
|
||||
{
|
||||
if (is_imx8qxp_lpuart(sport))
|
||||
return clk_get_rate(sport->baud_clk);
|
||||
|
||||
return clk_get_rate(sport->ipg_clk);
|
||||
}
|
||||
|
||||
#define lpuart_enable_clks(x) __lpuart_enable_clks(x, true)
|
||||
#define lpuart_disable_clks(x) __lpuart_enable_clks(x, false)
|
||||
|
||||
static void lpuart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned char temp;
|
||||
|
@ -1040,10 +1098,8 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
|
|||
sport->rx_dma_rng_buf_len = 16;
|
||||
|
||||
ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC);
|
||||
if (!ring->buf) {
|
||||
dev_err(sport->port.dev, "Ring buf alloc failed\n");
|
||||
if (!ring->buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
|
||||
sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len);
|
||||
|
@ -2071,14 +2127,14 @@ lpuart_console_get_options(struct lpuart_port *sport, int *baud,
|
|||
brfa = readb(sport->port.membase + UARTCR4);
|
||||
brfa &= UARTCR4_BRFA_MASK;
|
||||
|
||||
uartclk = clk_get_rate(sport->clk);
|
||||
uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
/*
|
||||
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
|
||||
*/
|
||||
baud_raw = uartclk / (16 * (sbr + brfa / 32));
|
||||
|
||||
if (*baud != baud_raw)
|
||||
printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
|
||||
dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
|
||||
"from %d to %d\n", baud_raw, *baud);
|
||||
}
|
||||
|
||||
|
@ -2114,14 +2170,14 @@ lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
|
|||
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||
bd &= UARTBAUD_SBR_MASK;
|
||||
sbr = bd;
|
||||
uartclk = clk_get_rate(sport->clk);
|
||||
uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
/*
|
||||
* baud = mod_clk/(16*(sbr[13]+(brfa)/32)
|
||||
*/
|
||||
baud_raw = uartclk / (16 * sbr);
|
||||
|
||||
if (*baud != baud_raw)
|
||||
printk(KERN_INFO "Serial: Console lpuart rounded baud rate"
|
||||
dev_info(sport->port.dev, "Serial: Console lpuart rounded baud rate"
|
||||
"from %d to %d\n", baud_raw, *baud);
|
||||
}
|
||||
|
||||
|
@ -2288,6 +2344,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
sport->port.mapbase = res->start;
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.type = PORT_LPUART;
|
||||
sport->devtype = sdata->devtype;
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "cannot obtain irq\n");
|
||||
|
@ -2303,20 +2360,27 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
|
||||
sport->port.rs485_config = lpuart_config_rs485;
|
||||
|
||||
sport->clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(sport->clk)) {
|
||||
ret = PTR_ERR(sport->clk);
|
||||
dev_err(&pdev->dev, "failed to get uart clk: %d\n", ret);
|
||||
sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(sport->ipg_clk)) {
|
||||
ret = PTR_ERR(sport->ipg_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(sport->clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable uart clk: %d\n", ret);
|
||||
return ret;
|
||||
sport->baud_clk = NULL;
|
||||
if (is_imx8qxp_lpuart(sport)) {
|
||||
sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
|
||||
if (IS_ERR(sport->baud_clk)) {
|
||||
ret = PTR_ERR(sport->baud_clk);
|
||||
dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
sport->port.uartclk = clk_get_rate(sport->clk);
|
||||
ret = lpuart_enable_clks(sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
sport->port.uartclk = lpuart_get_baud_clk_rate(sport);
|
||||
|
||||
lpuart_ports[sport->port.line] = sport;
|
||||
|
||||
|
@ -2364,7 +2428,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
|
||||
failed_attach_port:
|
||||
failed_irq_request:
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2376,7 +2440,7 @@ static int lpuart_remove(struct platform_device *pdev)
|
|||
|
||||
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
|
||||
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
if (sport->dma_tx_chan)
|
||||
dma_release_channel(sport->dma_tx_chan);
|
||||
|
@ -2441,7 +2505,7 @@ static int lpuart_suspend(struct device *dev)
|
|||
}
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_disable_unprepare(sport->clk);
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2453,7 +2517,7 @@ static int lpuart_resume(struct device *dev)
|
|||
unsigned long temp;
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
clk_prepare_enable(sport->clk);
|
||||
lpuart_enable_clks(sport);
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
lpuart32_setup_watermark(sport);
|
||||
|
|
|
@ -383,6 +383,7 @@ static void imx_uart_ucrs_restore(struct imx_port *sport,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* called with port.lock taken and irqs caller dependent */
|
||||
static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
|
||||
{
|
||||
*ucr2 &= ~(UCR2_CTSC | UCR2_CTS);
|
||||
|
@ -391,6 +392,7 @@ static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2)
|
|||
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
|
||||
}
|
||||
|
||||
/* called with port.lock taken and irqs caller dependent */
|
||||
static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
|
||||
{
|
||||
*ucr2 &= ~UCR2_CTSC;
|
||||
|
@ -400,6 +402,7 @@ static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2)
|
|||
mctrl_gpio_set(sport->gpios, sport->port.mctrl);
|
||||
}
|
||||
|
||||
/* called with port.lock taken and irqs caller dependent */
|
||||
static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2)
|
||||
{
|
||||
*ucr2 |= UCR2_CTSC;
|
||||
|
@ -1549,49 +1552,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
old_csize = CS8;
|
||||
}
|
||||
|
||||
if ((termios->c_cflag & CSIZE) == CS8)
|
||||
ucr2 = UCR2_WS | UCR2_SRST | UCR2_IRTS;
|
||||
else
|
||||
ucr2 = UCR2_SRST | UCR2_IRTS;
|
||||
|
||||
if (termios->c_cflag & CRTSCTS) {
|
||||
if (sport->have_rtscts) {
|
||||
ucr2 &= ~UCR2_IRTS;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/*
|
||||
* RTS is mandatory for rs485 operation, so keep
|
||||
* it under manual control and keep transmitter
|
||||
* disabled.
|
||||
*/
|
||||
if (port->rs485.flags &
|
||||
SER_RS485_RTS_AFTER_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
} else {
|
||||
imx_uart_rts_auto(sport, &ucr2);
|
||||
}
|
||||
} else {
|
||||
termios->c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
} else if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* disable transmitter */
|
||||
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
}
|
||||
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
ucr2 |= UCR2_STPB;
|
||||
if (termios->c_cflag & PARENB) {
|
||||
ucr2 |= UCR2_PREN;
|
||||
if (termios->c_cflag & PARODD)
|
||||
ucr2 |= UCR2_PROE;
|
||||
}
|
||||
|
||||
del_timer_sync(&sport->timer);
|
||||
|
||||
/*
|
||||
|
@ -1602,6 +1562,45 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/*
|
||||
* Read current UCR2 and save it for future use, then clear all the bits
|
||||
* except those we will or may need to preserve.
|
||||
*/
|
||||
old_ucr2 = imx_uart_readl(sport, UCR2);
|
||||
ucr2 = old_ucr2 & (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN | UCR2_CTS);
|
||||
|
||||
ucr2 |= UCR2_SRST | UCR2_IRTS;
|
||||
if ((termios->c_cflag & CSIZE) == CS8)
|
||||
ucr2 |= UCR2_WS;
|
||||
|
||||
if (!sport->have_rtscts)
|
||||
termios->c_cflag &= ~CRTSCTS;
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
/*
|
||||
* RTS is mandatory for rs485 operation, so keep
|
||||
* it under manual control and keep transmitter
|
||||
* disabled.
|
||||
*/
|
||||
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
|
||||
imx_uart_rts_active(sport, &ucr2);
|
||||
else
|
||||
imx_uart_rts_inactive(sport, &ucr2);
|
||||
|
||||
} else if (termios->c_cflag & CRTSCTS)
|
||||
imx_uart_rts_auto(sport, &ucr2);
|
||||
|
||||
if (termios->c_cflag & CRTSCTS)
|
||||
ucr2 &= ~UCR2_IRTS;
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
ucr2 |= UCR2_STPB;
|
||||
if (termios->c_cflag & PARENB) {
|
||||
ucr2 |= UCR2_PREN;
|
||||
if (termios->c_cflag & PARODD)
|
||||
ucr2 |= UCR2_PROE;
|
||||
}
|
||||
|
||||
sport->port.read_status_mask = 0;
|
||||
if (termios->c_iflag & INPCK)
|
||||
sport->port.read_status_mask |= (URXD_FRMERR | URXD_PRERR);
|
||||
|
@ -1639,7 +1638,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
imx_uart_writel(sport,
|
||||
old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
|
||||
UCR1);
|
||||
old_ucr2 = imx_uart_readl(sport, UCR2);
|
||||
imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2);
|
||||
|
||||
while (!(imx_uart_readl(sport, USR2) & USR2_TXDC))
|
||||
|
@ -1647,7 +1645,6 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
/* then, disable everything */
|
||||
imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2);
|
||||
old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN);
|
||||
|
||||
/* custom-baudrate handling */
|
||||
div = sport->port.uartclk / (baud * 16);
|
||||
|
@ -1685,8 +1682,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
|
||||
imx_uart_writel(sport, old_ucr1, UCR1);
|
||||
|
||||
/* set the parity, stop bits and data size */
|
||||
imx_uart_writel(sport, ucr2 | old_ucr2, UCR2);
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
|
||||
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
|
||||
imx_uart_enable_ms(&sport->port);
|
||||
|
@ -2015,7 +2011,7 @@ imx_uart_console_get_options(struct imx_port *sport, int *baud,
|
|||
}
|
||||
|
||||
if (*baud != baud_raw)
|
||||
pr_info("Console IMX rounded baud rate from %d to %d\n",
|
||||
dev_info(sport->port.dev, "Console IMX rounded baud rate from %d to %d\n",
|
||||
baud_raw, *baud);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,12 +258,17 @@ struct max310x_one {
|
|||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
struct work_struct rs_work;
|
||||
|
||||
u8 wr_header;
|
||||
u8 rd_header;
|
||||
u8 rx_buf[MAX310X_FIFO_SIZE];
|
||||
};
|
||||
#define to_max310x_port(_port) \
|
||||
container_of(_port, struct max310x_one, port)
|
||||
|
||||
struct max310x_port {
|
||||
struct max310x_devtype *devtype;
|
||||
struct regmap *regmap;
|
||||
struct mutex mutex;
|
||||
struct clk *clk;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
struct gpio_chip gpio;
|
||||
|
@ -496,37 +501,48 @@ static bool max310x_reg_precious(struct device *dev, unsigned int reg)
|
|||
|
||||
static int max310x_set_baud(struct uart_port *port, int baud)
|
||||
{
|
||||
unsigned int mode = 0, clk = port->uartclk, div = clk / baud;
|
||||
unsigned int mode = 0, div = 0, frac = 0, c = 0, F = 0;
|
||||
|
||||
/* Check for minimal value for divider */
|
||||
if (div < 16)
|
||||
div = 16;
|
||||
|
||||
if (clk % baud && (div / 16) < 0x8000) {
|
||||
/*
|
||||
* Calculate the integer divisor first. Select a proper mode
|
||||
* in case if the requested baud is too high for the pre-defined
|
||||
* clocks frequency.
|
||||
*/
|
||||
div = port->uartclk / baud;
|
||||
if (div < 8) {
|
||||
/* Mode x4 */
|
||||
c = 4;
|
||||
mode = MAX310X_BRGCFG_4XMODE_BIT;
|
||||
} else if (div < 16) {
|
||||
/* Mode x2 */
|
||||
c = 8;
|
||||
mode = MAX310X_BRGCFG_2XMODE_BIT;
|
||||
clk = port->uartclk * 2;
|
||||
div = clk / baud;
|
||||
|
||||
if (clk % baud && (div / 16) < 0x8000) {
|
||||
/* Mode x4 */
|
||||
mode = MAX310X_BRGCFG_4XMODE_BIT;
|
||||
clk = port->uartclk * 4;
|
||||
div = clk / baud;
|
||||
}
|
||||
} else {
|
||||
c = 16;
|
||||
}
|
||||
|
||||
max310x_port_write(port, MAX310X_BRGDIVMSB_REG, (div / 16) >> 8);
|
||||
max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div / 16);
|
||||
max310x_port_write(port, MAX310X_BRGCFG_REG, (div % 16) | mode);
|
||||
/* Calculate the divisor in accordance with the fraction coefficient */
|
||||
div /= c;
|
||||
F = c*baud;
|
||||
|
||||
return DIV_ROUND_CLOSEST(clk, div);
|
||||
/* Calculate the baud rate fraction */
|
||||
if (div > 0)
|
||||
frac = (16*(port->uartclk % F)) / F;
|
||||
else
|
||||
div = 1;
|
||||
|
||||
max310x_port_write(port, MAX310X_BRGDIVMSB_REG, div >> 8);
|
||||
max310x_port_write(port, MAX310X_BRGDIVLSB_REG, div);
|
||||
max310x_port_write(port, MAX310X_BRGCFG_REG, frac | mode);
|
||||
|
||||
/* Return the actual baud rate we just programmed */
|
||||
return (16*port->uartclk) / (c*(16*div + frac));
|
||||
}
|
||||
|
||||
static int max310x_update_best_err(unsigned long f, long *besterr)
|
||||
{
|
||||
/* Use baudrate 115200 for calculate error */
|
||||
long err = f % (115200 * 16);
|
||||
long err = f % (460800 * 16);
|
||||
|
||||
if ((*besterr < 0) || (*besterr > err)) {
|
||||
*besterr = err;
|
||||
|
@ -607,11 +623,11 @@ static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
|
|||
|
||||
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
|
||||
{
|
||||
u8 header[] = { (port->iobase + MAX310X_THR_REG) | MAX310X_WRITE_BIT };
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
struct spi_transfer xfer[] = {
|
||||
{
|
||||
.tx_buf = &header,
|
||||
.len = sizeof(header),
|
||||
.tx_buf = &one->wr_header,
|
||||
.len = sizeof(one->wr_header),
|
||||
}, {
|
||||
.tx_buf = txbuf,
|
||||
.len = len,
|
||||
|
@ -622,11 +638,11 @@ static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int
|
|||
|
||||
static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
|
||||
{
|
||||
u8 header[] = { port->iobase + MAX310X_RHR_REG };
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
struct spi_transfer xfer[] = {
|
||||
{
|
||||
.tx_buf = &header,
|
||||
.len = sizeof(header),
|
||||
.tx_buf = &one->rd_header,
|
||||
.len = sizeof(one->rd_header),
|
||||
}, {
|
||||
.rx_buf = rxbuf,
|
||||
.len = len,
|
||||
|
@ -637,8 +653,8 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
|
|||
|
||||
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||
{
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
unsigned int sts, ch, flag, i;
|
||||
u8 buf[MAX310X_FIFO_SIZE];
|
||||
|
||||
if (port->read_status_mask == MAX310X_LSR_RXOVR_BIT) {
|
||||
/* We are just reading, happily ignoring any error conditions.
|
||||
|
@ -653,7 +669,7 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
|||
* */
|
||||
|
||||
sts = max310x_port_read(port, MAX310X_LSR_IRQSTS_REG);
|
||||
max310x_batch_read(port, buf, rxlen);
|
||||
max310x_batch_read(port, one->rx_buf, rxlen);
|
||||
|
||||
port->icount.rx += rxlen;
|
||||
flag = TTY_NORMAL;
|
||||
|
@ -664,9 +680,16 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
|||
port->icount.overrun++;
|
||||
}
|
||||
|
||||
for (i = 0; i < rxlen; ++i) {
|
||||
uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT, buf[i], flag);
|
||||
}
|
||||
for (i = 0; i < (rxlen - 1); ++i)
|
||||
uart_insert_char(port, sts, 0, one->rx_buf[i], flag);
|
||||
|
||||
/*
|
||||
* Handle the overrun case for the last character only, since
|
||||
* the RxFIFO overflow happens after it is pushed to the FIFO
|
||||
* tail.
|
||||
*/
|
||||
uart_insert_char(port, sts, MAX310X_LSR_RXOVR_BIT,
|
||||
one->rx_buf[rxlen], flag);
|
||||
|
||||
} else {
|
||||
if (unlikely(rxlen >= port->fifosize)) {
|
||||
|
@ -766,10 +789,9 @@ static void max310x_handle_tx(struct uart_port *port)
|
|||
|
||||
static void max310x_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct max310x_one *one = container_of(port, struct max310x_one, port);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
|
||||
if (!work_pending(&one->tx_work))
|
||||
schedule_work(&one->tx_work);
|
||||
schedule_work(&one->tx_work);
|
||||
}
|
||||
|
||||
static irqreturn_t max310x_port_irq(struct max310x_port *s, int portno)
|
||||
|
@ -826,14 +848,11 @@ static irqreturn_t max310x_ist(int irq, void *dev_id)
|
|||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
static void max310x_wq_proc(struct work_struct *ws)
|
||||
static void max310x_tx_proc(struct work_struct *ws)
|
||||
{
|
||||
struct max310x_one *one = container_of(ws, struct max310x_one, tx_work);
|
||||
struct max310x_port *s = dev_get_drvdata(one->port.dev);
|
||||
|
||||
mutex_lock(&s->mutex);
|
||||
max310x_handle_tx(&one->port);
|
||||
mutex_unlock(&s->mutex);
|
||||
}
|
||||
|
||||
static unsigned int max310x_tx_empty(struct uart_port *port)
|
||||
|
@ -863,7 +882,7 @@ static void max310x_md_proc(struct work_struct *ws)
|
|||
|
||||
static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct max310x_one *one = container_of(port, struct max310x_one, port);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
|
||||
schedule_work(&one->md_work);
|
||||
}
|
||||
|
@ -962,37 +981,36 @@ static void max310x_set_termios(struct uart_port *port,
|
|||
static void max310x_rs_proc(struct work_struct *ws)
|
||||
{
|
||||
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
|
||||
unsigned int val;
|
||||
unsigned int delay, mode1 = 0, mode2 = 0;
|
||||
|
||||
val = (one->port.rs485.delay_rts_before_send << 4) |
|
||||
delay = (one->port.rs485.delay_rts_before_send << 4) |
|
||||
one->port.rs485.delay_rts_after_send;
|
||||
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, val);
|
||||
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
|
||||
|
||||
if (one->port.rs485.flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(&one->port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
} else {
|
||||
max310x_port_update(&one->port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, 0);
|
||||
mode1 = MAX310X_MODE1_TRNSCVCTRL_BIT;
|
||||
|
||||
if (!(one->port.rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
|
||||
}
|
||||
|
||||
max310x_port_update(&one->port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
|
||||
max310x_port_update(&one->port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
|
||||
}
|
||||
|
||||
static int max310x_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct max310x_one *one = container_of(port, struct max310x_one, port);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
|
||||
if ((rs485->delay_rts_before_send > 0x0f) ||
|
||||
(rs485->delay_rts_after_send > 0x0f))
|
||||
return -ERANGE;
|
||||
|
||||
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_ENABLED;
|
||||
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
|
||||
SER_RS485_ENABLED;
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
port->rs485 = *rs485;
|
||||
|
||||
|
@ -1018,6 +1036,22 @@ static int max310x_startup(struct uart_port *port)
|
|||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_FIFORST_BIT, 0);
|
||||
|
||||
/* Configure mode1/mode2 to have rs485/rs232 enabled at startup */
|
||||
val = (clamp(port->rs485.delay_rts_before_send, 0U, 15U) << 4) |
|
||||
clamp(port->rs485.delay_rts_after_send, 0U, 15U);
|
||||
max310x_port_write(port, MAX310X_HDPIXDELAY_REG, val);
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
max310x_port_update(port, MAX310X_MODE1_REG,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT,
|
||||
MAX310X_MODE1_TRNSCVCTRL_BIT);
|
||||
|
||||
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
|
||||
max310x_port_update(port, MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT,
|
||||
MAX310X_MODE2_ECHOSUPR_BIT);
|
||||
}
|
||||
|
||||
/* Configure flow control levels */
|
||||
/* Flow control halt level 96, resume level 48 */
|
||||
max310x_port_write(port, MAX310X_FLOWLVL_REG,
|
||||
|
@ -1269,8 +1303,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
|||
uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
|
||||
dev_dbg(dev, "Reference clock set to %i Hz\n", uartclk);
|
||||
|
||||
mutex_init(&s->mutex);
|
||||
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
unsigned int line;
|
||||
|
||||
|
@ -1298,11 +1330,15 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype,
|
|||
/* Clear IRQ status register */
|
||||
max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG);
|
||||
/* Initialize queue for start TX */
|
||||
INIT_WORK(&s->p[i].tx_work, max310x_wq_proc);
|
||||
INIT_WORK(&s->p[i].tx_work, max310x_tx_proc);
|
||||
/* Initialize queue for changing LOOPBACK mode */
|
||||
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
|
||||
/* Initialize queue for changing RS485 mode */
|
||||
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
|
||||
/* Initialize SPI-transfer buffers */
|
||||
s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) |
|
||||
MAX310X_WRITE_BIT;
|
||||
s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG);
|
||||
|
||||
/* Register port */
|
||||
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
|
||||
|
@ -1350,8 +1386,6 @@ out_uart:
|
|||
}
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
|
||||
out_clk:
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
|
@ -1372,7 +1406,6 @@ static int max310x_remove(struct device *dev)
|
|||
s->devtype->power(&s->p[i].port, 0);
|
||||
}
|
||||
|
||||
mutex_destroy(&s->mutex);
|
||||
clk_disable_unprepare(s->clk);
|
||||
|
||||
return 0;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -383,10 +383,14 @@ no_rx:
|
|||
|
||||
static inline void msm_wait_for_xmitr(struct uart_port *port)
|
||||
{
|
||||
unsigned int timeout = 500000;
|
||||
|
||||
while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) {
|
||||
if (msm_read(port, UART_ISR) & UART_ISR_TX_READY)
|
||||
break;
|
||||
udelay(1);
|
||||
if (!timeout--)
|
||||
break;
|
||||
}
|
||||
msm_write(port, UART_CR_CMD_RESET_TX_READY, UART_CR);
|
||||
}
|
||||
|
|
|
@ -1777,6 +1777,7 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
{
|
||||
struct uart_state *state = container_of(port, struct uart_state, port);
|
||||
struct uart_port *uport;
|
||||
int ret;
|
||||
|
||||
uport = uart_port_check(state);
|
||||
if (!uport || uport->flags & UPF_DEAD)
|
||||
|
@ -1787,7 +1788,11 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty)
|
|||
/*
|
||||
* Start up the serial port.
|
||||
*/
|
||||
return uart_startup(tty, state, 0);
|
||||
ret = uart_startup(tty, state, 0);
|
||||
if (ret > 0)
|
||||
tty_port_set_active(port, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *uart_type(struct uart_port *port)
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/termios.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include "serial_mctrl_gpio.h"
|
||||
|
||||
|
@ -116,6 +117,19 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
|
|||
|
||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
||||
enum gpiod_flags flags;
|
||||
char *gpio_str;
|
||||
bool present;
|
||||
|
||||
/* Check if GPIO property exists and continue if not */
|
||||
gpio_str = kasprintf(GFP_KERNEL, "%s-gpios",
|
||||
mctrl_gpios_desc[i].name);
|
||||
if (!gpio_str)
|
||||
continue;
|
||||
|
||||
present = device_property_present(dev, gpio_str);
|
||||
kfree(gpio_str);
|
||||
if (!present)
|
||||
continue;
|
||||
|
||||
if (mctrl_gpios_desc[i].dir_out)
|
||||
flags = GPIOD_OUT_LOW;
|
||||
|
|
|
@ -1398,6 +1398,7 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long flags;
|
||||
dma_addr_t buf;
|
||||
int head, tail;
|
||||
|
||||
/*
|
||||
* DMA is idle now.
|
||||
|
@ -1407,16 +1408,23 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|||
* consistent xmit buffer state.
|
||||
*/
|
||||
spin_lock_irq(&port->lock);
|
||||
buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1));
|
||||
head = xmit->head;
|
||||
tail = xmit->tail;
|
||||
buf = s->tx_dma_addr + (tail & (UART_XMIT_SIZE - 1));
|
||||
s->tx_dma_len = min_t(unsigned int,
|
||||
CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE),
|
||||
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE));
|
||||
spin_unlock_irq(&port->lock);
|
||||
CIRC_CNT(head, tail, UART_XMIT_SIZE),
|
||||
CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE));
|
||||
if (!s->tx_dma_len) {
|
||||
/* Transmit buffer has been flushed */
|
||||
spin_unlock_irq(&port->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc) {
|
||||
spin_unlock_irq(&port->lock);
|
||||
dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n");
|
||||
goto switch_to_pio;
|
||||
}
|
||||
|
@ -1424,18 +1432,18 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
|
|||
dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
spin_lock_irq(&port->lock);
|
||||
desc->callback = sci_dma_tx_complete;
|
||||
desc->callback_param = s;
|
||||
spin_unlock_irq(&port->lock);
|
||||
s->cookie_tx = dmaengine_submit(desc);
|
||||
if (dma_submit_error(s->cookie_tx)) {
|
||||
spin_unlock_irq(&port->lock);
|
||||
dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n");
|
||||
goto switch_to_pio;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&port->lock);
|
||||
dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
|
||||
__func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx);
|
||||
__func__, xmit->buf, tail, head, s->cookie_tx);
|
||||
|
||||
dma_async_issue_pending(chan);
|
||||
return;
|
||||
|
@ -1648,11 +1656,18 @@ static void sci_free_dma(struct uart_port *port)
|
|||
|
||||
static void sci_flush_buffer(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
/*
|
||||
* In uart_flush_buffer(), the xmit circular buffer has just been
|
||||
* cleared, so we have to reset tx_dma_len accordingly.
|
||||
* cleared, so we have to reset tx_dma_len accordingly, and stop any
|
||||
* pending transfers
|
||||
*/
|
||||
to_sci_port(port)->tx_dma_len = 0;
|
||||
s->tx_dma_len = 0;
|
||||
if (s->chan_tx) {
|
||||
dmaengine_terminate_async(s->chan_tx);
|
||||
s->cookie_tx = -EINVAL;
|
||||
}
|
||||
}
|
||||
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
|
||||
static inline void sci_request_dma(struct uart_port *port)
|
||||
|
|
|
@ -105,9 +105,7 @@ static int stm32_config_rs485(struct uart_port *port,
|
|||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
u32 usartdiv, baud, cr1, cr3;
|
||||
bool over8;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
|
||||
|
||||
port->rs485 = *rs485conf;
|
||||
|
@ -147,7 +145,6 @@ static int stm32_config_rs485(struct uart_port *port,
|
|||
}
|
||||
|
||||
stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit));
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -194,8 +191,8 @@ static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
|
||||
static unsigned long stm32_get_char(struct uart_port *port, u32 *sr,
|
||||
int *last_res)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
@ -205,10 +202,13 @@ stm32_get_char(struct uart_port *port, u32 *sr, int *last_res)
|
|||
c = stm32_port->rx_buf[RX_BUF_L - (*last_res)--];
|
||||
if ((*last_res) == 0)
|
||||
*last_res = RX_BUF_L;
|
||||
return c;
|
||||
} else {
|
||||
return readl_relaxed(port->membase + ofs->rdr);
|
||||
c = readl_relaxed(port->membase + ofs->rdr);
|
||||
/* apply RDR data mask */
|
||||
c &= stm32_port->rdr_mask;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void stm32_receive_chars(struct uart_port *port, bool threaded)
|
||||
|
@ -225,35 +225,51 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded)
|
|||
|
||||
while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) {
|
||||
sr |= USART_SR_DUMMY_RX;
|
||||
c = stm32_get_char(port, &sr, &stm32_port->last_res);
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
/*
|
||||
* Status bits has to be cleared before reading the RDR:
|
||||
* In FIFO mode, reading the RDR will pop the next data
|
||||
* (if any) along with its status bits into the SR.
|
||||
* Not doing so leads to misalignement between RDR and SR,
|
||||
* and clear status bits of the next rx data.
|
||||
*
|
||||
* Clear errors flags for stm32f7 and stm32h7 compatible
|
||||
* devices. On stm32f4 compatible devices, the error bit is
|
||||
* cleared by the sequence [read SR - read DR].
|
||||
*/
|
||||
if ((sr & USART_SR_ERR_MASK) && ofs->icr != UNDEF_REG)
|
||||
stm32_clr_bits(port, ofs->icr, USART_ICR_ORECF |
|
||||
USART_ICR_PECF | USART_ICR_FECF);
|
||||
|
||||
c = stm32_get_char(port, &sr, &stm32_port->last_res);
|
||||
port->icount.rx++;
|
||||
if (sr & USART_SR_ERR_MASK) {
|
||||
if (sr & USART_SR_LBD) {
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (sr & USART_SR_ORE) {
|
||||
if (ofs->icr != UNDEF_REG)
|
||||
writel_relaxed(USART_ICR_ORECF,
|
||||
port->membase +
|
||||
ofs->icr);
|
||||
if (sr & USART_SR_ORE) {
|
||||
port->icount.overrun++;
|
||||
} else if (sr & USART_SR_PE) {
|
||||
port->icount.parity++;
|
||||
} else if (sr & USART_SR_FE) {
|
||||
port->icount.frame++;
|
||||
/* Break detection if character is null */
|
||||
if (!c) {
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else {
|
||||
port->icount.frame++;
|
||||
}
|
||||
}
|
||||
|
||||
sr &= port->read_status_mask;
|
||||
|
||||
if (sr & USART_SR_LBD)
|
||||
flag = TTY_BREAK;
|
||||
else if (sr & USART_SR_PE)
|
||||
if (sr & USART_SR_PE) {
|
||||
flag = TTY_PARITY;
|
||||
else if (sr & USART_SR_FE)
|
||||
flag = TTY_FRAME;
|
||||
} else if (sr & USART_SR_FE) {
|
||||
if (!c)
|
||||
flag = TTY_BREAK;
|
||||
else
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(port, c))
|
||||
|
@ -271,21 +287,6 @@ static void stm32_tx_dma_complete(void *arg)
|
|||
struct uart_port *port = arg;
|
||||
struct stm32_port *stm32port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
|
||||
unsigned int isr;
|
||||
int ret;
|
||||
|
||||
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
|
||||
isr,
|
||||
(isr & USART_SR_TC),
|
||||
10, 100000);
|
||||
|
||||
if (ret)
|
||||
dev_err(port->dev, "terminal count not set\n");
|
||||
|
||||
if (ofs->icr == UNDEF_REG)
|
||||
stm32_clr_bits(port, ofs->isr, USART_SR_TC);
|
||||
else
|
||||
stm32_set_bits(port, ofs->icr, USART_CR_TC);
|
||||
|
||||
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
|
||||
stm32port->tx_dma_busy = false;
|
||||
|
@ -294,32 +295,57 @@ static void stm32_tx_dma_complete(void *arg)
|
|||
stm32_transmit_chars(port);
|
||||
}
|
||||
|
||||
static void stm32_tx_interrupt_enable(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
||||
/*
|
||||
* Enables TX FIFO threashold irq when FIFO is enabled,
|
||||
* or TX empty irq when FIFO is disabled
|
||||
*/
|
||||
if (stm32_port->fifoen)
|
||||
stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE);
|
||||
else
|
||||
stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
||||
}
|
||||
|
||||
static void stm32_tx_interrupt_disable(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
||||
if (stm32_port->fifoen)
|
||||
stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE);
|
||||
else
|
||||
stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
||||
}
|
||||
|
||||
static void stm32_transmit_chars_pio(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int isr;
|
||||
int ret;
|
||||
|
||||
if (stm32_port->tx_dma_busy) {
|
||||
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT);
|
||||
stm32_port->tx_dma_busy = false;
|
||||
}
|
||||
|
||||
ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr,
|
||||
isr,
|
||||
(isr & USART_SR_TXE),
|
||||
10, 100000);
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
/* Check that TDR is empty before filling FIFO */
|
||||
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
|
||||
break;
|
||||
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(port->dev, "tx empty not set\n");
|
||||
|
||||
stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
||||
|
||||
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
/* rely on TXE irq (mask or unmask) for sending remaining data */
|
||||
if (uart_circ_empty(xmit))
|
||||
stm32_tx_interrupt_disable(port);
|
||||
else
|
||||
stm32_tx_interrupt_enable(port);
|
||||
}
|
||||
|
||||
static void stm32_transmit_chars_dma(struct uart_port *port)
|
||||
|
@ -377,7 +403,6 @@ static void stm32_transmit_chars_dma(struct uart_port *port)
|
|||
/* Issue pending DMA TX requests */
|
||||
dma_async_issue_pending(stm32port->tx_ch);
|
||||
|
||||
stm32_clr_bits(port, ofs->isr, USART_SR_TC);
|
||||
stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT);
|
||||
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
|
@ -401,15 +426,15 @@ static void stm32_transmit_chars(struct uart_port *port)
|
|||
return;
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(port)) {
|
||||
stm32_stop_tx(port);
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
stm32_tx_interrupt_disable(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
stm32_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
if (ofs->icr == UNDEF_REG)
|
||||
stm32_clr_bits(port, ofs->isr, USART_SR_TC);
|
||||
else
|
||||
stm32_set_bits(port, ofs->icr, USART_ICR_TCCF);
|
||||
|
||||
if (stm32_port->tx_ch)
|
||||
stm32_transmit_chars_dma(port);
|
||||
|
@ -420,7 +445,7 @@ static void stm32_transmit_chars(struct uart_port *port)
|
|||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
stm32_stop_tx(port);
|
||||
stm32_tx_interrupt_disable(port);
|
||||
}
|
||||
|
||||
static irqreturn_t stm32_interrupt(int irq, void *ptr)
|
||||
|
@ -434,6 +459,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr)
|
|||
|
||||
sr = readl_relaxed(port->membase + ofs->isr);
|
||||
|
||||
if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG)
|
||||
writel_relaxed(USART_ICR_RTOCF,
|
||||
port->membase + ofs->icr);
|
||||
|
||||
if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG))
|
||||
writel_relaxed(USART_ICR_WUCF,
|
||||
port->membase + ofs->icr);
|
||||
|
@ -495,10 +524,7 @@ static unsigned int stm32_get_mctrl(struct uart_port *port)
|
|||
/* Transmit stop */
|
||||
static void stm32_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
||||
stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE);
|
||||
stm32_tx_interrupt_disable(port);
|
||||
}
|
||||
|
||||
/* There are probably characters waiting to be transmitted. */
|
||||
|
@ -520,7 +546,10 @@ static void stm32_throttle(struct uart_port *port)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
|
||||
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
||||
if (stm32_port->cr3_irq)
|
||||
stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -532,7 +561,10 @@ static void stm32_unthrottle(struct uart_port *port)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
stm32_set_bits(port, ofs->cr1, USART_CR1_RXNEIE);
|
||||
stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
||||
if (stm32_port->cr3_irq)
|
||||
stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
|
@ -542,7 +574,10 @@ static void stm32_stop_rx(struct uart_port *port)
|
|||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
|
||||
stm32_clr_bits(port, ofs->cr1, USART_CR1_RXNEIE);
|
||||
stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq);
|
||||
if (stm32_port->cr3_irq)
|
||||
stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq);
|
||||
|
||||
}
|
||||
|
||||
/* Handle breaks - ignored by us */
|
||||
|
@ -554,7 +589,6 @@ static int stm32_startup(struct uart_port *port)
|
|||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
const char *name = to_platform_device(port->dev)->name;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
@ -565,16 +599,21 @@ static int stm32_startup(struct uart_port *port)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cfg->has_wakeup && stm32_port->wakeirq >= 0) {
|
||||
ret = dev_pm_set_dedicated_wake_irq(port->dev,
|
||||
stm32_port->wakeirq);
|
||||
if (ret) {
|
||||
free_irq(port->irq, port);
|
||||
return ret;
|
||||
}
|
||||
/* RX FIFO Flush */
|
||||
if (ofs->rqr != UNDEF_REG)
|
||||
stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ);
|
||||
|
||||
/* Tx and RX FIFO configuration */
|
||||
if (stm32_port->fifoen) {
|
||||
val = readl_relaxed(port->membase + ofs->cr3);
|
||||
val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK);
|
||||
val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT;
|
||||
val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT;
|
||||
writel_relaxed(val, port->membase + ofs->cr3);
|
||||
}
|
||||
|
||||
val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
|
||||
/* RX FIFO enabling */
|
||||
val = stm32_port->cr1_irq | USART_CR1_RE;
|
||||
if (stm32_port->fifoen)
|
||||
val |= USART_CR1_FIFOEN;
|
||||
stm32_set_bits(port, ofs->cr1, val);
|
||||
|
@ -587,18 +626,57 @@ static void stm32_shutdown(struct uart_port *port)
|
|||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
u32 val;
|
||||
u32 val, isr;
|
||||
int ret;
|
||||
|
||||
val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;
|
||||
val = USART_CR1_TXEIE | USART_CR1_TE;
|
||||
val |= stm32_port->cr1_irq | USART_CR1_RE;
|
||||
val |= BIT(cfg->uart_enable_bit);
|
||||
if (stm32_port->fifoen)
|
||||
val |= USART_CR1_FIFOEN;
|
||||
|
||||
ret = readl_relaxed_poll_timeout(port->membase + ofs->isr,
|
||||
isr, (isr & USART_SR_TC),
|
||||
10, 100000);
|
||||
|
||||
if (ret)
|
||||
dev_err(port->dev, "transmission complete not set\n");
|
||||
|
||||
stm32_clr_bits(port, ofs->cr1, val);
|
||||
|
||||
dev_pm_clear_wake_irq(port->dev);
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
static unsigned int stm32_get_databits(struct ktermios *termios)
|
||||
{
|
||||
unsigned int bits;
|
||||
|
||||
tcflag_t cflag = termios->c_cflag;
|
||||
|
||||
switch (cflag & CSIZE) {
|
||||
/*
|
||||
* CSIZE settings are not necessarily supported in hardware.
|
||||
* CSIZE unsupported configurations are handled here to set word length
|
||||
* to 8 bits word as default configuration and to print debug message.
|
||||
*/
|
||||
case CS5:
|
||||
bits = 5;
|
||||
break;
|
||||
case CS6:
|
||||
bits = 6;
|
||||
break;
|
||||
case CS7:
|
||||
bits = 7;
|
||||
break;
|
||||
/* default including CS8 */
|
||||
default:
|
||||
bits = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
|
@ -606,7 +684,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
struct serial_rs485 *rs485conf = &port->rs485;
|
||||
unsigned int baud;
|
||||
unsigned int baud, bits;
|
||||
u32 usartdiv, mantissa, fraction, oversampling;
|
||||
tcflag_t cflag = termios->c_cflag;
|
||||
u32 cr1, cr2, cr3;
|
||||
|
@ -622,26 +700,64 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
/* Stop serial port and reset value */
|
||||
writel_relaxed(0, port->membase + ofs->cr1);
|
||||
|
||||
cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE;
|
||||
/* flush RX & TX FIFO */
|
||||
if (ofs->rqr != UNDEF_REG)
|
||||
stm32_set_bits(port, ofs->rqr,
|
||||
USART_RQR_TXFRQ | USART_RQR_RXFRQ);
|
||||
|
||||
cr1 = USART_CR1_TE | USART_CR1_RE;
|
||||
if (stm32_port->fifoen)
|
||||
cr1 |= USART_CR1_FIFOEN;
|
||||
cr2 = 0;
|
||||
cr3 = 0;
|
||||
cr3 = readl_relaxed(port->membase + ofs->cr3);
|
||||
cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE
|
||||
| USART_CR3_TXFTCFG_MASK;
|
||||
|
||||
if (cflag & CSTOPB)
|
||||
cr2 |= USART_CR2_STOP_2B;
|
||||
|
||||
bits = stm32_get_databits(termios);
|
||||
stm32_port->rdr_mask = (BIT(bits) - 1);
|
||||
|
||||
if (cflag & PARENB) {
|
||||
bits++;
|
||||
cr1 |= USART_CR1_PCE;
|
||||
if ((cflag & CSIZE) == CS8) {
|
||||
if (cfg->has_7bits_data)
|
||||
cr1 |= USART_CR1_M0;
|
||||
else
|
||||
cr1 |= USART_CR1_M;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Word length configuration:
|
||||
* CS8 + parity, 9 bits word aka [M1:M0] = 0b01
|
||||
* CS7 or (CS6 + parity), 7 bits word aka [M1:M0] = 0b10
|
||||
* CS8 or (CS7 + parity), 8 bits word aka [M1:M0] = 0b00
|
||||
* M0 and M1 already cleared by cr1 initialization.
|
||||
*/
|
||||
if (bits == 9)
|
||||
cr1 |= USART_CR1_M0;
|
||||
else if ((bits == 7) && cfg->has_7bits_data)
|
||||
cr1 |= USART_CR1_M1;
|
||||
else if (bits != 8)
|
||||
dev_dbg(port->dev, "Unsupported data bits config: %u bits\n"
|
||||
, bits);
|
||||
|
||||
if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch ||
|
||||
stm32_port->fifoen)) {
|
||||
if (cflag & CSTOPB)
|
||||
bits = bits + 3; /* 1 start bit + 2 stop bits */
|
||||
else
|
||||
bits = bits + 2; /* 1 start bit + 1 stop bit */
|
||||
|
||||
/* RX timeout irq to occur after last stop bit + bits */
|
||||
stm32_port->cr1_irq = USART_CR1_RTOIE;
|
||||
writel_relaxed(bits, port->membase + ofs->rtor);
|
||||
cr2 |= USART_CR2_RTOEN;
|
||||
/* Not using dma, enable fifo threshold irq */
|
||||
if (!stm32_port->rx_ch)
|
||||
stm32_port->cr3_irq = USART_CR3_RXFTIE;
|
||||
}
|
||||
|
||||
cr1 |= stm32_port->cr1_irq;
|
||||
cr3 |= stm32_port->cr3_irq;
|
||||
|
||||
if (cflag & PARODD)
|
||||
cr1 |= USART_CR1_PS;
|
||||
|
||||
|
@ -679,14 +795,14 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= USART_SR_PE | USART_SR_FE;
|
||||
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
port->read_status_mask |= USART_SR_LBD;
|
||||
port->read_status_mask |= USART_SR_FE;
|
||||
|
||||
/* Characters to ignore */
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
|
||||
if (termios->c_iflag & IGNBRK) {
|
||||
port->ignore_status_mask |= USART_SR_LBD;
|
||||
port->ignore_status_mask |= USART_SR_FE;
|
||||
/*
|
||||
* If we're ignoring parity and break indicators,
|
||||
* ignore overruns too (for real raw support).
|
||||
|
@ -808,12 +924,32 @@ static int stm32_init_port(struct stm32_port *stm32port,
|
|||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->ops = &stm32_uart_ops;
|
||||
port->dev = &pdev->dev;
|
||||
port->irq = platform_get_irq(pdev, 0);
|
||||
port->fifosize = stm32port->info->cfg.fifosize;
|
||||
|
||||
ret = platform_get_irq(pdev, 0);
|
||||
if (ret <= 0) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Can't get event IRQ: %d\n", ret);
|
||||
return ret ? ret : -ENODEV;
|
||||
}
|
||||
port->irq = ret;
|
||||
|
||||
port->rs485_config = stm32_config_rs485;
|
||||
|
||||
stm32_init_rs485(port, pdev);
|
||||
|
||||
stm32port->wakeirq = platform_get_irq(pdev, 1);
|
||||
if (stm32port->info->cfg.has_wakeup) {
|
||||
stm32port->wakeirq = platform_get_irq(pdev, 1);
|
||||
if (stm32port->wakeirq <= 0 && stm32port->wakeirq != -ENXIO) {
|
||||
if (stm32port->wakeirq != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
"Can't get event wake IRQ: %d\n",
|
||||
stm32port->wakeirq);
|
||||
return stm32port->wakeirq ? stm32port->wakeirq :
|
||||
-ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
stm32port->fifoen = stm32port->info->cfg.has_fifo;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
@ -862,6 +998,8 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev)
|
|||
stm32_ports[id].hw_flow_control = of_property_read_bool(np,
|
||||
"st,hw-flow-ctrl");
|
||||
stm32_ports[id].port.line = id;
|
||||
stm32_ports[id].cr1_irq = USART_CR1_RXNEIE;
|
||||
stm32_ports[id].cr3_irq = 0;
|
||||
stm32_ports[id].last_res = RX_BUF_L;
|
||||
return &stm32_ports[id];
|
||||
}
|
||||
|
@ -1020,15 +1158,22 @@ static int stm32_serial_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) {
|
||||
if (stm32port->wakeirq > 0) {
|
||||
ret = device_init_wakeup(&pdev->dev, true);
|
||||
if (ret)
|
||||
goto err_uninit;
|
||||
|
||||
ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
|
||||
stm32port->wakeirq);
|
||||
if (ret)
|
||||
goto err_nowup;
|
||||
|
||||
device_set_wakeup_enable(&pdev->dev, false);
|
||||
}
|
||||
|
||||
ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port);
|
||||
if (ret)
|
||||
goto err_nowup;
|
||||
goto err_wirq;
|
||||
|
||||
ret = stm32_of_dma_rx_probe(stm32port, pdev);
|
||||
if (ret)
|
||||
|
@ -1042,8 +1187,12 @@ static int stm32_serial_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_wirq:
|
||||
if (stm32port->wakeirq > 0)
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
|
||||
err_nowup:
|
||||
if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0)
|
||||
if (stm32port->wakeirq > 0)
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
err_uninit:
|
||||
|
@ -1057,7 +1206,6 @@ static int stm32_serial_remove(struct platform_device *pdev)
|
|||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
|
||||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
|
||||
stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR);
|
||||
|
||||
|
@ -1079,8 +1227,10 @@ static int stm32_serial_remove(struct platform_device *pdev)
|
|||
TX_BUF_L, stm32_port->tx_buf,
|
||||
stm32_port->tx_dma_buf);
|
||||
|
||||
if (cfg->has_wakeup && stm32_port->wakeirq >= 0)
|
||||
if (stm32_port->wakeirq > 0) {
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
}
|
||||
|
||||
clk_disable_unprepare(stm32_port->clk);
|
||||
|
||||
|
@ -1195,7 +1345,7 @@ static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable)
|
|||
struct stm32_usart_config *cfg = &stm32_port->info->cfg;
|
||||
u32 val;
|
||||
|
||||
if (!cfg->has_wakeup || stm32_port->wakeirq < 0)
|
||||
if (stm32_port->wakeirq <= 0)
|
||||
return;
|
||||
|
||||
if (enable) {
|
||||
|
|
|
@ -27,6 +27,7 @@ struct stm32_usart_config {
|
|||
bool has_7bits_data;
|
||||
bool has_wakeup;
|
||||
bool has_fifo;
|
||||
int fifosize;
|
||||
};
|
||||
|
||||
struct stm32_usart_info {
|
||||
|
@ -54,6 +55,7 @@ struct stm32_usart_info stm32f4_info = {
|
|||
.cfg = {
|
||||
.uart_enable_bit = 13,
|
||||
.has_7bits_data = false,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -74,6 +76,7 @@ struct stm32_usart_info stm32f7_info = {
|
|||
.cfg = {
|
||||
.uart_enable_bit = 0,
|
||||
.has_7bits_data = true,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -96,6 +99,7 @@ struct stm32_usart_info stm32h7_info = {
|
|||
.has_7bits_data = true,
|
||||
.has_wakeup = true,
|
||||
.has_fifo = true,
|
||||
.fifosize = 16,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -108,7 +112,6 @@ struct stm32_usart_info stm32h7_info = {
|
|||
#define USART_SR_RXNE BIT(5)
|
||||
#define USART_SR_TC BIT(6)
|
||||
#define USART_SR_TXE BIT(7)
|
||||
#define USART_SR_LBD BIT(8)
|
||||
#define USART_SR_CTSIF BIT(9)
|
||||
#define USART_SR_CTS BIT(10) /* F7 */
|
||||
#define USART_SR_RTOF BIT(11) /* F7 */
|
||||
|
@ -120,8 +123,7 @@ struct stm32_usart_info stm32h7_info = {
|
|||
#define USART_SR_SBKF BIT(18) /* F7 */
|
||||
#define USART_SR_WUF BIT(20) /* H7 */
|
||||
#define USART_SR_TEACK BIT(21) /* F7 */
|
||||
#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \
|
||||
USART_SR_FE | USART_SR_PE)
|
||||
#define USART_SR_ERR_MASK (USART_SR_ORE | USART_SR_FE | USART_SR_PE)
|
||||
/* Dummy bits */
|
||||
#define USART_SR_DUMMY_RX BIT(16)
|
||||
|
||||
|
@ -151,8 +153,7 @@ struct stm32_usart_info stm32h7_info = {
|
|||
#define USART_CR1_PS BIT(9)
|
||||
#define USART_CR1_PCE BIT(10)
|
||||
#define USART_CR1_WAKE BIT(11)
|
||||
#define USART_CR1_M BIT(12)
|
||||
#define USART_CR1_M0 BIT(12) /* F7 */
|
||||
#define USART_CR1_M0 BIT(12) /* F7 (CR1_M for F4) */
|
||||
#define USART_CR1_MME BIT(13) /* F7 */
|
||||
#define USART_CR1_CMIE BIT(14) /* F7 */
|
||||
#define USART_CR1_OVER8 BIT(15)
|
||||
|
@ -169,8 +170,6 @@ struct stm32_usart_info stm32h7_info = {
|
|||
/* USART_CR2 */
|
||||
#define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */
|
||||
#define USART_CR2_ADDM7 BIT(4) /* F7 */
|
||||
#define USART_CR2_LBDL BIT(5)
|
||||
#define USART_CR2_LBDIE BIT(6)
|
||||
#define USART_CR2_LBCL BIT(8)
|
||||
#define USART_CR2_CPHA BIT(9)
|
||||
#define USART_CR2_CPOL BIT(10)
|
||||
|
@ -209,6 +208,19 @@ struct stm32_usart_info stm32h7_info = {
|
|||
#define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */
|
||||
#define USART_CR3_WUS_START_BIT BIT(21) /* H7 */
|
||||
#define USART_CR3_WUFIE BIT(22) /* H7 */
|
||||
#define USART_CR3_TXFTIE BIT(23) /* H7 */
|
||||
#define USART_CR3_TCBGTIE BIT(24) /* H7 */
|
||||
#define USART_CR3_RXFTCFG_MASK GENMASK(27, 25) /* H7 */
|
||||
#define USART_CR3_RXFTCFG_SHIFT 25 /* H7 */
|
||||
#define USART_CR3_RXFTIE BIT(28) /* H7 */
|
||||
#define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */
|
||||
#define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */
|
||||
|
||||
/* TX FIFO threashold set to half of its depth */
|
||||
#define USART_CR3_TXFTCFG_HALF 0x2
|
||||
|
||||
/* RX FIFO threashold set to half of its depth */
|
||||
#define USART_CR3_RXFTCFG_HALF 0x2
|
||||
|
||||
/* USART_GTPR */
|
||||
#define USART_GTPR_PSC_MASK GENMASK(7, 0)
|
||||
|
@ -227,12 +239,10 @@ struct stm32_usart_info stm32h7_info = {
|
|||
|
||||
/* USART_ICR */
|
||||
#define USART_ICR_PECF BIT(0) /* F7 */
|
||||
#define USART_ICR_FFECF BIT(1) /* F7 */
|
||||
#define USART_ICR_NCF BIT(2) /* F7 */
|
||||
#define USART_ICR_FECF BIT(1) /* F7 */
|
||||
#define USART_ICR_ORECF BIT(3) /* F7 */
|
||||
#define USART_ICR_IDLECF BIT(4) /* F7 */
|
||||
#define USART_ICR_TCCF BIT(6) /* F7 */
|
||||
#define USART_ICR_LBDCF BIT(8) /* F7 */
|
||||
#define USART_ICR_CTSCF BIT(9) /* F7 */
|
||||
#define USART_ICR_RTOCF BIT(11) /* F7 */
|
||||
#define USART_ICR_EOBCF BIT(12) /* F7 */
|
||||
|
@ -256,11 +266,14 @@ struct stm32_port {
|
|||
struct dma_chan *tx_ch; /* dma tx channel */
|
||||
dma_addr_t tx_dma_buf; /* dma tx buffer bus address */
|
||||
unsigned char *tx_buf; /* dma tx buffer cpu address */
|
||||
u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */
|
||||
u32 cr3_irq; /* USART_CR3_RXFTIE */
|
||||
int last_res;
|
||||
bool tx_dma_busy; /* dma tx busy */
|
||||
bool hw_flow_control;
|
||||
bool fifoen;
|
||||
int wakeirq;
|
||||
int rdr_mask; /* receive data register mask */
|
||||
};
|
||||
|
||||
static struct stm32_port stm32_ports[STM32_MAX_PORTS];
|
||||
|
|
|
@ -26,21 +26,23 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#define CDNS_UART_TTY_NAME "ttyPS"
|
||||
#define CDNS_UART_NAME "xuartps"
|
||||
#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
|
||||
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
|
||||
#define CDNS_UART_REGISTER_SPACE 0x1000
|
||||
#define TX_TIMEOUT 500000
|
||||
|
||||
/* Rx Trigger level */
|
||||
static int rx_trigger_level = 56;
|
||||
module_param(rx_trigger_level, uint, S_IRUGO);
|
||||
static int uartps_major;
|
||||
module_param(rx_trigger_level, uint, 0444);
|
||||
MODULE_PARM_DESC(rx_trigger_level, "Rx trigger level, 1-63 bytes");
|
||||
|
||||
/* Rx Timeout */
|
||||
static int rx_timeout = 10;
|
||||
module_param(rx_timeout, uint, S_IRUGO);
|
||||
module_param(rx_timeout, uint, 0444);
|
||||
MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
|
||||
|
||||
/* Register offsets for the UART. */
|
||||
|
@ -199,7 +201,7 @@ struct cdns_platform_data {
|
|||
u32 quirks;
|
||||
};
|
||||
#define to_cdns_uart(_nb) container_of(_nb, struct cdns_uart, \
|
||||
clk_rate_change_nb);
|
||||
clk_rate_change_nb)
|
||||
|
||||
/**
|
||||
* cdns_uart_handle_rx - Handle the received bytes along with Rx errors.
|
||||
|
@ -312,15 +314,16 @@ static void cdns_uart_handle_tx(void *dev_id)
|
|||
} else {
|
||||
numbytes = port->fifosize;
|
||||
while (numbytes && !uart_circ_empty(&port->state->xmit) &&
|
||||
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
|
||||
!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_TXFULL)) {
|
||||
/*
|
||||
* Get the data from the UART circular buffer
|
||||
* and write it to the cdns_uart's TX_FIFO
|
||||
* register.
|
||||
*/
|
||||
writel(
|
||||
port->state->xmit.buf[port->state->xmit.
|
||||
tail], port->membase + CDNS_UART_FIFO);
|
||||
port->state->xmit.buf[port->state->xmit.tail],
|
||||
port->membase + CDNS_UART_FIFO);
|
||||
|
||||
port->icount.tx++;
|
||||
|
||||
|
@ -684,18 +687,21 @@ static void cdns_uart_set_termios(struct uart_port *port,
|
|||
unsigned int cval = 0;
|
||||
unsigned int baud, minbaud, maxbaud;
|
||||
unsigned long flags;
|
||||
unsigned int ctrl_reg, mode_reg;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
unsigned int ctrl_reg, mode_reg, val;
|
||||
int err;
|
||||
|
||||
/* Wait for the transmit FIFO to empty before making changes */
|
||||
if (!(readl(port->membase + CDNS_UART_CR) &
|
||||
CDNS_UART_CR_TX_DIS)) {
|
||||
while (!(readl(port->membase + CDNS_UART_SR) &
|
||||
CDNS_UART_SR_TXEMPTY)) {
|
||||
cpu_relax();
|
||||
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 */
|
||||
ctrl_reg = readl(port->membase + CDNS_UART_CR);
|
||||
|
@ -1073,8 +1079,6 @@ static void cdns_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
|||
cpu_relax();
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1517,7 +1521,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
cdns_uart_uart_driver->owner = THIS_MODULE;
|
||||
cdns_uart_uart_driver->driver_name = driver_name;
|
||||
cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
|
||||
cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
|
||||
cdns_uart_uart_driver->major = uartps_major;
|
||||
cdns_uart_uart_driver->minor = cdns_uart_data->id;
|
||||
cdns_uart_uart_driver->nr = 1;
|
||||
|
||||
|
@ -1546,6 +1550,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
|||
goto err_out_id;
|
||||
}
|
||||
|
||||
uartps_major = cdns_uart_uart_driver->tty_driver->major;
|
||||
cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1837,7 +1837,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
|
|||
static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
||||
int *index)
|
||||
{
|
||||
struct tty_driver *driver;
|
||||
struct tty_driver *driver = NULL;
|
||||
|
||||
switch (device) {
|
||||
#ifdef CONFIG_VT
|
||||
|
@ -1858,6 +1858,8 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (driver)
|
||||
tty_driver_kref_put(driver);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -918,52 +918,6 @@
|
|||
|
||||
extern void mv64340_irq_init(unsigned int base);
|
||||
|
||||
/* MPSC Platform Device, Driver Data (Shared register regions) */
|
||||
#define MPSC_SHARED_NAME "mpsc_shared"
|
||||
|
||||
#define MPSC_ROUTING_BASE_ORDER 0
|
||||
#define MPSC_SDMA_INTR_BASE_ORDER 1
|
||||
|
||||
#define MPSC_ROUTING_REG_BLOCK_SIZE 0x000c
|
||||
#define MPSC_SDMA_INTR_REG_BLOCK_SIZE 0x0084
|
||||
|
||||
struct mpsc_shared_pdata {
|
||||
u32 mrr_val;
|
||||
u32 rcrr_val;
|
||||
u32 tcrr_val;
|
||||
u32 intr_cause_val;
|
||||
u32 intr_mask_val;
|
||||
};
|
||||
|
||||
/* MPSC Platform Device, Driver Data */
|
||||
#define MPSC_CTLR_NAME "mpsc"
|
||||
|
||||
#define MPSC_BASE_ORDER 0
|
||||
#define MPSC_SDMA_BASE_ORDER 1
|
||||
#define MPSC_BRG_BASE_ORDER 2
|
||||
|
||||
#define MPSC_REG_BLOCK_SIZE 0x0038
|
||||
#define MPSC_SDMA_REG_BLOCK_SIZE 0x0c18
|
||||
#define MPSC_BRG_REG_BLOCK_SIZE 0x0008
|
||||
|
||||
struct mpsc_pdata {
|
||||
u8 mirror_regs;
|
||||
u8 cache_mgmt;
|
||||
u8 max_idle;
|
||||
int default_baud;
|
||||
int default_bits;
|
||||
int default_parity;
|
||||
int default_flow;
|
||||
u32 chr_1_val;
|
||||
u32 chr_2_val;
|
||||
u32 chr_10_val;
|
||||
u32 mpcr_val;
|
||||
u32 bcr_val;
|
||||
u8 brg_can_tune;
|
||||
u8 brg_clk_src;
|
||||
u32 brg_clk_freq;
|
||||
};
|
||||
|
||||
/* Watchdog Platform Device, Driver Data */
|
||||
#define MV64x60_WDT_NAME "mv64x60_wdt"
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ struct uart_8250_port {
|
|||
* if no_console_suspend
|
||||
*/
|
||||
unsigned char probe;
|
||||
struct mctrl_gpios *gpios;
|
||||
#define UART_PROBE_RSA (1 << 0)
|
||||
|
||||
/*
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
/* Motorola i.MX SoC */
|
||||
#define PORT_IMX 62
|
||||
|
||||
/* Marvell MPSC */
|
||||
/* Marvell MPSC (obsolete unused) */
|
||||
#define PORT_MPSC 63
|
||||
|
||||
/* TXX9 type number */
|
||||
|
|
Загрузка…
Ссылка в новой задаче