serial: 8250: Support rs485 bus termination GPIO

A patch from »serial: 8250: Add rs485 emulation to 8250_dw« in state Mainline for linux-kernel

From: Lukas Wunner <lukas@...> Date: Wed, 4 Dec 2019 12:16:28 +0100

Commit-Message

Amend the serial core to retrieve the rs485 bus termination GPIO from the device tree (or ACPI table) and amend the default ->rs485_config() callback for 8250 drivers to change the GPIO on request from user space. Signed-off-by: Lukas Wunner <lukas@...> Signed-off-by: Heiko Stuebner <heiko@...>

Patch-Comment

drivers/tty/serial/8250/8250_port.c | 5 +++++ drivers/tty/serial/serial_core.c | 25 +++++++++++++++++++++++++ include/linux/serial_core.h | 1 + 3 files changed, 31 insertions(+)

Statistics

  • 31 lines added
  • 0 lines removed

Changes

--------------------- drivers/tty/serial/8250/8250_port.c ----------------------
index 4440867b7d20..47c059987538 100644
@@ -30,6 +30,7 @@
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/ktime.h>
+#include <linux/gpio/consumer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -681,6 +682,10 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
memset(rs485->padding, 0, sizeof(rs485->padding));
port->rs485 = *rs485;
+ if (port->rs485_term_gpio)
+ gpiod_set_value(port->rs485_term_gpio,
+ rs485->flags & SER_RS485_TERMINATE_BUS);
+
/*
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
----------------------- drivers/tty/serial/serial_core.c -----------------------
index 43b6682877d5..77702b6371e3 100644
@@ -27,6 +27,7 @@
#include <linux/irq.h>
#include <linux/uaccess.h>
+#include <linux/gpio/consumer.h>
/*
* This is used to lock changes in serial line configuration.
@@ -3317,6 +3318,7 @@ int uart_get_rs485_mode(struct uart_port *port)
* to get to a defined state with the following properties:
*/
rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED |
+ SER_RS485_TERMINATE_BUS |
SER_RS485_RTS_AFTER_SEND);
rs485conf->flags |= SER_RS485_RTS_ON_SEND;
@@ -3331,6 +3333,29 @@ int uart_get_rs485_mode(struct uart_port *port)
rs485conf->flags |= SER_RS485_RTS_AFTER_SEND;
}
+ if (port->rs485_term_gpio)
+ devm_gpiod_put(dev, port->rs485_term_gpio);
+
+ port->rs485_term_gpio = devm_gpiod_get(dev, "rs485-term",
+ GPIOD_FLAGS_BIT_DIR_OUT);
+ if (IS_ERR(port->rs485_term_gpio)) {
+ ret = PTR_ERR(port->rs485_term_gpio);
+ port->rs485_term_gpio = NULL;
+ if (ret != -ENOENT) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Cannot get rs485-term-gpios\n");
+ return ret;
+ }
+ } else {
+ ret = gpiod_get_value(port->rs485_term_gpio);
+ if (ret < 0) {
+ dev_err(dev, "Cannot get rs485-term-gpios value\n");
+ return ret;
+ }
+ if (ret)
+ rs485conf->flags |= SER_RS485_TERMINATE_BUS;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);
------------------------- include/linux/serial_core.h --------------------------
index b649a2b894e7..9521e23b2144 100644
@@ -251,6 +251,7 @@ struct uart_port {
struct attribute_group *attr_group; /* port specific attributes */
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485;
+ struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */
struct serial_iso7816 iso7816;
void *private_data; /* generic platform data pointer */
};
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...