* [PATCH v4 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl
2014-10-10 16:53 [PATCH v4 0/4] serial: mxs-auart: gpios as modem signals Janusz Uzycki
@ 2014-10-10 16:53 ` Janusz Uzycki
2014-10-24 15:31 ` Richard Genoud
2014-10-10 16:53 ` [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals Janusz Uzycki
` (2 subsequent siblings)
3 siblings, 1 reply; 18+ messages in thread
From: Janusz Uzycki @ 2014-10-10 16:53 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Richard Genoud,
Fabio Estevam, linux-serial, devicetree, linux-arm-kernel,
Janusz Uzycki
Russell King:
The only thing which the .get_mctrl method is supposed to do is
to return the state of the /input/ lines, which are CTS, DCD, DSR, RI.
The output line state is stored in port->mctrl, and is added to
the returned value by serial_core when it's required.
RTS output state should not be returned from the .get_mctrl method.
This patch removes ctrl variable from mxs_auart_port
and removes useless reading back RTS line.
The ctrl variable in mxs_auart_port duplicated mctrl,
member of uart_port structure in serial_core.h.
The removed code from mxs_auart_set_mctrl() and mxs_auart_get_mctrl
duplicated uart_update_mctrl() and uart_tiocmget()
in serial_core.c.
Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
---
v3 -> v4 changelog:
[PATCH 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl
* renamed from "serial: mxs-auart: ctrl removed from mxs_auart_port"
* mxs_auart_get_mctrl() read back RTS line. It is removed too.
v2 -> v3 changelog:
The patch was introduced:
new [PATCH 1/4] serial: mxs-auart: ctrl removed from mxs_auart_port
* the ctrl variable duplicated mctrl, member of uart_port structure
in serial_core.h
* the code duplicated uart_update_mctrl() and uart_tiocmget()
in serial_core.c
* mxs_auart_get_mctrl() reads back RTS line. It could be removed too
but not sure.
---
drivers/tty/serial/mxs-auart.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index e838e84..2d49901 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -143,7 +143,6 @@ struct mxs_auart_port {
#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
#define MXS_AUART_RTSCTS 4 /* bit 4 */
unsigned long flags;
- unsigned int ctrl;
enum mxs_auart_type devtype;
unsigned int irq;
@@ -406,8 +405,6 @@ 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);
@@ -418,24 +415,17 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
ctrl |= AUART_CTRL2_RTS;
}
- s->ctrl = mctrl;
writel(ctrl, u->membase + AUART_CTRL2);
}
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);
- int ctrl2 = readl(u->membase + AUART_CTRL2);
- u32 mctrl = s->ctrl;
+ u32 mctrl = 0;
- mctrl &= ~TIOCM_CTS;
if (stat & AUART_STAT_CTS)
mctrl |= TIOCM_CTS;
- if (ctrl2 & AUART_CTRL2_RTS)
- mctrl |= TIOCM_RTS;
-
return mctrl;
}
@@ -1071,8 +1061,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->port.type = PORT_IMX;
s->port.dev = s->dev = &pdev->dev;
- s->ctrl = 0;
-
s->irq = platform_get_irq(pdev, 0);
s->port.irq = s->irq;
ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
--
1.7.11.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl
2014-10-10 16:53 ` [PATCH v4 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl Janusz Uzycki
@ 2014-10-24 15:31 ` Richard Genoud
0 siblings, 0 replies; 18+ messages in thread
From: Richard Genoud @ 2014-10-24 15:31 UTC (permalink / raw)
To: Janusz Uzycki, Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Fabio Estevam, linux-serial,
devicetree, linux-arm-kernel
On 10/10/2014 18:53, Janusz Uzycki wrote:
> Russell King:
> The only thing which the .get_mctrl method is supposed to do is
> to return the state of the /input/ lines, which are CTS, DCD, DSR, RI.
> The output line state is stored in port->mctrl, and is added to
> the returned value by serial_core when it's required.
> RTS output state should not be returned from the .get_mctrl method.
>
> This patch removes ctrl variable from mxs_auart_port
> and removes useless reading back RTS line.
>
> The ctrl variable in mxs_auart_port duplicated mctrl,
> member of uart_port structure in serial_core.h.
> The removed code from mxs_auart_set_mctrl() and mxs_auart_get_mctrl
> duplicated uart_update_mctrl() and uart_tiocmget()
> in serial_core.c.
>
> Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
> ---
> v3 -> v4 changelog:
> [PATCH 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl
> * renamed from "serial: mxs-auart: ctrl removed from mxs_auart_port"
> * mxs_auart_get_mctrl() read back RTS line. It is removed too.
>
> v2 -> v3 changelog:
> The patch was introduced:
> new [PATCH 1/4] serial: mxs-auart: ctrl removed from mxs_auart_port
> * the ctrl variable duplicated mctrl, member of uart_port structure
> in serial_core.h
> * the code duplicated uart_update_mctrl() and uart_tiocmget()
> in serial_core.c
> * mxs_auart_get_mctrl() reads back RTS line. It could be removed too
> but not sure.
>
> ---
> drivers/tty/serial/mxs-auart.c | 14 +-------------
> 1 file changed, 1 insertion(+), 13 deletions(-)
>
> diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
> index e838e84..2d49901 100644
> --- a/drivers/tty/serial/mxs-auart.c
> +++ b/drivers/tty/serial/mxs-auart.c
> @@ -143,7 +143,6 @@ struct mxs_auart_port {
> #define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
> #define MXS_AUART_RTSCTS 4 /* bit 4 */
> unsigned long flags;
> - unsigned int ctrl;
> enum mxs_auart_type devtype;
>
> unsigned int irq;
> @@ -406,8 +405,6 @@ 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);
> @@ -418,24 +415,17 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
> ctrl |= AUART_CTRL2_RTS;
> }
>
> - s->ctrl = mctrl;
> writel(ctrl, u->membase + AUART_CTRL2);
> }
>
> 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);
> - int ctrl2 = readl(u->membase + AUART_CTRL2);
> - u32 mctrl = s->ctrl;
> + u32 mctrl = 0;
>
> - mctrl &= ~TIOCM_CTS;
> if (stat & AUART_STAT_CTS)
> mctrl |= TIOCM_CTS;
>
> - if (ctrl2 & AUART_CTRL2_RTS)
> - mctrl |= TIOCM_RTS;
> -
> return mctrl;
> }
>
> @@ -1071,8 +1061,6 @@ static int mxs_auart_probe(struct platform_device *pdev)
> s->port.type = PORT_IMX;
> s->port.dev = s->dev = &pdev->dev;
>
> - s->ctrl = 0;
> -
> s->irq = platform_get_irq(pdev, 0);
> s->port.irq = s->irq;
> ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
>
Seems good to me.
Reviewed-by: Richard Genoud <richard.genoud@gmail.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals
2014-10-10 16:53 [PATCH v4 0/4] serial: mxs-auart: gpios as modem signals Janusz Uzycki
2014-10-10 16:53 ` [PATCH v4 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl Janusz Uzycki
@ 2014-10-10 16:53 ` Janusz Uzycki
2014-10-24 15:32 ` Richard Genoud
2014-10-10 16:53 ` [PATCH v4 3/4] serial: mxs-auart: add interrupts for modem control lines Janusz Uzycki
2014-10-10 16:53 ` [PATCH v4 4/4] serial: mxs-auart: enable PPS support Janusz Uzycki
3 siblings, 1 reply; 18+ messages in thread
From: Janusz Uzycki @ 2014-10-10 16:53 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Richard Genoud,
Fabio Estevam, linux-serial, devicetree, linux-arm-kernel,
Janusz Uzycki
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@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@8006a000 {
@@ -21,6 +26,9 @@ auart0: serial@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 */
+ 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);
--
1.7.11.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals
2014-10-10 16:53 ` [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals Janusz Uzycki
@ 2014-10-24 15:32 ` Richard Genoud
2014-10-24 15:51 ` Janusz Użycki
0 siblings, 1 reply; 18+ messages in thread
From: Richard Genoud @ 2014-10-24 15:32 UTC (permalink / raw)
To: Janusz Uzycki, Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Fabio Estevam, linux-serial,
devicetree, linux-arm-kernel
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@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@8006a000 {
> @@ -21,6 +26,9 @@ auart0: serial@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.)
> + 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@gmail.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals
2014-10-24 15:32 ` Richard Genoud
@ 2014-10-24 15:51 ` Janusz Użycki
2014-10-31 8:48 ` Richard Genoud
0 siblings, 1 reply; 18+ messages in thread
From: Janusz Użycki @ 2014-10-24 15:51 UTC (permalink / raw)
To: Richard Genoud, Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Fabio Estevam, linux-serial,
devicetree, linux-arm-kernel
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@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@8006a000 {
>> @@ -21,6 +26,9 @@ auart0: serial@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?
After review and small fixes requested new version is required for a
patchset
or rather patch resend?
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@gmail.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals
2014-10-24 15:51 ` Janusz Użycki
@ 2014-10-31 8:48 ` Richard Genoud
2014-11-06 11:13 ` Janusz Użycki
0 siblings, 1 reply; 18+ messages in thread
From: Richard Genoud @ 2014-10-31 8:48 UTC (permalink / raw)
To: Janusz Użycki, Huang Shijie
Cc: Greg Kroah-Hartman, Russell King - ARM Linux, Jiri Slaby,
Fabio Estevam, linux-serial@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org
2014-10-24 17:51 GMT+02:00 Janusz Użycki <j.uzycki@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@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@8006a000 {
>>> @@ -21,6 +26,9 @@ auart0: serial@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@gmail.com>
>
>
--
for me, ck means con kolivas and not calvin klein... does it mean I'm a geek ?
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals
2014-10-31 8:48 ` Richard Genoud
@ 2014-11-06 11:13 ` Janusz Użycki
[not found] ` <CAMiH66FKJm8hcgtR=-ZzzpCq+PQ8xkixbUnMzRPVd_cM_6VM1w@mail.gmail.com>
0 siblings, 1 reply; 18+ messages in thread
From: Janusz Użycki @ 2014-11-06 11:13 UTC (permalink / raw)
To: Richard Genoud, Huang Shijie
Cc: Greg Kroah-Hartman, Russell King - ARM Linux, Jiri Slaby,
Fabio Estevam, linux-serial@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org
Any news?
best regards
Janusz
W dniu 2014-10-31 o 09:48, Richard Genoud pisze:
> 2014-10-24 17:51 GMT+02:00 Janusz Użycki <j.uzycki@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@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@8006a000 {
>>>> @@ -21,6 +26,9 @@ auart0: serial@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@gmail.com>
>>
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v4 3/4] serial: mxs-auart: add interrupts for modem control lines
2014-10-10 16:53 [PATCH v4 0/4] serial: mxs-auart: gpios as modem signals Janusz Uzycki
2014-10-10 16:53 ` [PATCH v4 1/4] serial: mxs-auart: clean get_mctrl and set_mctrl Janusz Uzycki
2014-10-10 16:53 ` [PATCH v4 2/4] serial: mxs-auart: use mctrl_gpio helpers for handling modem signals Janusz Uzycki
@ 2014-10-10 16:53 ` Janusz Uzycki
2014-10-10 16:53 ` [PATCH v4 4/4] serial: mxs-auart: enable PPS support Janusz Uzycki
3 siblings, 0 replies; 18+ messages in thread
From: Janusz Uzycki @ 2014-10-10 16:53 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Richard Genoud,
Fabio Estevam, linux-serial, devicetree, linux-arm-kernel,
Janusz Uzycki
Handle CTS/DSR/RI/DCD GPIO interrupts in mxs-auart.
Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
---
v3 -> v4 changelog:
* rebased
v2 -> v3 changelog:
* introduces mctrl_prev instead of removed ctrl
* mxs_auart_modem_status() moved from [3/4]
* mxs_auart_modem_status() interrupt_enabled meant s->ms_irq_enabled
---
drivers/tty/serial/mxs-auart.c | 174 ++++++++++++++++++++++++++-
1 file changed, 172 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 8bbcfd1..5ce4a50 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -42,7 +42,10 @@
#include <asm/cacheflush.h>
+#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/err.h>
+#include <linux/irq.h>
#include "serial_mctrl_gpio.h"
#define MXS_AUART_PORTS 5
@@ -146,6 +149,7 @@ struct mxs_auart_port {
#define MXS_AUART_DMA_RX_READY 3 /* bit 3 */
#define MXS_AUART_RTSCTS 4 /* bit 4 */
unsigned long flags;
+ unsigned int mctrl_prev;
enum mxs_auart_type devtype;
unsigned int irq;
@@ -163,6 +167,8 @@ struct mxs_auart_port {
void *rx_dma_buf;
struct mctrl_gpios *gpios;
+ int gpio_irq[UART_GPIO_MAX];
+ bool ms_irq_enabled;
};
static struct platform_device_id mxs_auart_devtype[] = {
@@ -427,6 +433,29 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
mctrl_gpio_set(s->gpios, mctrl);
}
+#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS)
+static u32 mxs_auart_modem_status(struct mxs_auart_port *s, u32 mctrl)
+{
+ u32 mctrl_diff;
+
+ mctrl_diff = mctrl ^ s->mctrl_prev;
+ s->mctrl_prev = mctrl;
+ if (mctrl_diff & MCTRL_ANY_DELTA && s->ms_irq_enabled &&
+ s->port.state != NULL) {
+ if (mctrl_diff & TIOCM_RI)
+ s->port.icount.rng++;
+ if (mctrl_diff & TIOCM_DSR)
+ s->port.icount.dsr++;
+ if (mctrl_diff & TIOCM_CD)
+ uart_handle_dcd_change(&s->port, mctrl & TIOCM_CD);
+ if (mctrl_diff & TIOCM_CTS)
+ uart_handle_cts_change(&s->port, mctrl & TIOCM_CTS);
+
+ wake_up_interruptible(&s->port.state->port.delta_msr_wait);
+ }
+ return mctrl;
+}
+
static u32 mxs_auart_get_mctrl(struct uart_port *u)
{
struct mxs_auart_port *s = to_auart_port(u);
@@ -439,6 +468,64 @@ static u32 mxs_auart_get_mctrl(struct uart_port *u)
return mctrl_gpio_get(s->gpios, &mctrl);
}
+/*
+ * Enable modem status interrupts
+ */
+static void mxs_auart_enable_ms(struct uart_port *port)
+{
+ struct mxs_auart_port *s = to_auart_port(port);
+
+ /*
+ * Interrupt should not be enabled twice
+ */
+ if (s->ms_irq_enabled)
+ return;
+
+ s->ms_irq_enabled = true;
+
+ if (s->gpio_irq[UART_GPIO_CTS] >= 0)
+ enable_irq(s->gpio_irq[UART_GPIO_CTS]);
+ /* TODO: enable AUART_INTR_CTSMIEN otherwise */
+
+ if (s->gpio_irq[UART_GPIO_DSR] >= 0)
+ enable_irq(s->gpio_irq[UART_GPIO_DSR]);
+
+ if (s->gpio_irq[UART_GPIO_RI] >= 0)
+ enable_irq(s->gpio_irq[UART_GPIO_RI]);
+
+ if (s->gpio_irq[UART_GPIO_DCD] >= 0)
+ enable_irq(s->gpio_irq[UART_GPIO_DCD]);
+}
+
+/*
+ * Disable modem status interrupts
+ */
+static void mxs_auart_disable_ms(struct uart_port *port)
+{
+ struct mxs_auart_port *s = to_auart_port(port);
+
+ /*
+ * Interrupt should not be disabled twice
+ */
+ if (!s->ms_irq_enabled)
+ return;
+
+ s->ms_irq_enabled = false;
+
+ if (s->gpio_irq[UART_GPIO_CTS] >= 0)
+ disable_irq(s->gpio_irq[UART_GPIO_CTS]);
+ /* TODO: disable AUART_INTR_CTSMIEN otherwise */
+
+ if (s->gpio_irq[UART_GPIO_DSR] >= 0)
+ disable_irq(s->gpio_irq[UART_GPIO_DSR]);
+
+ if (s->gpio_irq[UART_GPIO_RI] >= 0)
+ disable_irq(s->gpio_irq[UART_GPIO_RI]);
+
+ if (s->gpio_irq[UART_GPIO_DCD] >= 0)
+ disable_irq(s->gpio_irq[UART_GPIO_DCD]);
+}
+
static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
static void dma_rx_callback(void *arg)
{
@@ -689,6 +776,12 @@ static void mxs_auart_settermios(struct uart_port *u,
dev_err(s->dev, "We can not start up the DMA.\n");
}
}
+
+ /* CTS flow-control and modem-status interrupts */
+ if (UART_ENABLE_MS(u, termios->c_cflag))
+ mxs_auart_enable_ms(u);
+ else
+ mxs_auart_disable_ms(u);
}
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
@@ -706,8 +799,18 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
| AUART_INTR_CTSMIS),
s->port.membase + AUART_INTR_CLR);
+ /*
+ * Dealing with GPIO interrupt
+ */
+ if (irq == s->gpio_irq[UART_GPIO_CTS] ||
+ irq == s->gpio_irq[UART_GPIO_DCD] ||
+ irq == s->gpio_irq[UART_GPIO_DSR] ||
+ irq == s->gpio_irq[UART_GPIO_RI])
+ mxs_auart_modem_status(s,
+ mctrl_gpio_get(s->gpios, &s->mctrl_prev));
+
if (istat & AUART_INTR_CTSMIS) {
- if (CTS_AT_AUART())
+ if (CTS_AT_AUART() && s->ms_irq_enabled)
uart_handle_cts_change(&s->port,
stat & AUART_STAT_CTS);
writel(AUART_INTR_CTSMIS,
@@ -770,6 +873,10 @@ static int mxs_auart_startup(struct uart_port *u)
*/
writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
+ /* get initial status of modem lines */
+ mctrl_gpio_get(s->gpios, &s->mctrl_prev);
+
+ s->ms_irq_enabled = false;
return 0;
}
@@ -777,6 +884,8 @@ static void mxs_auart_shutdown(struct uart_port *u)
{
struct mxs_auart_port *s = to_auart_port(u);
+ mxs_auart_disable_ms(u);
+
if (auart_dma_enabled(s))
mxs_auart_dma_exit(s);
@@ -833,6 +942,7 @@ static struct uart_ops mxs_auart_ops = {
.start_tx = mxs_auart_start_tx,
.stop_tx = mxs_auart_stop_tx,
.stop_rx = mxs_auart_stop_rx,
+ .enable_ms = mxs_auart_enable_ms,
.break_ctl = mxs_auart_break_ctl,
.set_mctrl = mxs_auart_set_mctrl,
.get_mctrl = mxs_auart_get_mctrl,
@@ -1035,6 +1145,9 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
{
+ enum mctrl_gpio_idx i;
+ struct gpio_desc *gpiod;
+
s->gpios = mctrl_gpio_init(dev, 0);
if (IS_ERR_OR_NULL(s->gpios))
return false;
@@ -1047,9 +1160,54 @@ static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev)
clear_bit(MXS_AUART_RTSCTS, &s->flags);
}
+ for (i = 0; i < UART_GPIO_MAX; i++) {
+ gpiod = mctrl_gpio_to_gpiod(s->gpios, i);
+ if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
+ s->gpio_irq[i] = gpiod_to_irq(gpiod);
+ else
+ s->gpio_irq[i] = -EINVAL;
+ }
+
return true;
}
+static void mxs_auart_free_gpio_irq(struct mxs_auart_port *s)
+{
+ enum mctrl_gpio_idx i;
+
+ for (i = 0; i < UART_GPIO_MAX; i++)
+ if (s->gpio_irq[i] >= 0)
+ free_irq(s->gpio_irq[i], s);
+}
+
+static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
+{
+ int *irq = s->gpio_irq;
+ enum mctrl_gpio_idx i;
+ int err = 0;
+
+ for (i = 0; (i < UART_GPIO_MAX) && !err; i++) {
+ if (irq[i] < 0)
+ continue;
+
+ irq_set_status_flags(irq[i], IRQ_NOAUTOEN);
+ err = request_irq(irq[i], mxs_auart_irq_handle,
+ IRQ_TYPE_EDGE_BOTH, dev_name(s->dev), s);
+ if (err)
+ dev_err(s->dev, "%s - Can't get %d irq\n",
+ __func__, irq[i]);
+ }
+
+ /*
+ * If something went wrong, rollback.
+ */
+ while (err && (--i >= 0))
+ if (irq[i] >= 0)
+ free_irq(irq[i], s);
+
+ return err;
+}
+
static int mxs_auart_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@@ -1097,6 +1255,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->port.type = PORT_IMX;
s->port.dev = s->dev = &pdev->dev;
+ s->mctrl_prev = 0;
+
s->irq = platform_get_irq(pdev, 0);
s->port.irq = s->irq;
ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
@@ -1109,13 +1269,20 @@ static int mxs_auart_probe(struct platform_device *pdev)
dev_err(&pdev->dev,
"Failed to initialize GPIOs. The serial port may not work as expected\n");
+ /*
+ * Get the GPIO lines IRQ
+ */
+ ret = mxs_auart_request_gpio_irq(s);
+ if (ret)
+ goto out_free_irq;
+
auart_port[s->port.line] = s;
mxs_auart_reset(&s->port);
ret = uart_add_one_port(&auart_driver, &s->port);
if (ret)
- goto out_free_irq;
+ goto out_free_gpio_irq;
version = readl(s->port.membase + AUART_VERSION);
dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
@@ -1124,6 +1291,8 @@ static int mxs_auart_probe(struct platform_device *pdev)
return 0;
+out_free_gpio_irq:
+ mxs_auart_free_gpio_irq(s);
out_free_irq:
auart_port[pdev->id] = NULL;
free_irq(s->irq, s);
@@ -1143,6 +1312,7 @@ static int mxs_auart_remove(struct platform_device *pdev)
auart_port[pdev->id] = NULL;
+ mxs_auart_free_gpio_irq(s);
clk_put(s->clk);
free_irq(s->irq, s);
kfree(s);
--
1.7.11.3
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v4 4/4] serial: mxs-auart: enable PPS support
2014-10-10 16:53 [PATCH v4 0/4] serial: mxs-auart: gpios as modem signals Janusz Uzycki
` (2 preceding siblings ...)
2014-10-10 16:53 ` [PATCH v4 3/4] serial: mxs-auart: add interrupts for modem control lines Janusz Uzycki
@ 2014-10-10 16:53 ` Janusz Uzycki
3 siblings, 0 replies; 18+ messages in thread
From: Janusz Uzycki @ 2014-10-10 16:53 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Russell King - ARM Linux, Jiri Slaby, Richard Genoud,
Fabio Estevam, linux-serial, devicetree, linux-arm-kernel,
Janusz Uzycki
Enables PPS support in mxs-auart serial driver to make PPS API working.
Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
---
v3 -> v4 changelog:
* coding style: braces in both branches of condition
v2 -> v3 changelog:
* no changes
---
drivers/tty/serial/mxs-auart.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 5ce4a50..840c1f7 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -784,6 +784,16 @@ static void mxs_auart_settermios(struct uart_port *u,
mxs_auart_disable_ms(u);
}
+static void mxs_auart_set_ldisc(struct uart_port *port, int new)
+{
+ if (new == N_PPS) {
+ port->flags |= UPF_HARDPPS_CD;
+ mxs_auart_enable_ms(port);
+ } else {
+ port->flags &= ~UPF_HARDPPS_CD;
+ }
+}
+
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
{
u32 istat;
@@ -949,6 +959,7 @@ static struct uart_ops mxs_auart_ops = {
.startup = mxs_auart_startup,
.shutdown = mxs_auart_shutdown,
.set_termios = mxs_auart_settermios,
+ .set_ldisc = mxs_auart_set_ldisc,
.type = mxs_auart_type,
.release_port = mxs_auart_release_port,
.request_port = mxs_auart_request_port,
--
1.7.11.3
^ permalink raw reply related [flat|nested] 18+ messages in thread