Skip to content

Commit 8d47923

Browse files
LinoSanfilippo333gregkh
authored andcommitted
serial: amba-pl011: add RS485 support
Add basic support for RS485: Provide a callback to configure RS485 settings. Handle the RS485 specific part in the functions pl011_rs485_tx_start() and pl011_rs485_tx_stop() which extend the generic start/stop callbacks. Beside via IOCTL from userspace RS485 can be enabled by means of the device tree property "rs485-enabled-at-boot-time". Signed-off-by: Lino Sanfilippo <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 240e126 commit 8d47923

File tree

1 file changed

+161
-2
lines changed

1 file changed

+161
-2
lines changed

drivers/tty/serial/amba-pl011.c

Lines changed: 161 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ struct uart_amba_port {
265265
unsigned int old_cr; /* state during shutdown */
266266
unsigned int fixed_baud; /* vendor-set fixed baud rate */
267267
char type[12];
268+
bool rs485_tx_started;
269+
unsigned int rs485_tx_drain_interval; /* usecs */
268270
#ifdef CONFIG_DMA_ENGINE
269271
/* DMA stuff */
270272
bool using_tx_dma;
@@ -275,6 +277,8 @@ struct uart_amba_port {
275277
#endif
276278
};
277279

280+
static unsigned int pl011_tx_empty(struct uart_port *port);
281+
278282
static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap,
279283
unsigned int reg)
280284
{
@@ -1282,6 +1286,42 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
12821286
#define pl011_dma_flush_buffer NULL
12831287
#endif
12841288

1289+
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
1290+
{
1291+
struct uart_port *port = &uap->port;
1292+
int i = 0;
1293+
u32 cr;
1294+
1295+
/* Wait until hardware tx queue is empty */
1296+
while (!pl011_tx_empty(port)) {
1297+
if (i == port->fifosize) {
1298+
dev_warn(port->dev,
1299+
"timeout while draining hardware tx queue\n");
1300+
break;
1301+
}
1302+
1303+
udelay(uap->rs485_tx_drain_interval);
1304+
i++;
1305+
}
1306+
1307+
if (port->rs485.delay_rts_after_send)
1308+
mdelay(port->rs485.delay_rts_after_send);
1309+
1310+
cr = pl011_read(uap, REG_CR);
1311+
1312+
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
1313+
cr &= ~UART011_CR_RTS;
1314+
else
1315+
cr |= UART011_CR_RTS;
1316+
1317+
/* Disable the transmitter and reenable the transceiver */
1318+
cr &= ~UART011_CR_TXE;
1319+
cr |= UART011_CR_RXE;
1320+
pl011_write(cr, uap, REG_CR);
1321+
1322+
uap->rs485_tx_started = false;
1323+
}
1324+
12851325
static void pl011_stop_tx(struct uart_port *port)
12861326
{
12871327
struct uart_amba_port *uap =
@@ -1290,6 +1330,9 @@ static void pl011_stop_tx(struct uart_port *port)
12901330
uap->im &= ~UART011_TXIM;
12911331
pl011_write(uap->im, uap, REG_IMSC);
12921332
pl011_dma_tx_stop(uap);
1333+
1334+
if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
1335+
pl011_rs485_tx_stop(uap);
12931336
}
12941337

12951338
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq);
@@ -1380,6 +1423,32 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
13801423
return true;
13811424
}
13821425

1426+
static void pl011_rs485_tx_start(struct uart_amba_port *uap)
1427+
{
1428+
struct uart_port *port = &uap->port;
1429+
u32 cr;
1430+
1431+
/* Enable transmitter */
1432+
cr = pl011_read(uap, REG_CR);
1433+
cr |= UART011_CR_TXE;
1434+
1435+
/* Disable receiver if half-duplex */
1436+
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
1437+
cr &= ~UART011_CR_RXE;
1438+
1439+
if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
1440+
cr &= ~UART011_CR_RTS;
1441+
else
1442+
cr |= UART011_CR_RTS;
1443+
1444+
pl011_write(cr, uap, REG_CR);
1445+
1446+
if (port->rs485.delay_rts_before_send)
1447+
mdelay(port->rs485.delay_rts_before_send);
1448+
1449+
uap->rs485_tx_started = true;
1450+
}
1451+
13831452
/* Returns true if tx interrupts have to be (kept) enabled */
13841453
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
13851454
{
@@ -1397,6 +1466,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
13971466
return false;
13981467
}
13991468

1469+
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
1470+
!uap->rs485_tx_started)
1471+
pl011_rs485_tx_start(uap);
1472+
14001473
/* If we are using DMA mode, try to send some characters. */
14011474
if (pl011_dma_tx_irq(uap))
14021475
return true;
@@ -1542,6 +1615,9 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl)
15421615
container_of(port, struct uart_amba_port, port);
15431616
unsigned int cr;
15441617

1618+
if (port->rs485.flags & SER_RS485_ENABLED)
1619+
mctrl &= ~TIOCM_RTS;
1620+
15451621
cr = pl011_read(uap, REG_CR);
15461622

15471623
#define TIOCMBIT(tiocmbit, uartbit) \
@@ -1763,7 +1839,17 @@ static int pl011_startup(struct uart_port *port)
17631839

