summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPierre-Olivier Huard <pierre-olivier.huard@rtone.fr>2024-02-06 16:22:38 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2024-02-08 08:15:29 +0100
commit8ce3f15f21254e82aab3bc7698db55b54b980eef (patch)
tree3358a9e895610a4d28a677cadf3a3d734e1ba8e0
parent96a5f863fbda1833d53aaef45abbb0960586b5ef (diff)
downloadbarebox-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.c33
-rw-r--r--drivers/serial/serial_ns16550.h3
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