serial: 8250_pci1xxxx: Add RS485 support to quad-uart driver
pci1xxxx uart supports RS485 mode of operation in the hardware with auto-direction control with configurable delay for releasing RTS after the transmission. This patch adds support for the RS485 mode. Co-developed-by: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com> Signed-off-by: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com> Signed-off-by: Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Link: https://lore.kernel.org/r/20230207164814.3104605-4-kumaravel.thiagarajan@microchip.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
32bb477fa7
commit
08cedda0b3
@ -164,6 +164,54 @@ static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
port->membase + UART_BAUD_CLK_DIVISOR_REG);
|
||||
}
|
||||
|
||||
static int pci1xxxx_rs485_config(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
u32 delay_in_baud_periods;
|
||||
u32 baud_period_in_ns;
|
||||
u32 mode_cfg = 0;
|
||||
u32 clock_div;
|
||||
|
||||
/*
|
||||
* pci1xxxx's uart hardware supports only RTS delay after
|
||||
* Tx and in units of bit times to a maximum of 15
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
mode_cfg = ADCL_CFG_EN | ADCL_CFG_PIN_SEL;
|
||||
|
||||
if (!(rs485->flags & SER_RS485_RTS_ON_SEND))
|
||||
mode_cfg |= ADCL_CFG_POL_SEL;
|
||||
|
||||
if (rs485->delay_rts_after_send) {
|
||||
clock_div = readl(port->membase + UART_BAUD_CLK_DIVISOR_REG);
|
||||
baud_period_in_ns =
|
||||
FIELD_GET(BAUD_CLOCK_DIV_INT_MSK, clock_div) *
|
||||
UART_BIT_SAMPLE_CNT;
|
||||
delay_in_baud_periods =
|
||||
rs485->delay_rts_after_send * NSEC_PER_MSEC /
|
||||
baud_period_in_ns;
|
||||
delay_in_baud_periods =
|
||||
min_t(u32, delay_in_baud_periods,
|
||||
FIELD_MAX(ADCL_CFG_RTS_DELAY_MASK));
|
||||
mode_cfg |= FIELD_PREP(ADCL_CFG_RTS_DELAY_MASK,
|
||||
delay_in_baud_periods);
|
||||
rs485->delay_rts_after_send =
|
||||
baud_period_in_ns * delay_in_baud_periods /
|
||||
NSEC_PER_MSEC;
|
||||
}
|
||||
}
|
||||
writel(mode_cfg, port->membase + ADCL_CFG_REG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 pci1xxxx_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_after_send = 1,
|
||||
/* Delay RTS before send is not supported */
|
||||
};
|
||||
|
||||
static int pci1xxxx_setup(struct pci_dev *pdev,
|
||||
struct uart_8250_port *port, int port_idx)
|
||||
{
|
||||
@ -174,6 +222,8 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
|
||||
port->port.set_termios = serial8250_do_set_termios;
|
||||
port->port.get_divisor = pci1xxxx_get_divisor;
|
||||
port->port.set_divisor = pci1xxxx_set_divisor;
|
||||
port->port.rs485_config = pci1xxxx_rs485_config;
|
||||
port->port.rs485_supported = pci1xxxx_rs485_supported;
|
||||
|
||||
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
|
||||
if (ret < 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user