diff options
author | Pierre-Olivier Huard <pierre-olivier.huard@rtone.fr> | 2024-02-06 16:22:38 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2024-02-08 08:15:29 +0100 |
commit | 8ce3f15f21254e82aab3bc7698db55b54b980eef (patch) | |
tree | 3358a9e895610a4d28a677cadf3a3d734e1ba8e0 | |
parent | 96a5f863fbda1833d53aaef45abbb0960586b5ef (diff) | |
download | barebox-8ce3f15f2125.tar.gz barebox-8ce3f15f2125.tar.xz |
serial: ns16550: add basic support for rs485
Add possibility to use RTS signal as a Data Enable signal on RS485
transceivers.
Signed-off-by: Pierre-Olivier Huard <pierre-olivier.huard@rtone.fr>
Link: https://lore.barebox.org/20240206152239.341460-2-pierre-olivier.huard@rtone.fr
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | drivers/serial/serial_ns16550.c | 33 | ||||
-rw-r--r-- | drivers/serial/serial_ns16550.h | 3 |
2 files changed, 34 insertions, 2 deletions
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c index c3bc79adc2..73d8365dac 100644 --- a/drivers/serial/serial_ns16550.c +++ b/drivers/serial/serial_ns16550.c @@ -40,6 +40,9 @@ struct ns16550_priv { void (*write_reg)(struct ns16550_priv *, uint8_t val, unsigned offset); uint8_t (*read_reg)(struct ns16550_priv *, unsigned offset); const char *access_type; + + bool rs485_mode; + bool rs485_rts_active_low; }; struct ns16550_drvdata { @@ -265,9 +268,31 @@ static void rpi_init_port(struct console_device *cdev) */ static void ns16550_putc(struct console_device *cdev, char c) { - /* Loop Doing Nothing */ - while ((ns16550_read(cdev, lsr) & LSR_THRE) == 0) ; + struct ns16550_priv *priv = to_ns16550_priv(cdev); + + /* wait until FIFO can accept at least one byte */ + while ((ns16550_read(cdev, lsr) & (LSR_THRE)) != (LSR_THRE)) + ; + + if (priv->rs485_mode) { + if (priv->rs485_rts_active_low) + ns16550_write(cdev, MCR_RTS, mcr); + else + ns16550_write(cdev, 0, mcr); + } + ns16550_write(cdev, c, thr); + + if (priv->rs485_mode) { + /* wait until FIFO is cleared*/ + while ((ns16550_read(cdev, lsr) & (LSR_EMPTY)) != (LSR_EMPTY)) + ; + + if (priv->rs485_rts_active_low) + ns16550_write(cdev, 0, mcr); + else + ns16550_write(cdev, MCR_RTS, mcr); + } } /** @@ -321,6 +346,10 @@ static void ns16550_probe_dt(struct device *dev, struct ns16550_priv *priv) priv->mmiobase += offset; of_property_read_u32(np, "reg-shift", &priv->plat.shift); of_property_read_u32(np, "reg-io-width", &width); + priv->rs485_rts_active_low = + of_property_read_bool(np, "rs485-rts-active-low"); + priv->rs485_mode = + of_property_read_bool(np, "linux,rs485-enabled-at-boot-time"); switch (width) { case 1: diff --git a/drivers/serial/serial_ns16550.h b/drivers/serial/serial_ns16550.h index 56c639a134..1c5d9d551a 100644 --- a/drivers/serial/serial_ns16550.h +++ b/drivers/serial/serial_ns16550.h @@ -73,6 +73,9 @@ #define LSR_TEMT 0x40 /* Xmitter empty */ #define LSR_ERR 0x80 /* Error */ +/* Transmitter FIFO completely empty */ +#define LSR_EMPTY (LSR_THRE | LSR_TEMT) + /* useful defaults for LCR */ #define LCR_8N1 0x03 |