[Adding Uwe and Stefan, who have been working with RS485 on i.MX lately. Maybe we should an entry for drivers/tty/serial/imx.c in MAINTAINERS file? ] On Mon, Apr 23, 2018 at 9:14 AM, Einar Vading <einar.vading@xxxxxxxx> wrote: > When using RS485 in half duplex mode the RTS line is typically used to > toggle receive/transmit on the transceiver IC. As some protocols (OSDP > f.ex.) specify that the slave should respond within some short time period, > it is important that the RTS line toggles the transceiver from transmit > mode to receive mode within that time. > > This change puts a pm_qos requirement on CPU_DMA_LATENCY when in RS485 tx > mode so that CPU wake times won't cause to long delays. > > Signed-off-by: Einar Vading <einarv@xxxxxxxx> > --- > Changes in v2: > - Uses a workqueue to avoid setting pm_qos from hard IRQ. > > drivers/tty/serial/imx.c | 25 +++++++++++++++++++++++++ > 1 file changed, 25 insertions(+) > > diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c > index f370c1cf4f27..5967f98f1686 100644 > --- a/drivers/tty/serial/imx.c > +++ b/drivers/tty/serial/imx.c > @@ -30,6 +30,8 @@ > #include <linux/of_device.h> > #include <linux/io.h> > #include <linux/dma-mapping.h> > +#include <linux/pm_qos.h> > +#include <linux/workqueue.h> > > #include <asm/irq.h> > #include <linux/platform_data/serial-imx.h> > @@ -225,6 +227,9 @@ struct imx_port { > unsigned int dma_tx_nents; > unsigned int saved_reg[10]; > bool context_saved; > + u32 latency; > + struct pm_qos_request pm_qos_req; > + struct work_struct qos_work; > }; > > struct imx_port_ucrs { > @@ -457,6 +462,8 @@ static void imx_uart_stop_tx(struct uart_port *port) > ucr4 = imx_uart_readl(sport, UCR4); > ucr4 &= ~UCR4_TCEN; > imx_uart_writel(sport, ucr4, UCR4); > + sport->latency = PM_QOS_DEFAULT_VALUE; > + schedule_work(&sport->qos_work); > } > } > > @@ -657,6 +664,9 @@ static void imx_uart_start_tx(struct uart_port *port) > if (port->rs485.flags & SER_RS485_ENABLED) { > u32 ucr2; > > + sport->latency = 0; > + schedule_work(&sport->qos_work); > + > ucr2 = imx_uart_readl(sport, UCR2); > if (port->rs485.flags & SER_RS485_RTS_ON_SEND) > imx_uart_rts_active(sport, &ucr2); > @@ -1852,6 +1862,14 @@ static int imx_uart_rs485_config(struct uart_port *port, > return 0; > } > > +static void imx_qos_work(struct work_struct *work) > +{ > + struct imx_port *sport; > + > + sport = container_of(work, struct imx_port, qos_work); > + pm_qos_update_request(&sport->pm_qos_req, sport->latency); > +} > + > static const struct uart_ops imx_uart_pops = { > .tx_empty = imx_uart_tx_empty, > .set_mctrl = imx_uart_set_mctrl, > @@ -1868,6 +1886,7 @@ static const struct uart_ops imx_uart_pops = { > .type = imx_uart_type, > .config_port = imx_uart_config_port, > .verify_port = imx_uart_verify_port, > + Minor nit: this change is unrelated. > #if defined(CONFIG_CONSOLE_POLL) > .poll_init = imx_uart_poll_init, > .poll_get_char = imx_uart_poll_get_char, > @@ -2335,6 +2354,10 @@ static int imx_uart_probe(struct platform_device *pdev) > } > } > > + pm_qos_add_request(&sport->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, > + PM_QOS_DEFAULT_VALUE); > + INIT_WORK(&sport->qos_work, imx_qos_work); > + > imx_uart_ports[sport->port.line] = sport; > > platform_set_drvdata(pdev, sport); > @@ -2346,6 +2369,8 @@ static int imx_uart_remove(struct platform_device *pdev) > { > struct imx_port *sport = platform_get_drvdata(pdev); > > + pm_qos_remove_request(&sport->pm_qos_req); > + > return uart_remove_one_port(&imx_uart_uart_driver, &sport->port); > } -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html