[PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals

Richard Genoud richard.genoud at gmail.com
Fri Oct 31 01:48:47 PDT 2014


2014-10-24 17:51 GMT+02:00 Janusz Użycki <j.uzycki at elproma.com.pl>:
>
> W dniu 2014-10-24 o 17:32, Richard Genoud pisze:
>
>> On 10/10/2014 18:53, Janusz Uzycki wrote:
>>>
>>> Dedicated CTS and RTS pins are unusable together with a lot of other
>>> peripherals because they share the same line. Pinctrl is limited.
>>>
>>> Moreover, the AUART controller doesn't handle DTR/DSR/DCD/RI signals,
>>> so we have to control them via GPIO.
>>>
>>> This patch permits to use GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI
>>> signals.
>>>
>>> Signed-off-by: Janusz Uzycki <j.uzycki at elproma.com.pl>
>>> ---
>>> v3 -> v4 changelog:
>>> * RTS_AT_AUART() and CTS_AT_AUART() macro defined
>>> * DMA engine disabled if RTS or CTS is GPIO line
>>> * warn if fsl,uart-has-rtscts and RTS/CTS via GPIO are mixed
>>> * CTSEN can't be enabled for hardware flow control block
>>>    if CTS is defined as GPIO line
>>> * RTSEN can be enabled for hardware flow control block
>>>    even if RTS is defined as GPIO line.
>>>    RTS pin depends on pinctrl configuration which
>>>    selects RTS output from hardware flow control block or GPIO line.
>>> * mxs_auart_settermios(): RTS_AT_AUART() and CTS_AT_AUART() used
>>> * mxs_auart_irq_handle(): CTS_AT_AUART() used
>>> * mxs_auart_init_gpios() returns true(success)/false(failure)
>>> * dev_err() message fixed in mxs_auart_probe()
>>>
>>> v2 -> v3 changelog:
>>> * mctrl_gpio_free() removed to simplify:
>>>    mctrl_gpio_free() is not necessary in mxs_auart_probe() and
>>>    mxs_auart_remove() because mctrl_gpio_init() does all
>>>    allocations with devm_* functions.
>>>    (see Documentation/serial/driver since kernel 3.16)
>>> * DMA on HW flow control comment updated, still not sure about the
>>> comment
>>> * mxs_auart_modem_status() removed from mxs_auart_get_mctrl():
>>>    mctrl_gpio_get() does not clear gpio interrupt pendings like
>>>    8250_core.c does with MSR.
>>> * mxs_auart_modem_status() moved to [3/4]
>>>    If enable_ms() is not called, uart_handle_cts_change()
>>>    shouldn't be called.
>>>
>>> ---
>>>   .../devicetree/bindings/serial/fsl-mxs-auart.txt   | 10 ++++-
>>>   drivers/tty/serial/Kconfig           |  1 +
>>>   drivers/tty/serial/mxs-auart.c       | 50 +++++++++++++++++++---
>>>   3 files changed, 55 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
>>> b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
>>> index 59a40f1..7c408c8 100644
>>> --- a/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
>>> +++ b/Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
>>> @@ -11,8 +11,13 @@ Required properties:
>>>   - dma-names: "rx" for RX channel, "tx" for TX channel.
>>>     Optional properties:
>>> -- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines,
>>> +- fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines
>>> +  for hardware flow control,
>>>         it also means you enable the DMA support for this UART.
>>> +- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for
>>> RTS/CTS/DTR/DSR/RI/DCD
>>> +  line respectively. It will use specified PIO instead of the peripheral
>>> +  function pin for the USART feature.
>>> +  If unsure, don't specify this property.
>>>     Example:
>>>   auart0: serial at 8006a000 {
>>> @@ -21,6 +26,9 @@ auart0: serial at 8006a000 {
>>>         interrupts = <112>;
>>>         dmas = <&dma_apbx 8>, <&dma_apbx 9>;
>>>         dma-names = "rx", "tx";
>>> +       cts-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
>>> +       dsr-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
>>> +       dcd-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
>>>   };
>>>     Note: Each auart port should have an alias correctly numbered in
>>> "aliases"
>>> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
>>> index 4fe8ca1..90e8516 100644
>>> --- a/drivers/tty/serial/Kconfig
>>> +++ b/drivers/tty/serial/Kconfig
>>> @@ -1357,6 +1357,7 @@ config SERIAL_MXS_AUART
>>>         depends on ARCH_MXS
>>>         tristate "MXS AUART support"
>>>         select SERIAL_CORE
>>> +       select SERIAL_MCTRL_GPIO if GPIOLIB
>>>         help
>>>           This driver supports the MXS Application UART (AUART) port.
>>>   diff --git a/drivers/tty/serial/mxs-auart.c
>>> b/drivers/tty/serial/mxs-auart.c
>>> index 2d49901..8bbcfd1 100644
>>> --- a/drivers/tty/serial/mxs-auart.c
>>> +++ b/drivers/tty/serial/mxs-auart.c
>>> @@ -42,6 +42,9 @@
>>>     #include <asm/cacheflush.h>
>>>   +#include <linux/err.h>
>>> +#include "serial_mctrl_gpio.h"
>>> +
>>>   #define MXS_AUART_PORTS 5
>>>   #define MXS_AUART_FIFO_SIZE           16
>>>   @@ -158,6 +161,8 @@ struct mxs_auart_port {
>>>         struct scatterlist rx_sgl;
>>>         struct dma_chan *rx_dma_chan;
>>>         void *rx_dma_buf;
>>> +
>>> +       struct mctrl_gpios      *gpios;
>>>   };
>>>     static struct platform_device_id mxs_auart_devtype[] = {
>>> @@ -405,6 +410,8 @@ static void mxs_auart_release_port(struct uart_port
>>> *u)
>>>     static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
>>>   {
>>> +       struct mxs_auart_port *s = to_auart_port(u);
>>> +
>>>         u32 ctrl = readl(u->membase + AUART_CTRL2);
>>>         ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS);
>>> @@ -416,17 +423,20 @@ static void mxs_auart_set_mctrl(struct uart_port
>>> *u, unsigned mctrl)
>>>         }
>>>         writel(ctrl, u->membase + AUART_CTRL2);
>>> +
>>> +       mctrl_gpio_set(s->gpios, mctrl);
>>>   }
>>>     static u32 mxs_auart_get_mctrl(struct uart_port *u)
>>>   {
>>> +       struct mxs_auart_port *s = to_auart_port(u);
>>>         u32 stat = readl(u->membase + AUART_STAT);
>>>         u32 mctrl = 0;
>>>         if (stat & AUART_STAT_CTS)
>>>                 mctrl |= TIOCM_CTS;
>>>   -     return mctrl;
>>> +       return mctrl_gpio_get(s->gpios, &mctrl);
>>>   }
>>>     static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
>>> @@ -554,6 +564,10 @@ err_out:
>>>     }
>>>   +#define RTS_AT_AUART()
>>> IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios,    \
>>> +                                                       UART_GPIO_RTS))
>>> +#define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios,    \
>>> +                                                       UART_GPIO_CTS))
>>>   static void mxs_auart_settermios(struct uart_port *u,
>>>                                  struct ktermios *termios,
>>>                                  struct ktermios *old)
>>> @@ -630,6 +644,7 @@ static void mxs_auart_settermios(struct uart_port *u,
>>>                 ctrl |= AUART_LINECTRL_STP2;
>>>         /* figure out the hardware flow control settings */
>>> +       ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
>>>         if (cflag & CRTSCTS) {
>>>                 /*
>>>                  * The DMA has a bug(see errata:2836) in mx23.
>>> @@ -644,9 +659,11 @@ static void mxs_auart_settermios(struct uart_port
>>> *u,
>>>                                 ctrl2 |= AUART_CTRL2_TXDMAE |
>>> AUART_CTRL2_RXDMAE
>>>                                        | AUART_CTRL2_DMAONERR;
>>>                 }
>>> -               ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN;
>>> -       } else {
>>> -               ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
>>> +               /* Even if RTS is GPIO line RTSEN can be enabled because
>>> +                * the pinctrl configuration decides about RTS pin
>>> function */
>>> +               ctrl2 |= AUART_CTRL2_RTSEN;
>>> +               if (CTS_AT_AUART())
>>> +                       ctrl2 |= AUART_CTRL2_CTSEN;
>>>         }
>>>         /* set baud rate */
>>> @@ -690,7 +707,9 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void
>>> *context)
>>>                         s->port.membase + AUART_INTR_CLR);
>>>         if (istat & AUART_INTR_CTSMIS) {
>>> -               uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
>>> +               if (CTS_AT_AUART())
>>> +                       uart_handle_cts_change(&s->port,
>>> +                                       stat & AUART_STAT_CTS);
>>>                 writel(AUART_INTR_CTSMIS,
>>>                                 s->port.membase + AUART_INTR_CLR);
>>>                 istat &= ~AUART_INTR_CTSMIS;
>>> @@ -1014,6 +1033,23 @@ static int serial_mxs_probe_dt(struct
>>> mxs_auart_port *s,
>>>         return 0;
>>>   }
>>>   +static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct
>>> device *dev)
>>> +{
>>> +       s->gpios = mctrl_gpio_init(dev, 0);
>>> +       if (IS_ERR_OR_NULL(s->gpios))
>>> +               return false;
>>> +
>>> +       /* Block (enabled before) DMA option if RTS or CTS is GPIO line
>>> */
>>
>> This is confusing, so I think some more comments won't be too much.
>> Something like:
>> /*
>>   * The DMA only work if the lines CTS/RTS are handled by the controller
>>   * cf. 8418e67d9523 serial: mxs: enable the DMA only when the RTS/CTS is
>> valid
>>   * So, If the CTS/RTS lines are controlled via GPIO the MXS_AUART_RTSCTS
>> bit should be
>>   * cleaned to indicate that the RTS/CTS lines are not handled by the
>> controller.
>>   */
>> (If I understood correctly what is done here.)
>
>
> This is not clear in the driver. If hardware RTS/CTS (non-gpio) is not
> defined in DT
> only DMA is not used. It is still possible to use hardware RTS/CTS lines
> if you set hw-flowcontrol in termios. So it is also possible to mix hardware
> RTS/CTS
> and gpio RTS/CTS. In mixed or gpio case the code blocks/disables DMA.
> I know my comment is not clear but the reason is in the earlier code.
> Can you propose better solution?
Maybe Huang Shijie knows more on this DMA vs RTS/CTS incompatibility.
[added Huang Shijie in Cc ]

> After review and small fixes requested new version is required for a
> patchset
> or rather patch resend?
It's better to resend the whole patchset (after giving some time for
Huang Shijie to give its thoughts )

