diff options
Diffstat (limited to 'target/linux/ath79/patches-4.19/0061-tty-serial-ar933x-uart-rs485-gpio.patch')
-rw-r--r-- | target/linux/ath79/patches-4.19/0061-tty-serial-ar933x-uart-rs485-gpio.patch | 267 |
1 files changed, 0 insertions, 267 deletions
diff --git a/target/linux/ath79/patches-4.19/0061-tty-serial-ar933x-uart-rs485-gpio.patch b/target/linux/ath79/patches-4.19/0061-tty-serial-ar933x-uart-rs485-gpio.patch deleted file mode 100644 index b77cd2d574..0000000000 --- a/target/linux/ath79/patches-4.19/0061-tty-serial-ar933x-uart-rs485-gpio.patch +++ /dev/null @@ -1,267 +0,0 @@ -From patchwork Fri Feb 21 21:23:31 2020 -Content-Type: text/plain; charset="utf-8" -MIME-Version: 1.0 -Content-Transfer-Encoding: 7bit -X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org> -X-Patchwork-Id: 1198835 -Date: Fri, 21 Feb 2020 22:23:31 +0100 -From: Daniel Golle <daniel@makrotopia.org> -To: linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org -Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, - Jiri Slaby <jslaby@suse.com>, Petr =?utf-8?q?=C5=A0tetiar?= <ynezz@true.cz>, - Chuanhong Guo <gch981213@gmail.com>, Piotr Dymacz <pepe2k@gmail.com> -Subject: [PATCH v2] serial: ar933x_uart: add RS485 support -Message-ID: <20200221212331.GA21467@makrotopia.org> -MIME-Version: 1.0 -Content-Disposition: inline -Sender: linux-kernel-owner@vger.kernel.org -Precedence: bulk -List-ID: <linux-kernel.vger.kernel.org> -X-Mailing-List: linux-kernel@vger.kernel.org - -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: Daniel Golle <daniel@makrotopia.org> ---- -v2: use bool to indicate ongoing half-duplex send, use it afterwards - to decide whether we've just been in a send operation. - - drivers/tty/serial/Kconfig | 1 + - drivers/tty/serial/ar933x_uart.c | 113 +++++++++++++++++++++++++++++-- - 2 files changed, 108 insertions(+), 6 deletions(-) - ---- a/drivers/tty/serial/Kconfig -+++ b/drivers/tty/serial/Kconfig -@@ -1296,6 +1296,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. ---- a/drivers/tty/serial/ar933x_uart.c -+++ b/drivers/tty/serial/ar933x_uart.c -@@ -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_i - 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 - - 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 - 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 u - 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) -@@ -340,11 +397,20 @@ static void ar933x_uart_rx_chars(struct - 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; -@@ -372,8 +438,14 @@ static void ar933x_uart_tx_chars(struct - 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) -@@ -435,8 +507,7 @@ static int ar933x_uart_startup(struct ua - 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); - -@@ -519,6 +590,21 @@ static const struct uart_ops ar933x_uart - .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]; -@@ -688,6 +774,8 @@ static int ar933x_uart_probe(struct plat - 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; -@@ -698,6 +786,7 @@ static int ar933x_uart_probe(struct plat - 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); -@@ -705,6 +794,18 @@ static int ar933x_uart_probe(struct plat - 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 |