mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
serial: qcom-geni: Enable support for half-duplex mode
Enable the use of the RTS pin for direction control in half-duplex modes to prevent data collisions. Utilize the rs485 structure and callbacks in the serial core framework to support half-duplex modes. Implement support for the TIOCSRS485 IOCTL value and the struct serial_rs485. Signed-off-by: Anup Kulkarni <quic_anupkulk@quicinc.com> Link: https://lore.kernel.org/r/20250603110145.3835111-1-quic_anupkulk@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
341a22fa05
commit
4fcc287f3c
|
|
@ -192,6 +192,33 @@ static struct qcom_geni_serial_port qcom_geni_console_port = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct serial_rs485 qcom_geni_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RTS_ON_SEND,
|
||||
};
|
||||
|
||||
/**
|
||||
* qcom_geni_set_rs485_mode - Set RTS pin state for RS485 mode
|
||||
* @uport: UART port
|
||||
* @flag: RS485 flag to determine RTS polarity
|
||||
*
|
||||
* Enables manual RTS control for RS485. Sets RTS to READY or NOT_READY
|
||||
* based on the specified flag if RS485 mode is enabled.
|
||||
*/
|
||||
static void qcom_geni_set_rs485_mode(struct uart_port *uport, u32 flag)
|
||||
{
|
||||
if (!(uport->rs485.flags & SER_RS485_ENABLED))
|
||||
return;
|
||||
|
||||
u32 rfr = UART_MANUAL_RFR_EN;
|
||||
|
||||
if (uport->rs485.flags & flag)
|
||||
rfr |= UART_RFR_NOT_READY;
|
||||
else
|
||||
rfr |= UART_RFR_READY;
|
||||
|
||||
writel(rfr, uport->membase + SE_UART_MANUAL_RFR);
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_request_port(struct uart_port *uport)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(uport->dev);
|
||||
|
|
@ -664,6 +691,8 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
|
|||
xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
|
||||
UART_XMIT_SIZE);
|
||||
|
||||
qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_ON_SEND);
|
||||
|
||||
qcom_geni_serial_setup_tx(uport, xmit_size);
|
||||
|
||||
ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size,
|
||||
|
|
@ -1071,8 +1100,10 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev)
|
|||
}
|
||||
|
||||
if (dma) {
|
||||
if (dma_tx_status & TX_DMA_DONE)
|
||||
if (dma_tx_status & TX_DMA_DONE) {
|
||||
qcom_geni_serial_handle_tx_dma(uport);
|
||||
qcom_geni_set_rs485_mode(uport, SER_RS485_RTS_AFTER_SEND);
|
||||
}
|
||||
|
||||
if (dma_rx_status) {
|
||||
if (dma_rx_status & RX_RESET_DONE)
|
||||
|
|
@ -1610,6 +1641,24 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_geni_rs485_config - Configure RS485 settings for the UART port
|
||||
* @uport: Pointer to the UART port structure
|
||||
* @termios: Pointer to the termios structure
|
||||
* @rs485: Pointer to the RS485 configuration structure
|
||||
* This function configures the RTS (Request to Send) pin behavior for RS485 mode.
|
||||
* When RS485 mode is enabled, the RTS pin is kept in default ACTIVE HIGH state.
|
||||
* Return: Always returns 0.
|
||||
*/
|
||||
|
||||
static int qcom_geni_rs485_config(struct uart_port *uport,
|
||||
struct ktermios *termios, struct serial_rs485 *rs485)
|
||||
{
|
||||
qcom_geni_set_rs485_mode(uport, SER_RS485_ENABLED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_ops qcom_geni_console_pops = {
|
||||
.tx_empty = qcom_geni_serial_tx_empty,
|
||||
.stop_tx = qcom_geni_serial_stop_tx_fifo,
|
||||
|
|
@ -1702,6 +1751,8 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
uport->mapbase = res->start;
|
||||
|
||||
uport->rs485_config = qcom_geni_rs485_config;
|
||||
uport->rs485_supported = qcom_geni_rs485_supported;
|
||||
port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
|
||||
port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
|
||||
port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
|
||||
|
|
@ -1767,6 +1818,10 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = uart_get_rs485_mode(uport);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = uart_add_one_port(drv, uport);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user