serial: 8250: 8250_omap: Support native RS485
Recent TI Sitara SoCs such as AM64/AM65 have gained the ability to automatically assert RTS when data is transmitted, obviating the need to emulate this functionality in software. The feature is controlled through new DIR_EN and DIR_POL bits in the Mode Definition Register 3. For details see page 8783 and 8890 of the AM65 TRM: https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf Cc: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Cc: Su Bao Cheng <baocheng.su@siemens.com> Cc: Vignesh Raghavendra <vigneshr@ti.com> Cc: Jan Kiszka <jan.kiszka@siemens.com> Cc: Bin Liu <b-liu@ti.com> Tested-by: Zeng Chao <chao.zeng@siemens.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Lukas Wunner <lukas@wunner.de> Link: https://lore.kernel.org/r/e9f25f5c9200a35d3162973c2b45d6b892cc9bf2.1665906869.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
35781d8356
commit
801954d121
@ -44,6 +44,7 @@
|
||||
#define UART_HAS_EFR2 BIT(4)
|
||||
#define UART_HAS_RHR_IT_DIS BIT(5)
|
||||
#define UART_RX_TIMEOUT_QUIRK BIT(6)
|
||||
#define UART_HAS_NATIVE_RS485 BIT(7)
|
||||
|
||||
#define OMAP_UART_FCR_RX_TRIG 6
|
||||
#define OMAP_UART_FCR_TX_TRIG 4
|
||||
@ -101,6 +102,11 @@
|
||||
#define UART_OMAP_IER2 0x1B
|
||||
#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
|
||||
|
||||
/* Mode Definition Register 3 */
|
||||
#define UART_OMAP_MDR3 0x20
|
||||
#define UART_OMAP_MDR3_DIR_POL BIT(3)
|
||||
#define UART_OMAP_MDR3_DIR_EN BIT(4)
|
||||
|
||||
/* Enhanced features register 2 */
|
||||
#define UART_OMAP_EFR2 0x23
|
||||
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
|
||||
@ -112,6 +118,7 @@ struct omap8250_priv {
|
||||
int line;
|
||||
u8 habit;
|
||||
u8 mdr1;
|
||||
u8 mdr3;
|
||||
u8 efr;
|
||||
u8 scr;
|
||||
u8 wer;
|
||||
@ -343,7 +350,10 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
||||
|
||||
up->port.ops->set_mctrl(&up->port, up->port.mctrl);
|
||||
|
||||
if (up->port.rs485.flags & SER_RS485_ENABLED)
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
if (up->port.rs485.flags & SER_RS485_ENABLED &&
|
||||
up->port.rs485_config == serial8250_em485_config)
|
||||
serial8250_em485_stop_tx(up);
|
||||
}
|
||||
|
||||
@ -792,6 +802,74 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static int omap8250_rs485_config(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
u32 fixed_delay_rts_before_send = 0;
|
||||
u32 fixed_delay_rts_after_send = 0;
|
||||
unsigned int baud;
|
||||
|
||||
/*
|
||||
* There is a fixed delay of 3 bit clock cycles after the TX shift
|
||||
* register is going empty to allow time for the stop bit to transition
|
||||
* through the transceiver before direction is changed to receive.
|
||||
*
|
||||
* Additionally there appears to be a 1 bit clock delay between writing
|
||||
* to the THR register and transmission of the start bit, per page 8783
|
||||
* of the AM65 TRM: https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf
|
||||
*/
|
||||
if (priv->quot) {
|
||||
if (priv->mdr1 & UART_OMAP_MDR1_16X_MODE)
|
||||
baud = port->uartclk / (16 * priv->quot);
|
||||
else
|
||||
baud = port->uartclk / (13 * priv->quot);
|
||||
|
||||
fixed_delay_rts_after_send = 3 * MSEC_PER_SEC / baud;
|
||||
fixed_delay_rts_before_send = 1 * MSEC_PER_SEC / baud;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to RS485 software emulation if the UART is missing
|
||||
* hardware support, if the device tree specifies an mctrl_gpio
|
||||
* (indicates that RTS is unavailable due to a pinmux conflict)
|
||||
* or if the requested delays exceed the fixed hardware delays.
|
||||
*/
|
||||
if (!(priv->habit & UART_HAS_NATIVE_RS485) ||
|
||||
mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) ||
|
||||
rs485->delay_rts_after_send > fixed_delay_rts_after_send ||
|
||||
rs485->delay_rts_before_send > fixed_delay_rts_before_send) {
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
port->rs485_config = serial8250_em485_config;
|
||||
return serial8250_em485_config(port, termios, rs485);
|
||||
}
|
||||
|
||||
rs485->delay_rts_after_send = fixed_delay_rts_after_send;
|
||||
rs485->delay_rts_before_send = fixed_delay_rts_before_send;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
priv->mdr3 |= UART_OMAP_MDR3_DIR_EN;
|
||||
else
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
|
||||
|
||||
/*
|
||||
* Retain same polarity semantics as RS485 software emulation,
|
||||
* i.e. SER_RS485_RTS_ON_SEND means driving RTS low on send.
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND)
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_POL;
|
||||
else
|
||||
priv->mdr3 |= UART_OMAP_MDR3_DIR_POL;
|
||||
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p);
|
||||
|
||||
@ -1241,7 +1319,7 @@ static struct omap8250_dma_params am33xx_dma = {
|
||||
static struct omap8250_platdata am654_platdata = {
|
||||
.dma_params = &am654_dma,
|
||||
.habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
|
||||
UART_RX_TIMEOUT_QUIRK,
|
||||
UART_RX_TIMEOUT_QUIRK | UART_HAS_NATIVE_RS485,
|
||||
};
|
||||
|
||||
static struct omap8250_platdata am33xx_platdata = {
|
||||
@ -1334,7 +1412,8 @@ static int omap8250_probe(struct platform_device *pdev)
|
||||
up.port.shutdown = omap_8250_shutdown;
|
||||
up.port.throttle = omap_8250_throttle;
|
||||
up.port.unthrottle = omap_8250_unthrottle;
|
||||
up.port.rs485_config = serial8250_em485_config;
|
||||
up.port.rs485_config = omap8250_rs485_config;
|
||||
/* same rs485_supported for software emulation and native RS485 */
|
||||
up.port.rs485_supported = serial8250_em485_supported;
|
||||
up.rs485_start_tx = serial8250_em485_start_tx;
|
||||
up.rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
|
Loading…
x
Reference in New Issue
Block a user