Re: [PATCH v2] serial: imx: Prevent RTS line toggle delays for RS485

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



[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



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux PPP]     [Linux FS]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Linmodem]     [Device Mapper]     [Linux Kernel for ARM]

  Powered by Linux