Commit 9be1064f authored by Daniel Golle's avatar Daniel Golle Committed by Greg Kroah-Hartman

serial: ar933x_uart: add RS485 support

Emulate half-duplex operation and use mctrl_gpio to add support for
RS485 tranceiver with transmit/receive switch hooked to RTS GPIO line.
This is needed to make use of the RS485 port found on Teltonika RUT955.
Signed-off-by: default avatarDaniel Golle <daniel@makrotopia.org>
Link: https://lore.kernel.org/r/20200221212331.GA21467@makrotopia.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9fa3c4b1
...@@ -1269,6 +1269,7 @@ config SERIAL_AR933X ...@@ -1269,6 +1269,7 @@ config SERIAL_AR933X
tristate "AR933X serial port support" tristate "AR933X serial port support"
depends on HAVE_CLK && ATH79 depends on HAVE_CLK && ATH79
select SERIAL_CORE select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
help help
If you have an Atheros AR933X SOC based board and want to use the If you have an Atheros AR933X SOC based board and want to use the
built-in UART of the SoC, say Y to this option. built-in UART of the SoC, say Y to this option.
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/console.h> #include <linux/console.h>
#include <linux/sysrq.h> #include <linux/sysrq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
...@@ -29,6 +30,8 @@ ...@@ -29,6 +30,8 @@
#include <asm/mach-ath79/ar933x_uart.h> #include <asm/mach-ath79/ar933x_uart.h>
#include "serial_mctrl_gpio.h"
#define DRIVER_NAME "ar933x-uart" #define DRIVER_NAME "ar933x-uart"
#define AR933X_UART_MAX_SCALE 0xff #define AR933X_UART_MAX_SCALE 0xff
...@@ -47,6 +50,8 @@ struct ar933x_uart_port { ...@@ -47,6 +50,8 @@ struct ar933x_uart_port {
unsigned int min_baud; unsigned int min_baud;
unsigned int max_baud; unsigned int max_baud;
struct clk *clk; struct clk *clk;
struct mctrl_gpios *gpios;
struct gpio_desc *rts_gpiod;
}; };
static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
...@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up) ...@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier); ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
} }
static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up)
{
up->ier |= AR933X_UART_INT_RX_VALID;
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}
static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up)
{
up->ier &= ~AR933X_UART_INT_RX_VALID;
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}
static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch) static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
{ {
unsigned int rdata; unsigned int rdata;
...@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port) ...@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port)
static unsigned int ar933x_uart_get_mctrl(struct uart_port *port) static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
{ {
return TIOCM_CAR; struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
mctrl_gpio_get(up->gpios, &ret);
return ret;
} }
static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
mctrl_gpio_set(up->gpios, mctrl);
} }
static void ar933x_uart_start_tx(struct uart_port *port) static void ar933x_uart_start_tx(struct uart_port *port)
...@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port) ...@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port)
ar933x_uart_start_tx_interrupt(up); ar933x_uart_start_tx_interrupt(up);
} }
static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up)
{
unsigned int status;
unsigned int timeout = 60000;
/* Wait up to 60ms for the character(s) to be sent. */
do {
status = ar933x_uart_read(up, AR933X_UART_CS_REG);
if (--timeout == 0)
break;
udelay(1);
} while (status & AR933X_UART_CS_TX_BUSY);
if (timeout == 0)
dev_err(up->port.dev, "waiting for TX timed out\n");
}
static void ar933x_uart_rx_flush(struct ar933x_uart_port *up)
{
unsigned int status;
/* clear RX_VALID interrupt */
ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID);
/* remove characters from the RX FIFO */
do {
ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
} while (status & AR933X_UART_DATA_RX_CSR);
}
static void ar933x_uart_stop_tx(struct uart_port *port) static void ar933x_uart_stop_tx(struct uart_port *port)
{ {
struct ar933x_uart_port *up = struct ar933x_uart_port *up =
...@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port) ...@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port)
struct ar933x_uart_port *up = struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port); container_of(port, struct ar933x_uart_port, port);
up->ier &= ~AR933X_UART_INT_RX_VALID; ar933x_uart_stop_rx_interrupt(up);
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
} }
static void ar933x_uart_break_ctl(struct uart_port *port, int break_state) static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
...@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up) ...@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
{ {
struct circ_buf *xmit = &up->port.state->xmit; struct circ_buf *xmit = &up->port.state->xmit;
struct serial_rs485 *rs485conf = &up->port.rs485;
int count; int count;
bool half_duplex_send = false;
if (uart_tx_stopped(&up->port)) if (uart_tx_stopped(&up->port))
return; return;
if ((rs485conf->flags & SER_RS485_ENABLED) &&
(up->port.x_char || !uart_circ_empty(xmit))) {
ar933x_uart_stop_rx_interrupt(up);
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
half_duplex_send = true;
}
count = up->port.fifosize; count = up->port.fifosize;
do { do {
unsigned int rdata; unsigned int rdata;
...@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up) ...@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(&up->port); uart_write_wakeup(&up->port);
if (!uart_circ_empty(xmit)) if (!uart_circ_empty(xmit)) {
ar933x_uart_start_tx_interrupt(up); ar933x_uart_start_tx_interrupt(up);
} else if (half_duplex_send) {
ar933x_uart_wait_tx_complete(up);
ar933x_uart_rx_flush(up);
ar933x_uart_start_rx_interrupt(up);
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
}
} }
static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id) static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
...@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port) ...@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port)
AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE); AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);
/* Enable RX interrupts */ /* Enable RX interrupts */
up->ier = AR933X_UART_INT_RX_VALID; ar933x_uart_start_rx_interrupt(up);
ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
spin_unlock_irqrestore(&up->port.lock, flags); spin_unlock_irqrestore(&up->port.lock, flags);
...@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = { ...@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = {
.verify_port = ar933x_uart_verify_port, .verify_port = ar933x_uart_verify_port,
}; };
static int ar933x_config_rs485(struct uart_port *port,
struct serial_rs485 *rs485conf)
{
struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
if ((rs485conf->flags & SER_RS485_ENABLED) &&
!up->rts_gpiod) {
dev_err(port->dev, "RS485 needs rts-gpio\n");
return 1;
}
port->rs485 = *rs485conf;
return 0;
}
#ifdef CONFIG_SERIAL_AR933X_CONSOLE #ifdef CONFIG_SERIAL_AR933X_CONSOLE
static struct ar933x_uart_port * static struct ar933x_uart_port *
ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
...@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev) ...@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev)
goto err_disable_clk; goto err_disable_clk;
} }
uart_get_rs485_mode(&pdev->dev, &port->rs485);
port->mapbase = mem_res->start; port->mapbase = mem_res->start;
port->line = id; port->line = id;
port->irq = irq_res->start; port->irq = irq_res->start;
...@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) ...@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
port->regshift = 2; port->regshift = 2;
port->fifosize = AR933X_UART_FIFO_SIZE; port->fifosize = AR933X_UART_FIFO_SIZE;
port->ops = &ar933x_uart_ops; port->ops = &ar933x_uart_ops;
port->rs485_config = ar933x_config_rs485;
baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1); baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD); up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
...@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev) ...@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev)
baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);
up->gpios = mctrl_gpio_init(port, 0);
if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS)
return PTR_ERR(up->gpios);
up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
if ((port->rs485.flags & SER_RS485_ENABLED) &&
!up->rts_gpiod) {
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
port->rs485.flags &= ~SER_RS485_ENABLED;
}
#ifdef CONFIG_SERIAL_AR933X_CONSOLE #ifdef CONFIG_SERIAL_AR933X_CONSOLE
ar933x_console_ports[up->port.line] = up; ar933x_console_ports[up->port.line] = up;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment