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

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.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9fa3c4b1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1269,6 +1269,7 @@ config SERIAL_AR933X
	tristate "AR933X serial port support"
	depends on HAVE_CLK && ATH79
	select SERIAL_CORE
	select SERIAL_MCTRL_GPIO if GPIOLIB
	help
	  If you have an Atheros AR933X SOC based board and want to use the
	  built-in UART of the SoC, say Y to this option.
+107 −6
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
@@ -29,6 +30,8 @@

#include <asm/mach-ath79/ar933x_uart.h>

#include "serial_mctrl_gpio.h"

#define DRIVER_NAME "ar933x-uart"

#define AR933X_UART_MAX_SCALE	0xff
@@ -47,6 +50,8 @@ struct ar933x_uart_port {
	unsigned int		min_baud;
	unsigned int		max_baud;
	struct clk		*clk;
	struct mctrl_gpios	*gpios;
	struct gpio_desc	*rts_gpiod;
};

static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up,
@@ -100,6 +105,18 @@ static inline void ar933x_uart_stop_tx_interrupt(struct ar933x_uart_port *up)
	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}

static inline void ar933x_uart_start_rx_interrupt(struct ar933x_uart_port *up)
{
	up->ier |= AR933X_UART_INT_RX_VALID;
	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}

static inline void ar933x_uart_stop_rx_interrupt(struct ar933x_uart_port *up)
{
	up->ier &= ~AR933X_UART_INT_RX_VALID;
	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
}

static inline void ar933x_uart_putc(struct ar933x_uart_port *up, int ch)
{
	unsigned int rdata;
@@ -125,11 +142,21 @@ static unsigned int ar933x_uart_tx_empty(struct uart_port *port)

static unsigned int ar933x_uart_get_mctrl(struct uart_port *port)
{
	return TIOCM_CAR;
	struct ar933x_uart_port *up =
		container_of(port, struct ar933x_uart_port, port);
	int ret = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;

	mctrl_gpio_get(up->gpios, &ret);

	return ret;
}

static void ar933x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct ar933x_uart_port *up =
		container_of(port, struct ar933x_uart_port, port);

	mctrl_gpio_set(up->gpios, mctrl);
}

static void ar933x_uart_start_tx(struct uart_port *port)
@@ -140,6 +167,37 @@ static void ar933x_uart_start_tx(struct uart_port *port)
	ar933x_uart_start_tx_interrupt(up);
}

static void ar933x_uart_wait_tx_complete(struct ar933x_uart_port *up)
{
	unsigned int status;
	unsigned int timeout = 60000;

	/* Wait up to 60ms for the character(s) to be sent. */
	do {
		status = ar933x_uart_read(up, AR933X_UART_CS_REG);
		if (--timeout == 0)
			break;
		udelay(1);
	} while (status & AR933X_UART_CS_TX_BUSY);

	if (timeout == 0)
		dev_err(up->port.dev, "waiting for TX timed out\n");
}

static void ar933x_uart_rx_flush(struct ar933x_uart_port *up)
{
	unsigned int status;

	/* clear RX_VALID interrupt */
	ar933x_uart_write(up, AR933X_UART_INT_REG, AR933X_UART_INT_RX_VALID);

	/* remove characters from the RX FIFO */
	do {
		ar933x_uart_write(up, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR);
		status = ar933x_uart_read(up, AR933X_UART_DATA_REG);
	} while (status & AR933X_UART_DATA_RX_CSR);
}

static void ar933x_uart_stop_tx(struct uart_port *port)
{
	struct ar933x_uart_port *up =
@@ -153,8 +211,7 @@ static void ar933x_uart_stop_rx(struct uart_port *port)
	struct ar933x_uart_port *up =
		container_of(port, struct ar933x_uart_port, port);

	up->ier &= ~AR933X_UART_INT_RX_VALID;
	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
	ar933x_uart_stop_rx_interrupt(up);
}

static void ar933x_uart_break_ctl(struct uart_port *port, int break_state)
@@ -336,11 +393,20 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
{
	struct circ_buf *xmit = &up->port.state->xmit;
	struct serial_rs485 *rs485conf = &up->port.rs485;
	int count;
	bool half_duplex_send = false;

	if (uart_tx_stopped(&up->port))
		return;

	if ((rs485conf->flags & SER_RS485_ENABLED) &&
	    (up->port.x_char || !uart_circ_empty(xmit))) {
		ar933x_uart_stop_rx_interrupt(up);
		gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
		half_duplex_send = true;
	}

	count = up->port.fifosize;
	do {
		unsigned int rdata;
@@ -368,8 +434,14 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&up->port);

	if (!uart_circ_empty(xmit))
	if (!uart_circ_empty(xmit)) {
		ar933x_uart_start_tx_interrupt(up);
	} else if (half_duplex_send) {
		ar933x_uart_wait_tx_complete(up);
		ar933x_uart_rx_flush(up);
		ar933x_uart_start_rx_interrupt(up);
		gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_AFTER_SEND));
	}
}

static irqreturn_t ar933x_uart_interrupt(int irq, void *dev_id)
@@ -427,8 +499,7 @@ static int ar933x_uart_startup(struct uart_port *port)
		AR933X_UART_CS_TX_READY_ORIDE | AR933X_UART_CS_RX_READY_ORIDE);

	/* Enable RX interrupts */
	up->ier = AR933X_UART_INT_RX_VALID;
	ar933x_uart_write(up, AR933X_UART_INT_EN_REG, up->ier);
	ar933x_uart_start_rx_interrupt(up);

	spin_unlock_irqrestore(&up->port.lock, flags);

@@ -511,6 +582,21 @@ static const struct uart_ops ar933x_uart_ops = {
	.verify_port	= ar933x_uart_verify_port,
};

static int ar933x_config_rs485(struct uart_port *port,
				struct serial_rs485 *rs485conf)
{
	struct ar933x_uart_port *up =
		container_of(port, struct ar933x_uart_port, port);

	if ((rs485conf->flags & SER_RS485_ENABLED) &&
	    !up->rts_gpiod) {
		dev_err(port->dev, "RS485 needs rts-gpio\n");
		return 1;
	}
	port->rs485 = *rs485conf;
	return 0;
}

#ifdef CONFIG_SERIAL_AR933X_CONSOLE
static struct ar933x_uart_port *
ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS];
@@ -680,6 +766,8 @@ static int ar933x_uart_probe(struct platform_device *pdev)
		goto err_disable_clk;
	}

	uart_get_rs485_mode(&pdev->dev, &port->rs485);

	port->mapbase = mem_res->start;
	port->line = id;
	port->irq = irq_res->start;
@@ -690,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
	port->regshift = 2;
	port->fifosize = AR933X_UART_FIFO_SIZE;
	port->ops = &ar933x_uart_ops;
	port->rs485_config = ar933x_config_rs485;

	baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
	up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
@@ -697,6 +786,18 @@ static int ar933x_uart_probe(struct platform_device *pdev)
	baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP);
	up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD);

	up->gpios = mctrl_gpio_init(port, 0);
	if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS)
		return PTR_ERR(up->gpios);

	up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);

	if ((port->rs485.flags & SER_RS485_ENABLED) &&
	    !up->rts_gpiod) {
		dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
		port->rs485.flags &= ~SER_RS485_ENABLED;
	}

#ifdef CONFIG_SERIAL_AR933X_CONSOLE
	ar933x_console_ports[up->port.line] = up;
#endif