17641840
/* restore RTS and DTR */
17651841
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
1766-
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
1842+
cr |= UART01x_CR_UARTEN | UART011_CR_RXE;
1843+
1844+
if (port->rs485.flags & SER_RS485_ENABLED) {
1845+
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
1846+
cr &= ~UART011_CR_RTS;
1847+
else
1848+
cr |= UART011_CR_RTS;
1849+
} else {
1850+
cr |= UART011_CR_TXE;
1851+
}
1852+
17671853
pl011_write(cr, uap, REG_CR);
17681854

17691855
spin_unlock_irq(&uap->port.lock);
@@ -1864,6 +1950,9 @@ static void pl011_shutdown(struct uart_port *port)
18641950

18651951
pl011_dma_shutdown(uap);
18661952

1953+
if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
1954+
pl011_rs485_tx_stop(uap);
1955+
18671956
free_irq(uap->port.irq, uap);
18681957

18691958
pl011_disable_uart(uap);
@@ -1941,6 +2030,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
19412030
unsigned int lcr_h, old_cr;
19422031
unsigned long flags;
19432032
unsigned int baud, quot, clkdiv;
2033+
unsigned int bits;
19442034

19452035
if (uap->vendor->oversampling)
19462036
clkdiv = 8;
@@ -1991,18 +2081,30 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
19912081
if (uap->fifosize > 1)
19922082
lcr_h |= UART01x_LCRH_FEN;
19932083

2084+
bits = tty_get_frame_size(termios->c_cflag);
2085+
19942086
spin_lock_irqsave(&port->lock, flags);
19952087

19962088
/*
19972089
* Update the per-port timeout.
19982090
*/
19992091
uart_update_timeout(port, termios->c_cflag, baud);
20002092

2093+
/*
2094+
* Calculate the approximated time it takes to transmit one character
2095+
* with the given baud rate. We use this as the poll interval when we
2096+
* wait for the tx queue to empty.
2097+
*/
2098+
uap->rs485_tx_drain_interval = (bits * 1000 * 1000) / baud;
2099+
20012100
pl011_setup_status_masks(port, termios);
20022101

20032102
if (UART_ENABLE_MS(port, termios->c_cflag))
20042103
pl011_enable_ms(port);
20052104

2105+
if (port->rs485.flags & SER_RS485_ENABLED)
2106+
termios->c_cflag &= ~CRTSCTS;
2107+
20062108
/* first, disable everything */
20072109
old_cr = pl011_read(uap, REG_CR);
20082110
pl011_write(0, uap, REG_CR);
@@ -2124,6 +2226,41 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
21242226
return ret;
21252227
}
21262228

2229+
static int pl011_rs485_config(struct uart_port *port,
2230+
struct serial_rs485 *rs485)
2231+
{
2232+
struct uart_amba_port *uap =
2233+
container_of(port, struct uart_amba_port, port);
2234+
2235+
/* pick sane settings if the user hasn't */
2236+
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
2237+
!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
2238+
rs485->flags |= SER_RS485_RTS_ON_SEND;
2239+
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
2240+
}
2241+
/* clamp the delays to [0, 100ms] */
2242+
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
2243+
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
2244+
memset(rs485->padding, 0, sizeof(rs485->padding));
2245+
2246+
if (port->rs485.flags & SER_RS485_ENABLED)
2247+
pl011_rs485_tx_stop(uap);
2248+
2249+
/* Set new configuration */
2250+
port->rs485 = *rs485;
2251+
2252+
/* Make sure auto RTS is disabled */
2253+
if (port->rs485.flags & SER_RS485_ENABLED) {
2254+
u32 cr = pl011_read(uap, REG_CR);
2255+
2256+
cr &= ~UART011_CR_RTSEN;
2257+
pl011_write(cr, uap, REG_CR);
2258+
port->status &= ~UPSTAT_AUTORTS;
2259+
}
2260+
2261+
return 0;
2262+
}
2263+
21272264
static const struct uart_ops amba_pl011_pops = {
21282265
.tx_empty = pl011_tx_empty,
21292266
.set_mctrl = pl011_set_mctrl,
@@ -2588,10 +2725,28 @@ static int pl011_find_free_port(void)
25882725
return -EBUSY;
25892726
}
25902727

2728+
static int pl011_get_rs485_mode(struct uart_amba_port *uap)
2729+
{
2730+
struct uart_port *port = &uap->port;
2731+
struct serial_rs485 *rs485 = &port->rs485;
2732+
int ret;
2733+
2734+
ret = uart_get_rs485_mode(port);
2735+
if (ret)
2736+
return ret;
2737+
2738+
/* clamp the delays to [0, 100ms] */
2739+
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
2740+
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
2741+
2742+
return 0;
2743+
}
2744+
25912745
static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
25922746
struct resource *mmiobase, int index)
25932747
{
25942748
void __iomem *base;
2749+
int ret;
25952750

25962751
base = devm_ioremap_resource(dev, mmiobase);
25972752
if (IS_ERR(base))
@@ -2608,6 +2763,10 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
26082763
uap->port.flags = UPF_BOOT_AUTOCONF;
26092764
uap->port.line = index;
26102765

2766+
ret = pl011_get_rs485_mode(uap);
2767+
if (ret)
2768+
return ret;
2769+
26112770
amba_ports[index] = uap;
26122771

26132772
return 0;
@@ -2665,7 +2824,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
26652824
uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
26662825
uap->port.irq = dev->irq[0];
26672826
uap->port.ops = &amba_pl011_pops;
2668-
2827+
uap->port.rs485_config = pl011_rs485_config;
26692828
snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
26702829

26712830
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);

0 commit comments

Comments
 (0)