>
> kind regards
> Janusz
>
>
>>> +       if (!RTS_AT_AUART() || !CTS_AT_AUART()) {
>>> +               if (test_bit(MXS_AUART_RTSCTS, &s->flags))
>>> +                       dev_warn(dev,
>>> +                                "DMA and flow control via gpio may cause
>>> some problems. DMA disabled!\n");
>>> +               clear_bit(MXS_AUART_RTSCTS, &s->flags);
>>> +       }
>>> +
>>> +       return true;
>>> +}
>>> +
>>>   static int mxs_auart_probe(struct platform_device *pdev)
>>>   {
>>>         const struct of_device_id *of_id =
>>> @@ -1069,6 +1105,10 @@ static int mxs_auart_probe(struct platform_device
>>> *pdev)
>>>         platform_set_drvdata(pdev, s);
>>>   +     if (!mxs_auart_init_gpios(s, &pdev->dev))
>>> +               dev_err(&pdev->dev,
>>> +                       "Failed to initialize GPIOs. The serial port may
>>> not work as expected\n");
>>> +
>>>         auart_port[s->port.line] = s;
>>>         mxs_auart_reset(&s->port);
>>>
>> Reviewed-by: Richard Genoud <richard.genoud at gmail.com>
>
>



-- 
for me, ck means con kolivas and not calvin klein... does it mean I'm a geek ?



More information about the linux-arm-kernel mailing list