*
  * Based on 8250_lpc18xx.c:
  * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
+ *
+ * The bcm2835aux is capable of RTS auto flow-control, but this driver doesn't
+ * take advantage of it yet.  When adding support, be sure not to enable it
+ * simultaneously to rs485.
  */
 
 #include <linux/clk.h>
 
 #include "8250.h"
 
+#define BCM2835_AUX_UART_CNTL          8
+#define BCM2835_AUX_UART_CNTL_RXEN     0x01 /* Receiver enable */
+#define BCM2835_AUX_UART_CNTL_TXEN     0x02 /* Transmitter enable */
+#define BCM2835_AUX_UART_CNTL_AUTORTS  0x04 /* RTS set by RX fill level */
+#define BCM2835_AUX_UART_CNTL_AUTOCTS  0x08 /* CTS stops transmitter */
+#define BCM2835_AUX_UART_CNTL_RTS3     0x00 /* RTS set until 3 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS2     0x10 /* RTS set until 2 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS1     0x20 /* RTS set until 1 chars left */
+#define BCM2835_AUX_UART_CNTL_RTS4     0x30 /* RTS set until 4 chars left */
+#define BCM2835_AUX_UART_CNTL_RTSINV   0x40 /* Invert auto RTS polarity */
+#define BCM2835_AUX_UART_CNTL_CTSINV   0x80 /* Invert auto CTS polarity */
+
 /**
  * struct bcm2835aux_data - driver private data of BCM2835 auxiliary UART
  * @clk: clock producer of the port's uartclk
  * @line: index of the port's serial8250_ports[] entry
+ * @cntl: cached copy of CNTL register
  */
 struct bcm2835aux_data {
        struct clk *clk;
        int line;
+       u32 cntl;
 };
 
+static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
+{
+       if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+               struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+               data->cntl &= ~BCM2835_AUX_UART_CNTL_RXEN;
+               serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+       }
+
+       /*
+        * On the bcm2835aux, the MCR register contains no other
+        * flags besides RTS.  So no need for a read-modify-write.
+        */
+       if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
+               serial8250_out_MCR(up, 0);
+       else
+               serial8250_out_MCR(up, UART_MCR_RTS);
+}
+
+static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
+{
+       if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
+               serial8250_out_MCR(up, 0);
+       else
+               serial8250_out_MCR(up, UART_MCR_RTS);
+
+       if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
+               struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
+
+               data->cntl |= BCM2835_AUX_UART_CNTL_RXEN;
+               serial_out(up, BCM2835_AUX_UART_CNTL, data->cntl);
+       }
+}
+
 static int bcm2835aux_serial_probe(struct platform_device *pdev)
 {
        struct uart_8250_port up = { };
        up.port.fifosize = 8;
        up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
                        UPF_SKIP_TEST | UPF_IOREMAP;
+       up.port.rs485_config = serial8250_em485_config;
+       up.rs485_start_tx = bcm2835aux_rs485_start_tx;
+       up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
+
+       /* initialize cached copy with power-on reset value */
+       data->cntl = BCM2835_AUX_UART_CNTL_RXEN | BCM2835_AUX_UART_CNTL_TXEN;
+
+       platform_set_drvdata(pdev, data);
 
        /* get the clock - this also enables the HW */
        data->clk = devm_clk_get(&pdev->dev, NULL);
        }
        data->line = ret;
 
-       platform_set_drvdata(pdev, data);
-
        return 0;
 
 dis_clk: