All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/3] tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c
@ 2014-03-10 16:45 ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Nicolas Ferre, Linus Walleij,
	Alexander Shiyan, linux-serial, linux-arm-kernel, Richard Genoud

The USART controller on sam9x5 chips (and also all AT91/SAMA5 chips
but at91rm9200) are not capable of handling DTR/DSR/DCD/RI signal.
Moreover, even if the controller can handle CTS/RTS, the dedicated
CTS/RTS pins are already muxed for other peripherals (LCDC/EMAC/MMC).

So this patchset adds the possibility to control those lines via GPIO,
as it is done for RTS in the patch "switch atmel serial to use gpiolib"

As it was suggested by Alexander Shiyan, I made that available for
every board.

Patch 1 implements the generic helpers to control modem lines via GPIO
Patch 2 implements modem control lines in atmel_serial atmel_serial.
Patch 3 implements the interrupts of CTS/DSR/DCD/RI in atmel_serial.

I've taken into account lasts remarks that Alexander made me off-list.

This is based on next-20140307 + [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
(It has been acked by Linus, but I don't think it has been applied in a tree yet)

Tested on at91sam9g35, with a null modem cable between 2 serial ports,
one with CTS/RTS controlled by the USART controller, the other via GPIO,
full duplex transfers.
Did some tests also with null modem cables on a PC, and with real modems.
And a lot of rings tested with ioctl TIOCMIWAIT, TIOCGICOUNT, TIOCMGET (and TIOCMSET, for RTS/DTR)

Updates from v5:
	- Add UART_GPIO_RNG.
	- Add atmel-serial documentation that was lost in v3 !
	- switched a dev_warn to dev_dbg.
	- remove checks (irq >= 0) in interrupt handler.
	- simplified a !IS_ERR_OR_NULL(gpiod) test to just gpiod
	- fixed a bug in rollback code in atmel_serial.c

Updates from v4:
	- patches "tty/serial: at91: remove unused open/close hooks" and
	"tty/serial: at91: use dev_err instead of printk" have been picked
	by Greg on tty tree.
	- As Alexander pointed out, IS_ERR_OR_NULL() was replaced by a simple
	check againts NULL in patch 1/3
	- in path 1/3, a warning is produced instead of an error when we can't set
	the direction of a GPIO.

Updates from v3:
	- add static keyword on struct uart0_gpios_table.
	- add use an index at the mctrl_gpio_init() function to make it
	usable by driver that allocates several ports at once.
	- hide struct gpio_desc from users.
	- patch "pinctrl: at91: implement get_direction" has been picked by Linus.
	- patch "ARM: at91: gpio: implement get_direction" has been acked by Linus.

Updates from v2:
	- remove UART_GPIO_MIN/UART_GPIO_MAX_INPUT and use a direction
	boolean instead.
	- implement get_direction in at91 pinctrl and mach-at91/gpio.c.
	- remove the get_mctrl_gpio_name() function that was used for
	logs only.
	- split atmel_serial.c patch in 2.
	- use a gpio lookup table to declare modem gpios in platform
	devices boards. So there's no more special case for platform
	data gpios in atmel_serial.c.

Updates from v1:
	- Instead of controlling modem signal only on atmel board, the
	code is now available for every board.
	- The active low flag from device tree is now used.

Richard Genoud (3):
  tty/serial: Add GPIOLIB helpers for controlling modem lines
  tty/serial: at91: use mctrl_gpio helpers
  tty/serial: at91: add interrupts for modem control lines

 .../devicetree/bindings/serial/atmel-usart.txt     |  12 +-
 Documentation/serial/driver                        |  25 +++
 arch/arm/mach-at91/at91rm9200_devices.c            |  16 +-
 arch/arm/mach-at91/at91sam9260_devices.c           |   7 -
 arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
 arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
 drivers/tty/serial/Kconfig                         |   4 +
 drivers/tty/serial/Makefile                        |   3 +
 drivers/tty/serial/atmel_serial.c                  | 230 +++++++++++++++++----
 drivers/tty/serial/serial_mctrl_gpio.c             | 143 +++++++++++++
 drivers/tty/serial/serial_mctrl_gpio.h             | 110 ++++++++++
 include/linux/platform_data/atmel.h                |   1 -
 14 files changed, 496 insertions(+), 73 deletions(-)
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.c
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.h

-- 
1.8.5.5


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 0/3] tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c
@ 2014-03-10 16:45 ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

The USART controller on sam9x5 chips (and also all AT91/SAMA5 chips
but at91rm9200) are not capable of handling DTR/DSR/DCD/RI signal.
Moreover, even if the controller can handle CTS/RTS, the dedicated
CTS/RTS pins are already muxed for other peripherals (LCDC/EMAC/MMC).

So this patchset adds the possibility to control those lines via GPIO,
as it is done for RTS in the patch "switch atmel serial to use gpiolib"

As it was suggested by Alexander Shiyan, I made that available for
every board.

Patch 1 implements the generic helpers to control modem lines via GPIO
Patch 2 implements modem control lines in atmel_serial atmel_serial.
Patch 3 implements the interrupts of CTS/DSR/DCD/RI in atmel_serial.

I've taken into account lasts remarks that Alexander made me off-list.

This is based on next-20140307 + [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
(It has been acked by Linus, but I don't think it has been applied in a tree yet)

Tested on at91sam9g35, with a null modem cable between 2 serial ports,
one with CTS/RTS controlled by the USART controller, the other via GPIO,
full duplex transfers.
Did some tests also with null modem cables on a PC, and with real modems.
And a lot of rings tested with ioctl TIOCMIWAIT, TIOCGICOUNT, TIOCMGET (and TIOCMSET, for RTS/DTR)

Updates from v5:
	- Add UART_GPIO_RNG.
	- Add atmel-serial documentation that was lost in v3 !
	- switched a dev_warn to dev_dbg.
	- remove checks (irq >= 0) in interrupt handler.
	- simplified a !IS_ERR_OR_NULL(gpiod) test to just gpiod
	- fixed a bug in rollback code in atmel_serial.c

Updates from v4:
	- patches "tty/serial: at91: remove unused open/close hooks" and
	"tty/serial: at91: use dev_err instead of printk" have been picked
	by Greg on tty tree.
	- As Alexander pointed out, IS_ERR_OR_NULL() was replaced by a simple
	check againts NULL in patch 1/3
	- in path 1/3, a warning is produced instead of an error when we can't set
	the direction of a GPIO.

Updates from v3:
	- add static keyword on struct uart0_gpios_table.
	- add use an index at the mctrl_gpio_init() function to make it
	usable by driver that allocates several ports at once.
	- hide struct gpio_desc from users.
	- patch "pinctrl: at91: implement get_direction" has been picked by Linus.
	- patch "ARM: at91: gpio: implement get_direction" has been acked by Linus.

Updates from v2:
	- remove UART_GPIO_MIN/UART_GPIO_MAX_INPUT and use a direction
	boolean instead.
	- implement get_direction in at91 pinctrl and mach-at91/gpio.c.
	- remove the get_mctrl_gpio_name() function that was used for
	logs only.
	- split atmel_serial.c patch in 2.
	- use a gpio lookup table to declare modem gpios in platform
	devices boards. So there's no more special case for platform
	data gpios in atmel_serial.c.

Updates from v1:
	- Instead of controlling modem signal only on atmel board, the
	code is now available for every board.
	- The active low flag from device tree is now used.

Richard Genoud (3):
  tty/serial: Add GPIOLIB helpers for controlling modem lines
  tty/serial: at91: use mctrl_gpio helpers
  tty/serial: at91: add interrupts for modem control lines

 .../devicetree/bindings/serial/atmel-usart.txt     |  12 +-
 Documentation/serial/driver                        |  25 +++
 arch/arm/mach-at91/at91rm9200_devices.c            |  16 +-
 arch/arm/mach-at91/at91sam9260_devices.c           |   7 -
 arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
 arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
 drivers/tty/serial/Kconfig                         |   4 +
 drivers/tty/serial/Makefile                        |   3 +
 drivers/tty/serial/atmel_serial.c                  | 230 +++++++++++++++++----
 drivers/tty/serial/serial_mctrl_gpio.c             | 143 +++++++++++++
 drivers/tty/serial/serial_mctrl_gpio.h             | 110 ++++++++++
 include/linux/platform_data/atmel.h                |   1 -
 14 files changed, 496 insertions(+), 73 deletions(-)
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.c
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.h

-- 
1.8.5.5

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-10 16:45 ` Richard Genoud
@ 2014-03-10 16:45   ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Nicolas Ferre, Linus Walleij,
	Alexander Shiyan, linux-serial, linux-arm-kernel, Richard Genoud

This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
GPIO.
This will be useful for many boards which have a serial controller that
only handle CTS/RTS pins (or even just RX/TX).

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
 Documentation/serial/driver            |  25 ++++++
 drivers/tty/serial/Kconfig             |   3 +
 drivers/tty/serial/Makefile            |   3 +
 drivers/tty/serial/serial_mctrl_gpio.c | 143 +++++++++++++++++++++++++++++++++
 drivers/tty/serial/serial_mctrl_gpio.h | 110 +++++++++++++++++++++++++
 5 files changed, 284 insertions(+)
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.c
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.h

diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index c3a7689a90e6..3bba1aeb799c 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -429,3 +429,28 @@ thus:
 		struct uart_port	port;
 		int			my_stuff;
 	};
+
+Modem control lines via GPIO
+----------------------------
+
+Some helpers are provided in order to set/get modem control lines via GPIO.
+
+mctrl_gpio_init(dev, idx):
+	This will get the {cts,rts,...}-gpios from device tree if they are
+	present and request them, set direction etc, and return an
+	allocated structure. devm_* functions are used, so there's no need
+	to call mctrl_gpio_free().
+
+mctrl_gpio_free(dev, gpios):
+	This will free the requested gpios in mctrl_gpio_init().
+	As devm_* function are used, there's generally no need to call
+	this function.
+
+mctrl_gpio_to_gpiod(gpios, gidx)
+	This returns the gpio structure associated to the modem line index.
+
+mctrl_gpio_set(gpios, mctrl):
+	This will sets the gpios according to the mctrl state.
+
+mctrl_gpio_get(gpios, mctrl):
+	This will update mctrl with the gpios values.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2e6d8ddc4425..7e8f15cfb8d0 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1509,4 +1509,7 @@ config SERIAL_ST_ASC_CONSOLE
 
 endmenu
 
+config SERIAL_MCTRL_GPIO
+	tristate
+
 endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 3680854fef41..bcf31da267dd 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -87,3 +87,6 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
+
+# GPIOLIB helpers for modem control lines
+obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
new file mode 100644
index 000000000000..bf9560ffe3f4
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -0,0 +1,143 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <uapi/asm-generic/termios.h>
+
+#include "serial_mctrl_gpio.h"
+
+struct mctrl_gpios {
+	struct gpio_desc *gpio[UART_GPIO_MAX];
+};
+
+static const struct {
+	const char *name;
+	unsigned int mctrl;
+	bool dir_out;
+} mctrl_gpios_desc[UART_GPIO_MAX] = {
+	{ "cts", TIOCM_CTS, false, },
+	{ "dsr", TIOCM_DSR, false, },
+	{ "dcd", TIOCM_CD, false, },
+	{ "rng", TIOCM_RNG, false, },
+	{ "rts", TIOCM_RTS, true, },
+	{ "dtr", TIOCM_DTR, true, },
+	{ "out1", TIOCM_OUT1, true, },
+	{ "out2", TIOCM_OUT2, true, },
+};
+
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+	enum mctrl_gpio_idx i;
+
+	if (IS_ERR_OR_NULL(gpios))
+		return;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
+		    mctrl_gpios_desc[i].dir_out)
+			gpiod_set_value(gpios->gpio[i],
+					!!(mctrl & mctrl_gpios_desc[i].mctrl));
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_set);
+
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx)
+{
+	if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
+		return gpios->gpio[gidx];
+	else
+		return NULL;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
+
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	enum mctrl_gpio_idx i;
+
+	/*
+	 * return it unchanged if the structure is not allocated
+	 */
+	if (IS_ERR_OR_NULL(gpios))
+		return *mctrl;
+
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
+		    !mctrl_gpios_desc[i].dir_out) {
+			if (gpiod_get_value(gpios->gpio[i]))
+				*mctrl |= mctrl_gpios_desc[i].mctrl;
+			else
+				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
+		}
+	}
+
+	return *mctrl;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_get);
+
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+{
+	struct mctrl_gpios *gpios;
+	enum mctrl_gpio_idx i;
+	int err;
+
+	gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
+	if (!gpios)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		gpios->gpio[i] = devm_gpiod_get_index(dev,
+						      mctrl_gpios_desc[i].name,
+						      idx);
+
+		/*
+		 * The GPIOs are maybe not all filled,
+		 * this is not an error.
+		 */
+		if (IS_ERR_OR_NULL(gpios->gpio[i]))
+			continue;
+
+		if (mctrl_gpios_desc[i].dir_out)
+			err = gpiod_direction_output(gpios->gpio[i], 0);
+		else
+			err = gpiod_direction_input(gpios->gpio[i]);
+		if (err) {
+			dev_dbg(dev, "Unable to set direction for %s GPIO",
+				mctrl_gpios_desc[i].name);
+			devm_gpiod_put(dev, gpios->gpio[i]);
+			gpios->gpio[i] = NULL;
+		}
+	}
+
+	return gpios;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
+
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+{
+	enum mctrl_gpio_idx i;
+
+	if (IS_ERR_OR_NULL(gpios))
+		return;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]))
+			devm_gpiod_put(dev, gpios->gpio[i]);
+	devm_kfree(dev, gpios);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_free);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
new file mode 100644
index 000000000000..400ba0494a17
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -0,0 +1,110 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SERIAL_MCTRL_GPIO__
+#define __SERIAL_MCTRL_GPIO__
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+
+enum mctrl_gpio_idx {
+	UART_GPIO_CTS,
+	UART_GPIO_DSR,
+	UART_GPIO_DCD,
+	UART_GPIO_RNG,
+	UART_GPIO_RI = UART_GPIO_RNG,
+	UART_GPIO_RTS,
+	UART_GPIO_DTR,
+	UART_GPIO_OUT1,
+	UART_GPIO_OUT2,
+	UART_GPIO_MAX,
+};
+
+/*
+ * Opaque descriptor for modem lines controlled by GPIOs
+ */
+struct mctrl_gpios;
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * Set state of the modem control output lines via GPIOs.
+ */
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
+
+/*
+ * Get state of the modem control output lines from GPIOs.
+ * The mctrl flags are updated and returned.
+ */
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
+
+/*
+ * Returns the associated struct gpio_desc to the modem line gidx
+ */
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx);
+
+/*
+ * Request and set direction of modem control lines GPIOs.
+ * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
+ * allocation error.
+ */
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
+
+/*
+ * Free the mctrl_gpios structure.
+ * Normally, this function will not be called, as the GPIOs will
+ * be disposed of by the resource management code.
+ */
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+
+#else /* GPIOLIB */
+
+static inline
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+}
+
+static inline
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	return *mctrl;
+}
+
+static inline
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+{
+}
+
+#endif /* GPIOLIB */
+
+#endif
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-03-10 16:45   ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
GPIO.
This will be useful for many boards which have a serial controller that
only handle CTS/RTS pins (or even just RX/TX).

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
 Documentation/serial/driver            |  25 ++++++
 drivers/tty/serial/Kconfig             |   3 +
 drivers/tty/serial/Makefile            |   3 +
 drivers/tty/serial/serial_mctrl_gpio.c | 143 +++++++++++++++++++++++++++++++++
 drivers/tty/serial/serial_mctrl_gpio.h | 110 +++++++++++++++++++++++++
 5 files changed, 284 insertions(+)
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.c
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.h

diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index c3a7689a90e6..3bba1aeb799c 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -429,3 +429,28 @@ thus:
 		struct uart_port	port;
 		int			my_stuff;
 	};
+
+Modem control lines via GPIO
+----------------------------
+
+Some helpers are provided in order to set/get modem control lines via GPIO.
+
+mctrl_gpio_init(dev, idx):
+	This will get the {cts,rts,...}-gpios from device tree if they are
+	present and request them, set direction etc, and return an
+	allocated structure. devm_* functions are used, so there's no need
+	to call mctrl_gpio_free().
+
+mctrl_gpio_free(dev, gpios):
+	This will free the requested gpios in mctrl_gpio_init().
+	As devm_* function are used, there's generally no need to call
+	this function.
+
+mctrl_gpio_to_gpiod(gpios, gidx)
+	This returns the gpio structure associated to the modem line index.
+
+mctrl_gpio_set(gpios, mctrl):
+	This will sets the gpios according to the mctrl state.
+
+mctrl_gpio_get(gpios, mctrl):
+	This will update mctrl with the gpios values.
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 2e6d8ddc4425..7e8f15cfb8d0 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1509,4 +1509,7 @@ config SERIAL_ST_ASC_CONSOLE
 
 endmenu
 
+config SERIAL_MCTRL_GPIO
+	tristate
+
 endif # TTY
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 3680854fef41..bcf31da267dd 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -87,3 +87,6 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
+
+# GPIOLIB helpers for modem control lines
+obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
new file mode 100644
index 000000000000..bf9560ffe3f4
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -0,0 +1,143 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <uapi/asm-generic/termios.h>
+
+#include "serial_mctrl_gpio.h"
+
+struct mctrl_gpios {
+	struct gpio_desc *gpio[UART_GPIO_MAX];
+};
+
+static const struct {
+	const char *name;
+	unsigned int mctrl;
+	bool dir_out;
+} mctrl_gpios_desc[UART_GPIO_MAX] = {
+	{ "cts", TIOCM_CTS, false, },
+	{ "dsr", TIOCM_DSR, false, },
+	{ "dcd", TIOCM_CD, false, },
+	{ "rng", TIOCM_RNG, false, },
+	{ "rts", TIOCM_RTS, true, },
+	{ "dtr", TIOCM_DTR, true, },
+	{ "out1", TIOCM_OUT1, true, },
+	{ "out2", TIOCM_OUT2, true, },
+};
+
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+	enum mctrl_gpio_idx i;
+
+	if (IS_ERR_OR_NULL(gpios))
+		return;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
+		    mctrl_gpios_desc[i].dir_out)
+			gpiod_set_value(gpios->gpio[i],
+					!!(mctrl & mctrl_gpios_desc[i].mctrl));
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_set);
+
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx)
+{
+	if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
+		return gpios->gpio[gidx];
+	else
+		return NULL;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
+
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	enum mctrl_gpio_idx i;
+
+	/*
+	 * return it unchanged if the structure is not allocated
+	 */
+	if (IS_ERR_OR_NULL(gpios))
+		return *mctrl;
+
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
+		    !mctrl_gpios_desc[i].dir_out) {
+			if (gpiod_get_value(gpios->gpio[i]))
+				*mctrl |= mctrl_gpios_desc[i].mctrl;
+			else
+				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
+		}
+	}
+
+	return *mctrl;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_get);
+
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+{
+	struct mctrl_gpios *gpios;
+	enum mctrl_gpio_idx i;
+	int err;
+
+	gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
+	if (!gpios)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		gpios->gpio[i] = devm_gpiod_get_index(dev,
+						      mctrl_gpios_desc[i].name,
+						      idx);
+
+		/*
+		 * The GPIOs are maybe not all filled,
+		 * this is not an error.
+		 */
+		if (IS_ERR_OR_NULL(gpios->gpio[i]))
+			continue;
+
+		if (mctrl_gpios_desc[i].dir_out)
+			err = gpiod_direction_output(gpios->gpio[i], 0);
+		else
+			err = gpiod_direction_input(gpios->gpio[i]);
+		if (err) {
+			dev_dbg(dev, "Unable to set direction for %s GPIO",
+				mctrl_gpios_desc[i].name);
+			devm_gpiod_put(dev, gpios->gpio[i]);
+			gpios->gpio[i] = NULL;
+		}
+	}
+
+	return gpios;
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_init);
+
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+{
+	enum mctrl_gpio_idx i;
+
+	if (IS_ERR_OR_NULL(gpios))
+		return;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (!IS_ERR_OR_NULL(gpios->gpio[i]))
+			devm_gpiod_put(dev, gpios->gpio[i]);
+	devm_kfree(dev, gpios);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_free);
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
new file mode 100644
index 000000000000..400ba0494a17
--- /dev/null
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -0,0 +1,110 @@
+/*
+ * Helpers for controlling modem lines via GPIO
+ *
+ * Copyright (C) 2014 Paratronic S.A.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SERIAL_MCTRL_GPIO__
+#define __SERIAL_MCTRL_GPIO__
+
+#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+
+enum mctrl_gpio_idx {
+	UART_GPIO_CTS,
+	UART_GPIO_DSR,
+	UART_GPIO_DCD,
+	UART_GPIO_RNG,
+	UART_GPIO_RI = UART_GPIO_RNG,
+	UART_GPIO_RTS,
+	UART_GPIO_DTR,
+	UART_GPIO_OUT1,
+	UART_GPIO_OUT2,
+	UART_GPIO_MAX,
+};
+
+/*
+ * Opaque descriptor for modem lines controlled by GPIOs
+ */
+struct mctrl_gpios;
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * Set state of the modem control output lines via GPIOs.
+ */
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl);
+
+/*
+ * Get state of the modem control output lines from GPIOs.
+ * The mctrl flags are updated and returned.
+ */
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl);
+
+/*
+ * Returns the associated struct gpio_desc to the modem line gidx
+ */
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx);
+
+/*
+ * Request and set direction of modem control lines GPIOs.
+ * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
+ * allocation error.
+ */
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx);
+
+/*
+ * Free the mctrl_gpios structure.
+ * Normally, this function will not be called, as the GPIOs will
+ * be disposed of by the resource management code.
+ */
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+
+#else /* GPIOLIB */
+
+static inline
+void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
+{
+}
+
+static inline
+unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
+{
+	return *mctrl;
+}
+
+static inline
+struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
+				      enum mctrl_gpio_idx gidx)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline
+struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx)
+{
+	return ERR_PTR(-ENOSYS);
+}
+
+static inline
+void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+{
+}
+
+#endif /* GPIOLIB */
+
+#endif
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 2/3] tty/serial: at91: use mctrl_gpio helpers
  2014-03-10 16:45 ` Richard Genoud
@ 2014-03-10 16:45   ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Nicolas Ferre, Linus Walleij,
	Alexander Shiyan, linux-serial, linux-arm-kernel, Richard Genoud

On sam9x5, dedicated CTS (and RTS) pins are unusable together with the
LCDC, the EMAC, or the MMC because they share the same line.

Moreover, the USART 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: Richard Genoud <richard.genoud@gmail.com>
---
 .../devicetree/bindings/serial/atmel-usart.txt     |  12 ++-
 arch/arm/mach-at91/at91rm9200_devices.c            |  16 ++--
 arch/arm/mach-at91/at91sam9260_devices.c           |   7 --
 arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
 arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
 drivers/tty/serial/Kconfig                         |   1 +
 drivers/tty/serial/atmel_serial.c                  | 105 ++++++++++++++-------
 include/linux/platform_data/atmel.h                |   1 -
 10 files changed, 90 insertions(+), 70 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt
index 17c1042b2df8..a6391e70a8fd 100644
--- a/Documentation/devicetree/bindings/serial/atmel-usart.txt
+++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt
@@ -13,8 +13,9 @@ Required properties:
 Optional properties:
 - atmel,use-dma-rx: use of PDC or DMA for receiving data
 - atmel,use-dma-tx: use of PDC or DMA for transmitting data
-- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
-  function pin for the USART RTS feature. If unsure, don't specify this property.
+- {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.
 - add dma bindings for dma transfer:
 	- dmas: DMA specifier, consisting of a phandle to DMA controller node,
 		memory peripheral interface and USART DMA channel ID, FIFO configuration.
@@ -35,7 +36,12 @@ Example:
 		clock-names = "usart";
 		atmel,use-dma-rx;
 		atmel,use-dma-tx;
-		rts-gpios = <&pioD 15 0>;
+		rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
+		cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
+		dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
+		dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
+		dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
+		rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
 	};
 
 - use DMA:
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index f3f19f21352a..291a90a5b1d4 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -15,6 +15,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -923,7 +924,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -962,7 +962,14 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
+};
+
+static struct gpiod_lookup_table uart0_gpios_table = {
+	.dev_id = "atmel_usart",
+	.table = {
+		GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
+		{ },
+	},
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -993,7 +1000,7 @@ static inline void configure_usart0_pins(unsigned pins)
 		 * We need to drive the pin manually. The serial driver will driver
 		 * this to high when initializing.
 		 */
-		uart0_data.rts_gpio = AT91_PIN_PA21;
+		gpiod_add_lookup_table(&uart0_gpios_table);
 	}
 }
 
@@ -1013,7 +1020,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1065,7 +1071,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1109,7 +1114,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 2ae7715f1309..a1b989eac8b8 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -820,7 +820,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -859,7 +858,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -911,7 +909,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -955,7 +952,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -999,7 +995,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -1043,7 +1038,6 @@ static struct resource uart4_resources[] = {
 static struct atmel_uart_data uart4_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart4_dmamask = DMA_BIT_MASK(32);
@@ -1082,7 +1076,6 @@ static struct resource uart5_resources[] = {
 static struct atmel_uart_data uart5_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart5_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 80e35895d28f..b5f7a7226ff8 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 43d53d6156dd..39803c3296b2 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -1325,7 +1325,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1364,7 +1363,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1408,7 +1406,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1452,7 +1449,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 77b04c2edd78..4e53d8d9737b 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1588,7 +1588,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1627,7 +1626,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1671,7 +1669,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1715,7 +1712,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1759,7 +1755,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 428fc412aaf1..f75985062913 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -957,7 +957,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -996,7 +995,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1048,7 +1046,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1092,7 +1089,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1136,7 +1132,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 7e8f15cfb8d0..f4e20410a138 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -97,6 +97,7 @@ config SERIAL_ATMEL
 	bool "AT91 / AT32 on-chip serial port support"
 	depends on ARCH_AT91 || AVR32
 	select SERIAL_CORE
+	select SERIAL_MCTRL_GPIO
 	help
 	  This enables the driver for the on-chip UARTs of the Atmel
 	  AT91 and AT32 processors.
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 53eeea13ff16..43ca659c1d4b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -43,6 +43,8 @@
 #include <linux/platform_data/atmel.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/err.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -57,6 +59,8 @@
 
 #include <linux/serial_core.h>
 
+#include "serial_mctrl_gpio.h"
+
 static void atmel_start_rx(struct uart_port *port);
 static void atmel_stop_rx(struct uart_port *port);
 
@@ -162,7 +166,7 @@ struct atmel_uart_port {
 	struct circ_buf		rx_ring;
 
 	struct serial_rs485	rs485;		/* rs485 settings */
-	int			rts_gpio;	/* optional RTS GPIO */
+	struct mctrl_gpios	*gpios;
 	unsigned int		tx_done_mask;
 	bool			is_usart;	/* usart or uart */
 	struct timer_list	uart_timer;	/* uart timer */
@@ -237,6 +241,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
 	return atmel_port->use_dma_rx;
 }
 
+static unsigned int atmel_get_lines_status(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int status, ret = 0;
+
+	status = UART_GET_CSR(port);
+
+	mctrl_gpio_get(atmel_port->gpios, &ret);
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_CTS))) {
+		if (ret & TIOCM_CTS)
+			status &= ~ATMEL_US_CTS;
+		else
+			status |= ATMEL_US_CTS;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_DSR))) {
+		if (ret & TIOCM_DSR)
+			status &= ~ATMEL_US_DSR;
+		else
+			status |= ATMEL_US_DSR;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_RI))) {
+		if (ret & TIOCM_RI)
+			status &= ~ATMEL_US_RI;
+		else
+			status |= ATMEL_US_RI;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_DCD))) {
+		if (ret & TIOCM_CD)
+			status &= ~ATMEL_US_DCD;
+		else
+			status |= ATMEL_US_DCD;
+	}
+
+	return status;
+}
+
 /* Enable or disable the rs485 support */
 void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 {
@@ -296,17 +344,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 	unsigned int mode;
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	/*
-	 * AT91RM9200 Errata #39: RTS0 is not internally connected
-	 * to PA21. We need to drive the pin as a GPIO.
-	 */
-	if (gpio_is_valid(atmel_port->rts_gpio)) {
-		if (mctrl & TIOCM_RTS)
-			gpio_set_value(atmel_port->rts_gpio, 0);
-		else
-			gpio_set_value(atmel_port->rts_gpio, 1);
-	}
-
 	if (mctrl & TIOCM_RTS)
 		control |= ATMEL_US_RTSEN;
 	else
@@ -319,6 +356,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 
 	UART_PUT_CR(port, control);
 
+	mctrl_gpio_set(atmel_port->gpios, mctrl);
+
 	/* Local loopback mode? */
 	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
 	if (mctrl & TIOCM_LOOP)
@@ -346,7 +385,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
  */
 static u_int atmel_get_mctrl(struct uart_port *port)
 {
-	unsigned int status, ret = 0;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int ret = 0, status;
 
 	status = UART_GET_CSR(port);
 
@@ -362,7 +402,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
 	if (!(status & ATMEL_US_RI))
 		ret |= TIOCM_RI;
 
-	return ret;
+	return mctrl_gpio_get(atmel_port->gpios, &ret);
 }
 
 /*
@@ -1042,7 +1082,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 	unsigned int status, pending, pass_counter = 0;
 
 	do {
-		status = UART_GET_CSR(port);
+		status = atmel_get_lines_status(port);
 		pending = status & UART_GET_IMR(port);
 		if (!pending)
 			break;
@@ -1568,7 +1608,7 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	/* Save current CSR for comparison in atmel_tasklet_func() */
-	atmel_port->irq_status_prev = UART_GET_CSR(port);
+	atmel_port->irq_status_prev = atmel_get_lines_status(port);
 	atmel_port->irq_status = atmel_port->irq_status_prev;
 
 	/*
@@ -2324,6 +2364,15 @@ static int atmel_serial_resume(struct platform_device *pdev)
 #define atmel_serial_resume NULL
 #endif
 
+static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
+{
+	p->gpios = mctrl_gpio_init(dev, 0);
+	if (IS_ERR_OR_NULL(p->gpios))
+		return -1;
+
+	return 0;
+}
+
 static int atmel_serial_probe(struct platform_device *pdev)
 {
 	struct atmel_uart_port *port;
@@ -2359,25 +2408,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
 	port = &atmel_ports[ret];
 	port->backup_imr = 0;
 	port->uart.line = ret;
-	port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
-	if (pdata)
-		port->rts_gpio = pdata->rts_gpio;
-	else if (np)
-		port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
-
-	if (gpio_is_valid(port->rts_gpio)) {
-		ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
-		if (ret) {
-			dev_err(&pdev->dev, "error requesting RTS GPIO\n");
-			goto err;
-		}
-		/* Default to 1 as RTS is active low */
-		ret = gpio_direction_output(port->rts_gpio, 1);
-		if (ret) {
-			dev_err(&pdev->dev, "error setting up RTS GPIO\n");
-			goto err;
-		}
-	}
+
+	ret = atmel_init_gpios(port, &pdev->dev);
+	if (ret < 0)
+		dev_err(&pdev->dev, "%s",
+			"Failed to initialize GPIOs. The serial port may not work as expected");
 
 	ret = atmel_init_port(port, pdev);
 	if (ret)
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
index e26b0c14edea..cea9f70133c5 100644
--- a/include/linux/platform_data/atmel.h
+++ b/include/linux/platform_data/atmel.h
@@ -84,7 +84,6 @@ struct atmel_uart_data {
 	short			use_dma_rx;	/* use receive DMA? */
 	void __iomem		*regs;		/* virt. base address, if any */
 	struct serial_rs485	rs485;		/* rs485 settings */
-	int			rts_gpio;	/* optional RTS GPIO */
 };
 
  /* Touchscreen Controller */
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 2/3] tty/serial: at91: use mctrl_gpio helpers
@ 2014-03-10 16:45   ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

On sam9x5, dedicated CTS (and RTS) pins are unusable together with the
LCDC, the EMAC, or the MMC because they share the same line.

Moreover, the USART 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: Richard Genoud <richard.genoud@gmail.com>
---
 .../devicetree/bindings/serial/atmel-usart.txt     |  12 ++-
 arch/arm/mach-at91/at91rm9200_devices.c            |  16 ++--
 arch/arm/mach-at91/at91sam9260_devices.c           |   7 --
 arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
 arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
 arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
 drivers/tty/serial/Kconfig                         |   1 +
 drivers/tty/serial/atmel_serial.c                  | 105 ++++++++++++++-------
 include/linux/platform_data/atmel.h                |   1 -
 10 files changed, 90 insertions(+), 70 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt
index 17c1042b2df8..a6391e70a8fd 100644
--- a/Documentation/devicetree/bindings/serial/atmel-usart.txt
+++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt
@@ -13,8 +13,9 @@ Required properties:
 Optional properties:
 - atmel,use-dma-rx: use of PDC or DMA for receiving data
 - atmel,use-dma-tx: use of PDC or DMA for transmitting data
-- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
-  function pin for the USART RTS feature. If unsure, don't specify this property.
+- {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.
 - add dma bindings for dma transfer:
 	- dmas: DMA specifier, consisting of a phandle to DMA controller node,
 		memory peripheral interface and USART DMA channel ID, FIFO configuration.
@@ -35,7 +36,12 @@ Example:
 		clock-names = "usart";
 		atmel,use-dma-rx;
 		atmel,use-dma-tx;
-		rts-gpios = <&pioD 15 0>;
+		rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
+		cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
+		dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
+		dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
+		dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
+		rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
 	};
 
 - use DMA:
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index f3f19f21352a..291a90a5b1d4 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -15,6 +15,7 @@
 
 #include <linux/dma-mapping.h>
 #include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/platform_device.h>
 #include <linux/i2c-gpio.h>
 
@@ -923,7 +924,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -962,7 +962,14 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
+};
+
+static struct gpiod_lookup_table uart0_gpios_table = {
+	.dev_id = "atmel_usart",
+	.table = {
+		GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
+		{ },
+	},
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -993,7 +1000,7 @@ static inline void configure_usart0_pins(unsigned pins)
 		 * We need to drive the pin manually. The serial driver will driver
 		 * this to high when initializing.
 		 */
-		uart0_data.rts_gpio = AT91_PIN_PA21;
+		gpiod_add_lookup_table(&uart0_gpios_table);
 	}
 }
 
@@ -1013,7 +1020,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1065,7 +1071,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1109,7 +1114,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 2ae7715f1309..a1b989eac8b8 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -820,7 +820,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -859,7 +858,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -911,7 +909,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -955,7 +952,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -999,7 +995,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
@@ -1043,7 +1038,6 @@ static struct resource uart4_resources[] = {
 static struct atmel_uart_data uart4_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart4_dmamask = DMA_BIT_MASK(32);
@@ -1082,7 +1076,6 @@ static struct resource uart5_resources[] = {
 static struct atmel_uart_data uart5_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart5_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 80e35895d28f..b5f7a7226ff8 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 43d53d6156dd..39803c3296b2 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -1325,7 +1325,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1364,7 +1363,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1408,7 +1406,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1452,7 +1449,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 77b04c2edd78..4e53d8d9737b 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -1588,7 +1588,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -1627,7 +1626,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1671,7 +1669,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1715,7 +1712,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1759,7 +1755,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 428fc412aaf1..f75985062913 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -957,7 +957,6 @@ static struct resource dbgu_resources[] = {
 static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 dbgu_dmamask = DMA_BIT_MASK(32);
@@ -996,7 +995,6 @@ static struct resource uart0_resources[] = {
 static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart0_dmamask = DMA_BIT_MASK(32);
@@ -1048,7 +1046,6 @@ static struct resource uart1_resources[] = {
 static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart1_dmamask = DMA_BIT_MASK(32);
@@ -1092,7 +1089,6 @@ static struct resource uart2_resources[] = {
 static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart2_dmamask = DMA_BIT_MASK(32);
@@ -1136,7 +1132,6 @@ static struct resource uart3_resources[] = {
 static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
-	.rts_gpio	= -EINVAL,
 };
 
 static u64 uart3_dmamask = DMA_BIT_MASK(32);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 7e8f15cfb8d0..f4e20410a138 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -97,6 +97,7 @@ config SERIAL_ATMEL
 	bool "AT91 / AT32 on-chip serial port support"
 	depends on ARCH_AT91 || AVR32
 	select SERIAL_CORE
+	select SERIAL_MCTRL_GPIO
 	help
 	  This enables the driver for the on-chip UARTs of the Atmel
 	  AT91 and AT32 processors.
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 53eeea13ff16..43ca659c1d4b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -43,6 +43,8 @@
 #include <linux/platform_data/atmel.h>
 #include <linux/timer.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
+#include <linux/err.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -57,6 +59,8 @@
 
 #include <linux/serial_core.h>
 
+#include "serial_mctrl_gpio.h"
+
 static void atmel_start_rx(struct uart_port *port);
 static void atmel_stop_rx(struct uart_port *port);
 
@@ -162,7 +166,7 @@ struct atmel_uart_port {
 	struct circ_buf		rx_ring;
 
 	struct serial_rs485	rs485;		/* rs485 settings */
-	int			rts_gpio;	/* optional RTS GPIO */
+	struct mctrl_gpios	*gpios;
 	unsigned int		tx_done_mask;
 	bool			is_usart;	/* usart or uart */
 	struct timer_list	uart_timer;	/* uart timer */
@@ -237,6 +241,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
 	return atmel_port->use_dma_rx;
 }
 
+static unsigned int atmel_get_lines_status(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int status, ret = 0;
+
+	status = UART_GET_CSR(port);
+
+	mctrl_gpio_get(atmel_port->gpios, &ret);
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_CTS))) {
+		if (ret & TIOCM_CTS)
+			status &= ~ATMEL_US_CTS;
+		else
+			status |= ATMEL_US_CTS;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_DSR))) {
+		if (ret & TIOCM_DSR)
+			status &= ~ATMEL_US_DSR;
+		else
+			status |= ATMEL_US_DSR;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_RI))) {
+		if (ret & TIOCM_RI)
+			status &= ~ATMEL_US_RI;
+		else
+			status |= ATMEL_US_RI;
+	}
+
+	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
+						UART_GPIO_DCD))) {
+		if (ret & TIOCM_CD)
+			status &= ~ATMEL_US_DCD;
+		else
+			status |= ATMEL_US_DCD;
+	}
+
+	return status;
+}
+
 /* Enable or disable the rs485 support */
 void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 {
@@ -296,17 +344,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 	unsigned int mode;
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	/*
-	 * AT91RM9200 Errata #39: RTS0 is not internally connected
-	 * to PA21. We need to drive the pin as a GPIO.
-	 */
-	if (gpio_is_valid(atmel_port->rts_gpio)) {
-		if (mctrl & TIOCM_RTS)
-			gpio_set_value(atmel_port->rts_gpio, 0);
-		else
-			gpio_set_value(atmel_port->rts_gpio, 1);
-	}
-
 	if (mctrl & TIOCM_RTS)
 		control |= ATMEL_US_RTSEN;
 	else
@@ -319,6 +356,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
 
 	UART_PUT_CR(port, control);
 
+	mctrl_gpio_set(atmel_port->gpios, mctrl);
+
 	/* Local loopback mode? */
 	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
 	if (mctrl & TIOCM_LOOP)
@@ -346,7 +385,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
  */
 static u_int atmel_get_mctrl(struct uart_port *port)
 {
-	unsigned int status, ret = 0;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int ret = 0, status;
 
 	status = UART_GET_CSR(port);
 
@@ -362,7 +402,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
 	if (!(status & ATMEL_US_RI))
 		ret |= TIOCM_RI;
 
-	return ret;
+	return mctrl_gpio_get(atmel_port->gpios, &ret);
 }
 
 /*
@@ -1042,7 +1082,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 	unsigned int status, pending, pass_counter = 0;
 
 	do {
-		status = UART_GET_CSR(port);
+		status = atmel_get_lines_status(port);
 		pending = status & UART_GET_IMR(port);
 		if (!pending)
 			break;
@@ -1568,7 +1608,7 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	/* Save current CSR for comparison in atmel_tasklet_func() */
-	atmel_port->irq_status_prev = UART_GET_CSR(port);
+	atmel_port->irq_status_prev = atmel_get_lines_status(port);
 	atmel_port->irq_status = atmel_port->irq_status_prev;
 
 	/*
@@ -2324,6 +2364,15 @@ static int atmel_serial_resume(struct platform_device *pdev)
 #define atmel_serial_resume NULL
 #endif
 
+static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
+{
+	p->gpios = mctrl_gpio_init(dev, 0);
+	if (IS_ERR_OR_NULL(p->gpios))
+		return -1;
+
+	return 0;
+}
+
 static int atmel_serial_probe(struct platform_device *pdev)
 {
 	struct atmel_uart_port *port;
@@ -2359,25 +2408,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
 	port = &atmel_ports[ret];
 	port->backup_imr = 0;
 	port->uart.line = ret;
-	port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
-	if (pdata)
-		port->rts_gpio = pdata->rts_gpio;
-	else if (np)
-		port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
-
-	if (gpio_is_valid(port->rts_gpio)) {
-		ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
-		if (ret) {
-			dev_err(&pdev->dev, "error requesting RTS GPIO\n");
-			goto err;
-		}
-		/* Default to 1 as RTS is active low */
-		ret = gpio_direction_output(port->rts_gpio, 1);
-		if (ret) {
-			dev_err(&pdev->dev, "error setting up RTS GPIO\n");
-			goto err;
-		}
-	}
+
+	ret = atmel_init_gpios(port, &pdev->dev);
+	if (ret < 0)
+		dev_err(&pdev->dev, "%s",
+			"Failed to initialize GPIOs. The serial port may not work as expected");
 
 	ret = atmel_init_port(port, pdev);
 	if (ret)
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
index e26b0c14edea..cea9f70133c5 100644
--- a/include/linux/platform_data/atmel.h
+++ b/include/linux/platform_data/atmel.h
@@ -84,7 +84,6 @@ struct atmel_uart_data {
 	short			use_dma_rx;	/* use receive DMA? */
 	void __iomem		*regs;		/* virt. base address, if any */
 	struct serial_rs485	rs485;		/* rs485 settings */
-	int			rts_gpio;	/* optional RTS GPIO */
 };
 
  /* Touchscreen Controller */
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 3/3] tty/serial: at91: add interrupts for modem control lines
  2014-03-10 16:45 ` Richard Genoud
@ 2014-03-10 16:45   ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Nicolas Ferre, Linus Walleij,
	Alexander Shiyan, linux-serial, linux-arm-kernel, Richard Genoud

Handle CTS/DSR/RI/DCD GPIO interrupts in atmel_serial.

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
 drivers/tty/serial/atmel_serial.c | 125 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 43ca659c1d4b..3fceae099c44 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -45,6 +45,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -167,7 +168,9 @@ struct atmel_uart_port {
 
 	struct serial_rs485	rs485;		/* rs485 settings */
 	struct mctrl_gpios	*gpios;
+	int			gpio_irq[UART_GPIO_MAX];
 	unsigned int		tx_done_mask;
+	bool			ms_irq_enabled;
 	bool			is_usart;	/* usart or uart */
 	struct timer_list	uart_timer;	/* uart timer */
 	int (*prepare_rx)(struct uart_port *port);
@@ -489,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
  */
 static void atmel_enable_ms(struct uart_port *port)
 {
-	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
-			| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	uint32_t ier = 0;
+
+	/*
+	 * Interrupt should not be enabled twice
+	 */
+	if (atmel_port->ms_irq_enabled)
+		return;
+
+	atmel_port->ms_irq_enabled = true;
+
+	if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
+	else
+		ier |= ATMEL_US_CTSIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
+	else
+		ier |= ATMEL_US_DSRIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
+	else
+		ier |= ATMEL_US_RIIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
+	else
+		ier |= ATMEL_US_DCDIC;
+
+	UART_PUT_IER(port, ier);
 }
 
 /*
@@ -1079,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
 static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	unsigned int status, pending, pass_counter = 0;
+	bool gpio_handled = false;
 
 	do {
 		status = atmel_get_lines_status(port);
 		pending = status & UART_GET_IMR(port);
+		if (!gpio_handled) {
+			/*
+			 * Dealing with GPIO interrupt
+			 */
+			if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
+				pending |= ATMEL_US_CTSIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
+				pending |= ATMEL_US_DSRIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
+				pending |= ATMEL_US_RIIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
+				pending |= ATMEL_US_DCDIC;
+
+			gpio_handled = true;
+		}
 		if (!pending)
 			break;
 
@@ -1563,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
 	}
 }
 
+static void atmel_free_gpio_irq(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	enum mctrl_gpio_idx i;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (atmel_port->gpio_irq[i] >= 0)
+			free_irq(atmel_port->gpio_irq[i], port);
+}
+
+static int atmel_request_gpio_irq(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int *irq = atmel_port->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], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
+				  "atmel_serial", port);
+		if (err)
+			dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
+				irq[i]);
+	}
+
+	/*
+	 * If something went wrong, rollback.
+	 */
+	while (err && (--i >= 0))
+		if (irq[i] >= 0)
+			free_irq(irq[i], port);
+
+	return err;
+}
+
 /*
  * Perform initialization and enable port for reception
  */
@@ -1579,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
 	 * handle an unexpected interrupt
 	 */
 	UART_PUT_IDR(port, -1);
+	atmel_port->ms_irq_enabled = false;
 
 	/*
 	 * Allocate the IRQ
@@ -1591,6 +1684,13 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	/*
+	 * Get the GPIO lines IRQ
+	 */
+	retval = atmel_request_gpio_irq(port);
+	if (retval)
+		goto free_irq;
+
+	/*
 	 * Initialize DMA (if necessary)
 	 */
 	atmel_init_property(atmel_port, pdev);
@@ -1654,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	return 0;
+
+free_irq:
+	free_irq(port->irq, port);
+
+	return retval;
 }
 
 /*
@@ -1701,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
 	atmel_port->rx_ring.tail = 0;
 
 	/*
-	 * Free the interrupt
+	 * Free the interrupts
 	 */
 	free_irq(port->irq, port);
+	atmel_free_gpio_irq(port);
+
+	atmel_port->ms_irq_enabled = false;
 }
 
 /*
@@ -2366,10 +2474,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
 
 static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
 {
+	enum mctrl_gpio_idx i;
+	struct gpio_desc *gpiod;
+
 	p->gpios = mctrl_gpio_init(dev, 0);
 	if (IS_ERR_OR_NULL(p->gpios))
 		return -1;
 
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
+		if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
+			p->gpio_irq[i] = gpiod_to_irq(gpiod);
+		else
+			p->gpio_irq[i] = -EINVAL;
+	}
+
 	return 0;
 }
 
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 3/3] tty/serial: at91: add interrupts for modem control lines
@ 2014-03-10 16:45   ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-10 16:45 UTC (permalink / raw)
  To: linux-arm-kernel

Handle CTS/DSR/RI/DCD GPIO interrupts in atmel_serial.

Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
---
 drivers/tty/serial/atmel_serial.c | 125 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 43ca659c1d4b..3fceae099c44 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -45,6 +45,7 @@
 #include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -167,7 +168,9 @@ struct atmel_uart_port {
 
 	struct serial_rs485	rs485;		/* rs485 settings */
 	struct mctrl_gpios	*gpios;
+	int			gpio_irq[UART_GPIO_MAX];
 	unsigned int		tx_done_mask;
+	bool			ms_irq_enabled;
 	bool			is_usart;	/* usart or uart */
 	struct timer_list	uart_timer;	/* uart timer */
 	int (*prepare_rx)(struct uart_port *port);
@@ -489,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
  */
 static void atmel_enable_ms(struct uart_port *port)
 {
-	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
-			| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	uint32_t ier = 0;
+
+	/*
+	 * Interrupt should not be enabled twice
+	 */
+	if (atmel_port->ms_irq_enabled)
+		return;
+
+	atmel_port->ms_irq_enabled = true;
+
+	if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
+	else
+		ier |= ATMEL_US_CTSIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
+	else
+		ier |= ATMEL_US_DSRIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
+	else
+		ier |= ATMEL_US_RIIC;
+
+	if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
+		enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
+	else
+		ier |= ATMEL_US_DCDIC;
+
+	UART_PUT_IER(port, ier);
 }
 
 /*
@@ -1079,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
 static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 {
 	struct uart_port *port = dev_id;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	unsigned int status, pending, pass_counter = 0;
+	bool gpio_handled = false;
 
 	do {
 		status = atmel_get_lines_status(port);
 		pending = status & UART_GET_IMR(port);
+		if (!gpio_handled) {
+			/*
+			 * Dealing with GPIO interrupt
+			 */
+			if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
+				pending |= ATMEL_US_CTSIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
+				pending |= ATMEL_US_DSRIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
+				pending |= ATMEL_US_RIIC;
+
+			if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
+				pending |= ATMEL_US_DCDIC;
+
+			gpio_handled = true;
+		}
 		if (!pending)
 			break;
 
@@ -1563,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
 	}
 }
 
+static void atmel_free_gpio_irq(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	enum mctrl_gpio_idx i;
+
+	for (i = 0; i < UART_GPIO_MAX; i++)
+		if (atmel_port->gpio_irq[i] >= 0)
+			free_irq(atmel_port->gpio_irq[i], port);
+}
+
+static int atmel_request_gpio_irq(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int *irq = atmel_port->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], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
+				  "atmel_serial", port);
+		if (err)
+			dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
+				irq[i]);
+	}
+
+	/*
+	 * If something went wrong, rollback.
+	 */
+	while (err && (--i >= 0))
+		if (irq[i] >= 0)
+			free_irq(irq[i], port);
+
+	return err;
+}
+
 /*
  * Perform initialization and enable port for reception
  */
@@ -1579,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
 	 * handle an unexpected interrupt
 	 */
 	UART_PUT_IDR(port, -1);
+	atmel_port->ms_irq_enabled = false;
 
 	/*
 	 * Allocate the IRQ
@@ -1591,6 +1684,13 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	/*
+	 * Get the GPIO lines IRQ
+	 */
+	retval = atmel_request_gpio_irq(port);
+	if (retval)
+		goto free_irq;
+
+	/*
 	 * Initialize DMA (if necessary)
 	 */
 	atmel_init_property(atmel_port, pdev);
@@ -1654,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
 	}
 
 	return 0;
+
+free_irq:
+	free_irq(port->irq, port);
+
+	return retval;
 }
 
 /*
@@ -1701,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
 	atmel_port->rx_ring.tail = 0;
 
 	/*
-	 * Free the interrupt
+	 * Free the interrupts
 	 */
 	free_irq(port->irq, port);
+	atmel_free_gpio_irq(port);
+
+	atmel_port->ms_irq_enabled = false;
 }
 
 /*
@@ -2366,10 +2474,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
 
 static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
 {
+	enum mctrl_gpio_idx i;
+	struct gpio_desc *gpiod;
+
 	p->gpios = mctrl_gpio_init(dev, 0);
 	if (IS_ERR_OR_NULL(p->gpios))
 		return -1;
 
+	for (i = 0; i < UART_GPIO_MAX; i++) {
+		gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
+		if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
+			p->gpio_irq[i] = gpiod_to_irq(gpiod);
+		else
+			p->gpio_irq[i] = -EINVAL;
+	}
+
 	return 0;
 }
 
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 2/3] tty/serial: at91: use mctrl_gpio helpers
  2014-03-10 16:45   ` Richard Genoud
@ 2014-03-10 17:20     ` Nicolas Ferre
  -1 siblings, 0 replies; 30+ messages in thread
From: Nicolas Ferre @ 2014-03-10 17:20 UTC (permalink / raw)
  To: Richard Genoud, Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Linus Walleij, Alexander Shiyan,
	linux-serial, linux-arm-kernel, Richard Genoud

On 10/03/2014 17:45, Richard Genoud :
> On sam9x5, dedicated CTS (and RTS) pins are unusable together with the
> LCDC, the EMAC, or the MMC because they share the same line.
> 
> Moreover, the USART 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: Richard Genoud <richard.genoud@gmail.com>

Good for me: Greg are you okay to take the at91 bits included in this patch?

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>


> ---
>  .../devicetree/bindings/serial/atmel-usart.txt     |  12 ++-
>  arch/arm/mach-at91/at91rm9200_devices.c            |  16 ++--
>  arch/arm/mach-at91/at91sam9260_devices.c           |   7 --
>  arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
>  arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
>  arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
>  arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
>  drivers/tty/serial/Kconfig                         |   1 +
>  drivers/tty/serial/atmel_serial.c                  | 105 ++++++++++++++-------
>  include/linux/platform_data/atmel.h                |   1 -
>  10 files changed, 90 insertions(+), 70 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt
> index 17c1042b2df8..a6391e70a8fd 100644
> --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt
> +++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt
> @@ -13,8 +13,9 @@ Required properties:
>  Optional properties:
>  - atmel,use-dma-rx: use of PDC or DMA for receiving data
>  - atmel,use-dma-tx: use of PDC or DMA for transmitting data
> -- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
> -  function pin for the USART RTS feature. If unsure, don't specify this property.
> +- {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.
>  - add dma bindings for dma transfer:
>  	- dmas: DMA specifier, consisting of a phandle to DMA controller node,
>  		memory peripheral interface and USART DMA channel ID, FIFO configuration.
> @@ -35,7 +36,12 @@ Example:
>  		clock-names = "usart";
>  		atmel,use-dma-rx;
>  		atmel,use-dma-tx;
> -		rts-gpios = <&pioD 15 0>;
> +		rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
> +		cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
> +		dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
> +		dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
> +		dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
> +		rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
>  	};
>  
>  - use DMA:
> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
> index f3f19f21352a..291a90a5b1d4 100644
> --- a/arch/arm/mach-at91/at91rm9200_devices.c
> +++ b/arch/arm/mach-at91/at91rm9200_devices.c
> @@ -15,6 +15,7 @@
>  
>  #include <linux/dma-mapping.h>
>  #include <linux/gpio.h>
> +#include <linux/gpio/driver.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c-gpio.h>
>  
> @@ -923,7 +924,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -962,7 +962,14 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
> +};
> +
> +static struct gpiod_lookup_table uart0_gpios_table = {
> +	.dev_id = "atmel_usart",
> +	.table = {
> +		GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
> +		{ },
> +	},
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -993,7 +1000,7 @@ static inline void configure_usart0_pins(unsigned pins)
>  		 * We need to drive the pin manually. The serial driver will driver
>  		 * this to high when initializing.
>  		 */
> -		uart0_data.rts_gpio = AT91_PIN_PA21;
> +		gpiod_add_lookup_table(&uart0_gpios_table);
>  	}
>  }
>  
> @@ -1013,7 +1020,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1065,7 +1071,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1109,7 +1114,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
> index 2ae7715f1309..a1b989eac8b8 100644
> --- a/arch/arm/mach-at91/at91sam9260_devices.c
> +++ b/arch/arm/mach-at91/at91sam9260_devices.c
> @@ -820,7 +820,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -859,7 +858,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -911,7 +909,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -955,7 +952,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -999,7 +995,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> @@ -1043,7 +1038,6 @@ static struct resource uart4_resources[] = {
>  static struct atmel_uart_data uart4_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart4_dmamask = DMA_BIT_MASK(32);
> @@ -1082,7 +1076,6 @@ static struct resource uart5_resources[] = {
>  static struct atmel_uart_data uart5_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart5_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 80e35895d28f..b5f7a7226ff8 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
> index 43d53d6156dd..39803c3296b2 100644
> --- a/arch/arm/mach-at91/at91sam9263_devices.c
> +++ b/arch/arm/mach-at91/at91sam9263_devices.c
> @@ -1325,7 +1325,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -1364,7 +1363,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1408,7 +1406,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1452,7 +1449,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index 77b04c2edd78..4e53d8d9737b 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -1588,7 +1588,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -1627,7 +1626,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1671,7 +1669,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1715,7 +1712,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1759,7 +1755,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
> index 428fc412aaf1..f75985062913 100644
> --- a/arch/arm/mach-at91/at91sam9rl_devices.c
> +++ b/arch/arm/mach-at91/at91sam9rl_devices.c
> @@ -957,7 +957,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -996,7 +995,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1048,7 +1046,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1092,7 +1089,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1136,7 +1132,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 7e8f15cfb8d0..f4e20410a138 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -97,6 +97,7 @@ config SERIAL_ATMEL
>  	bool "AT91 / AT32 on-chip serial port support"
>  	depends on ARCH_AT91 || AVR32
>  	select SERIAL_CORE
> +	select SERIAL_MCTRL_GPIO
>  	help
>  	  This enables the driver for the on-chip UARTs of the Atmel
>  	  AT91 and AT32 processors.
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 53eeea13ff16..43ca659c1d4b 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -43,6 +43,8 @@
>  #include <linux/platform_data/atmel.h>
>  #include <linux/timer.h>
>  #include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/err.h>
>  
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
> @@ -57,6 +59,8 @@
>  
>  #include <linux/serial_core.h>
>  
> +#include "serial_mctrl_gpio.h"
> +
>  static void atmel_start_rx(struct uart_port *port);
>  static void atmel_stop_rx(struct uart_port *port);
>  
> @@ -162,7 +166,7 @@ struct atmel_uart_port {
>  	struct circ_buf		rx_ring;
>  
>  	struct serial_rs485	rs485;		/* rs485 settings */
> -	int			rts_gpio;	/* optional RTS GPIO */
> +	struct mctrl_gpios	*gpios;
>  	unsigned int		tx_done_mask;
>  	bool			is_usart;	/* usart or uart */
>  	struct timer_list	uart_timer;	/* uart timer */
> @@ -237,6 +241,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
>  	return atmel_port->use_dma_rx;
>  }
>  
> +static unsigned int atmel_get_lines_status(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int status, ret = 0;
> +
> +	status = UART_GET_CSR(port);
> +
> +	mctrl_gpio_get(atmel_port->gpios, &ret);
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_CTS))) {
> +		if (ret & TIOCM_CTS)
> +			status &= ~ATMEL_US_CTS;
> +		else
> +			status |= ATMEL_US_CTS;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_DSR))) {
> +		if (ret & TIOCM_DSR)
> +			status &= ~ATMEL_US_DSR;
> +		else
> +			status |= ATMEL_US_DSR;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_RI))) {
> +		if (ret & TIOCM_RI)
> +			status &= ~ATMEL_US_RI;
> +		else
> +			status |= ATMEL_US_RI;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_DCD))) {
> +		if (ret & TIOCM_CD)
> +			status &= ~ATMEL_US_DCD;
> +		else
> +			status |= ATMEL_US_DCD;
> +	}
> +
> +	return status;
> +}
> +
>  /* Enable or disable the rs485 support */
>  void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
>  {
> @@ -296,17 +344,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>  	unsigned int mode;
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	/*
> -	 * AT91RM9200 Errata #39: RTS0 is not internally connected
> -	 * to PA21. We need to drive the pin as a GPIO.
> -	 */
> -	if (gpio_is_valid(atmel_port->rts_gpio)) {
> -		if (mctrl & TIOCM_RTS)
> -			gpio_set_value(atmel_port->rts_gpio, 0);
> -		else
> -			gpio_set_value(atmel_port->rts_gpio, 1);
> -	}
> -
>  	if (mctrl & TIOCM_RTS)
>  		control |= ATMEL_US_RTSEN;
>  	else
> @@ -319,6 +356,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>  
>  	UART_PUT_CR(port, control);
>  
> +	mctrl_gpio_set(atmel_port->gpios, mctrl);
> +
>  	/* Local loopback mode? */
>  	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
>  	if (mctrl & TIOCM_LOOP)
> @@ -346,7 +385,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>   */
>  static u_int atmel_get_mctrl(struct uart_port *port)
>  {
> -	unsigned int status, ret = 0;
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int ret = 0, status;
>  
>  	status = UART_GET_CSR(port);
>  
> @@ -362,7 +402,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
>  	if (!(status & ATMEL_US_RI))
>  		ret |= TIOCM_RI;
>  
> -	return ret;
> +	return mctrl_gpio_get(atmel_port->gpios, &ret);
>  }
>  
>  /*
> @@ -1042,7 +1082,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
>  	unsigned int status, pending, pass_counter = 0;
>  
>  	do {
> -		status = UART_GET_CSR(port);
> +		status = atmel_get_lines_status(port);
>  		pending = status & UART_GET_IMR(port);
>  		if (!pending)
>  			break;
> @@ -1568,7 +1608,7 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	/* Save current CSR for comparison in atmel_tasklet_func() */
> -	atmel_port->irq_status_prev = UART_GET_CSR(port);
> +	atmel_port->irq_status_prev = atmel_get_lines_status(port);
>  	atmel_port->irq_status = atmel_port->irq_status_prev;
>  
>  	/*
> @@ -2324,6 +2364,15 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  #define atmel_serial_resume NULL
>  #endif
>  
> +static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
> +{
> +	p->gpios = mctrl_gpio_init(dev, 0);
> +	if (IS_ERR_OR_NULL(p->gpios))
> +		return -1;
> +
> +	return 0;
> +}
> +
>  static int atmel_serial_probe(struct platform_device *pdev)
>  {
>  	struct atmel_uart_port *port;
> @@ -2359,25 +2408,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
>  	port = &atmel_ports[ret];
>  	port->backup_imr = 0;
>  	port->uart.line = ret;
> -	port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
> -	if (pdata)
> -		port->rts_gpio = pdata->rts_gpio;
> -	else if (np)
> -		port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
> -
> -	if (gpio_is_valid(port->rts_gpio)) {
> -		ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
> -		if (ret) {
> -			dev_err(&pdev->dev, "error requesting RTS GPIO\n");
> -			goto err;
> -		}
> -		/* Default to 1 as RTS is active low */
> -		ret = gpio_direction_output(port->rts_gpio, 1);
> -		if (ret) {
> -			dev_err(&pdev->dev, "error setting up RTS GPIO\n");
> -			goto err;
> -		}
> -	}
> +
> +	ret = atmel_init_gpios(port, &pdev->dev);
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "%s",
> +			"Failed to initialize GPIOs. The serial port may not work as expected");
>  
>  	ret = atmel_init_port(port, pdev);
>  	if (ret)
> diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
> index e26b0c14edea..cea9f70133c5 100644
> --- a/include/linux/platform_data/atmel.h
> +++ b/include/linux/platform_data/atmel.h
> @@ -84,7 +84,6 @@ struct atmel_uart_data {
>  	short			use_dma_rx;	/* use receive DMA? */
>  	void __iomem		*regs;		/* virt. base address, if any */
>  	struct serial_rs485	rs485;		/* rs485 settings */
> -	int			rts_gpio;	/* optional RTS GPIO */
>  };
>  
>   /* Touchscreen Controller */
> 


-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 2/3] tty/serial: at91: use mctrl_gpio helpers
@ 2014-03-10 17:20     ` Nicolas Ferre
  0 siblings, 0 replies; 30+ messages in thread
From: Nicolas Ferre @ 2014-03-10 17:20 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/03/2014 17:45, Richard Genoud :
> On sam9x5, dedicated CTS (and RTS) pins are unusable together with the
> LCDC, the EMAC, or the MMC because they share the same line.
> 
> Moreover, the USART 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: Richard Genoud <richard.genoud@gmail.com>

Good for me: Greg are you okay to take the at91 bits included in this patch?

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>


> ---
>  .../devicetree/bindings/serial/atmel-usart.txt     |  12 ++-
>  arch/arm/mach-at91/at91rm9200_devices.c            |  16 ++--
>  arch/arm/mach-at91/at91sam9260_devices.c           |   7 --
>  arch/arm/mach-at91/at91sam9261_devices.c           |   4 -
>  arch/arm/mach-at91/at91sam9263_devices.c           |   4 -
>  arch/arm/mach-at91/at91sam9g45_devices.c           |   5 -
>  arch/arm/mach-at91/at91sam9rl_devices.c            |   5 -
>  drivers/tty/serial/Kconfig                         |   1 +
>  drivers/tty/serial/atmel_serial.c                  | 105 ++++++++++++++-------
>  include/linux/platform_data/atmel.h                |   1 -
>  10 files changed, 90 insertions(+), 70 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/serial/atmel-usart.txt b/Documentation/devicetree/bindings/serial/atmel-usart.txt
> index 17c1042b2df8..a6391e70a8fd 100644
> --- a/Documentation/devicetree/bindings/serial/atmel-usart.txt
> +++ b/Documentation/devicetree/bindings/serial/atmel-usart.txt
> @@ -13,8 +13,9 @@ Required properties:
>  Optional properties:
>  - atmel,use-dma-rx: use of PDC or DMA for receiving data
>  - atmel,use-dma-tx: use of PDC or DMA for transmitting data
> -- rts-gpios: specify a GPIO for RTS line. It will use specified PIO instead of the peripheral
> -  function pin for the USART RTS feature. If unsure, don't specify this property.
> +- {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.
>  - add dma bindings for dma transfer:
>  	- dmas: DMA specifier, consisting of a phandle to DMA controller node,
>  		memory peripheral interface and USART DMA channel ID, FIFO configuration.
> @@ -35,7 +36,12 @@ Example:
>  		clock-names = "usart";
>  		atmel,use-dma-rx;
>  		atmel,use-dma-tx;
> -		rts-gpios = <&pioD 15 0>;
> +		rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
> +		cts-gpios = <&pioD 16 GPIO_ACTIVE_LOW>;
> +		dtr-gpios = <&pioD 17 GPIO_ACTIVE_LOW>;
> +		dsr-gpios = <&pioD 18 GPIO_ACTIVE_LOW>;
> +		dcd-gpios = <&pioD 20 GPIO_ACTIVE_LOW>;
> +		rng-gpios = <&pioD 19 GPIO_ACTIVE_LOW>;
>  	};
>  
>  - use DMA:
> diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
> index f3f19f21352a..291a90a5b1d4 100644
> --- a/arch/arm/mach-at91/at91rm9200_devices.c
> +++ b/arch/arm/mach-at91/at91rm9200_devices.c
> @@ -15,6 +15,7 @@
>  
>  #include <linux/dma-mapping.h>
>  #include <linux/gpio.h>
> +#include <linux/gpio/driver.h>
>  #include <linux/platform_device.h>
>  #include <linux/i2c-gpio.h>
>  
> @@ -923,7 +924,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -962,7 +962,14 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
> +};
> +
> +static struct gpiod_lookup_table uart0_gpios_table = {
> +	.dev_id = "atmel_usart",
> +	.table = {
> +		GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
> +		{ },
> +	},
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -993,7 +1000,7 @@ static inline void configure_usart0_pins(unsigned pins)
>  		 * We need to drive the pin manually. The serial driver will driver
>  		 * this to high when initializing.
>  		 */
> -		uart0_data.rts_gpio = AT91_PIN_PA21;
> +		gpiod_add_lookup_table(&uart0_gpios_table);
>  	}
>  }
>  
> @@ -1013,7 +1020,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1065,7 +1071,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1109,7 +1114,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
> index 2ae7715f1309..a1b989eac8b8 100644
> --- a/arch/arm/mach-at91/at91sam9260_devices.c
> +++ b/arch/arm/mach-at91/at91sam9260_devices.c
> @@ -820,7 +820,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -859,7 +858,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -911,7 +909,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -955,7 +952,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -999,7 +995,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> @@ -1043,7 +1038,6 @@ static struct resource uart4_resources[] = {
>  static struct atmel_uart_data uart4_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart4_dmamask = DMA_BIT_MASK(32);
> @@ -1082,7 +1076,6 @@ static struct resource uart5_resources[] = {
>  static struct atmel_uart_data uart5_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart5_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
> index 80e35895d28f..b5f7a7226ff8 100644
> --- a/arch/arm/mach-at91/at91sam9261_devices.c
> +++ b/arch/arm/mach-at91/at91sam9261_devices.c
> @@ -881,7 +881,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -920,7 +919,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -964,7 +962,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1008,7 +1005,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
> index 43d53d6156dd..39803c3296b2 100644
> --- a/arch/arm/mach-at91/at91sam9263_devices.c
> +++ b/arch/arm/mach-at91/at91sam9263_devices.c
> @@ -1325,7 +1325,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -1364,7 +1363,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1408,7 +1406,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1452,7 +1449,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
> index 77b04c2edd78..4e53d8d9737b 100644
> --- a/arch/arm/mach-at91/at91sam9g45_devices.c
> +++ b/arch/arm/mach-at91/at91sam9g45_devices.c
> @@ -1588,7 +1588,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -1627,7 +1626,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1671,7 +1669,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1715,7 +1712,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1759,7 +1755,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
> index 428fc412aaf1..f75985062913 100644
> --- a/arch/arm/mach-at91/at91sam9rl_devices.c
> +++ b/arch/arm/mach-at91/at91sam9rl_devices.c
> @@ -957,7 +957,6 @@ static struct resource dbgu_resources[] = {
>  static struct atmel_uart_data dbgu_data = {
>  	.use_dma_tx	= 0,
>  	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 dbgu_dmamask = DMA_BIT_MASK(32);
> @@ -996,7 +995,6 @@ static struct resource uart0_resources[] = {
>  static struct atmel_uart_data uart0_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart0_dmamask = DMA_BIT_MASK(32);
> @@ -1048,7 +1046,6 @@ static struct resource uart1_resources[] = {
>  static struct atmel_uart_data uart1_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart1_dmamask = DMA_BIT_MASK(32);
> @@ -1092,7 +1089,6 @@ static struct resource uart2_resources[] = {
>  static struct atmel_uart_data uart2_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart2_dmamask = DMA_BIT_MASK(32);
> @@ -1136,7 +1132,6 @@ static struct resource uart3_resources[] = {
>  static struct atmel_uart_data uart3_data = {
>  	.use_dma_tx	= 1,
>  	.use_dma_rx	= 1,
> -	.rts_gpio	= -EINVAL,
>  };
>  
>  static u64 uart3_dmamask = DMA_BIT_MASK(32);
> diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
> index 7e8f15cfb8d0..f4e20410a138 100644
> --- a/drivers/tty/serial/Kconfig
> +++ b/drivers/tty/serial/Kconfig
> @@ -97,6 +97,7 @@ config SERIAL_ATMEL
>  	bool "AT91 / AT32 on-chip serial port support"
>  	depends on ARCH_AT91 || AVR32
>  	select SERIAL_CORE
> +	select SERIAL_MCTRL_GPIO
>  	help
>  	  This enables the driver for the on-chip UARTs of the Atmel
>  	  AT91 and AT32 processors.
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 53eeea13ff16..43ca659c1d4b 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -43,6 +43,8 @@
>  #include <linux/platform_data/atmel.h>
>  #include <linux/timer.h>
>  #include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/err.h>
>  
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
> @@ -57,6 +59,8 @@
>  
>  #include <linux/serial_core.h>
>  
> +#include "serial_mctrl_gpio.h"
> +
>  static void atmel_start_rx(struct uart_port *port);
>  static void atmel_stop_rx(struct uart_port *port);
>  
> @@ -162,7 +166,7 @@ struct atmel_uart_port {
>  	struct circ_buf		rx_ring;
>  
>  	struct serial_rs485	rs485;		/* rs485 settings */
> -	int			rts_gpio;	/* optional RTS GPIO */
> +	struct mctrl_gpios	*gpios;
>  	unsigned int		tx_done_mask;
>  	bool			is_usart;	/* usart or uart */
>  	struct timer_list	uart_timer;	/* uart timer */
> @@ -237,6 +241,50 @@ static bool atmel_use_dma_rx(struct uart_port *port)
>  	return atmel_port->use_dma_rx;
>  }
>  
> +static unsigned int atmel_get_lines_status(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int status, ret = 0;
> +
> +	status = UART_GET_CSR(port);
> +
> +	mctrl_gpio_get(atmel_port->gpios, &ret);
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_CTS))) {
> +		if (ret & TIOCM_CTS)
> +			status &= ~ATMEL_US_CTS;
> +		else
> +			status |= ATMEL_US_CTS;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_DSR))) {
> +		if (ret & TIOCM_DSR)
> +			status &= ~ATMEL_US_DSR;
> +		else
> +			status |= ATMEL_US_DSR;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_RI))) {
> +		if (ret & TIOCM_RI)
> +			status &= ~ATMEL_US_RI;
> +		else
> +			status |= ATMEL_US_RI;
> +	}
> +
> +	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
> +						UART_GPIO_DCD))) {
> +		if (ret & TIOCM_CD)
> +			status &= ~ATMEL_US_DCD;
> +		else
> +			status |= ATMEL_US_DCD;
> +	}
> +
> +	return status;
> +}
> +
>  /* Enable or disable the rs485 support */
>  void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
>  {
> @@ -296,17 +344,6 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>  	unsigned int mode;
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	/*
> -	 * AT91RM9200 Errata #39: RTS0 is not internally connected
> -	 * to PA21. We need to drive the pin as a GPIO.
> -	 */
> -	if (gpio_is_valid(atmel_port->rts_gpio)) {
> -		if (mctrl & TIOCM_RTS)
> -			gpio_set_value(atmel_port->rts_gpio, 0);
> -		else
> -			gpio_set_value(atmel_port->rts_gpio, 1);
> -	}
> -
>  	if (mctrl & TIOCM_RTS)
>  		control |= ATMEL_US_RTSEN;
>  	else
> @@ -319,6 +356,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>  
>  	UART_PUT_CR(port, control);
>  
> +	mctrl_gpio_set(atmel_port->gpios, mctrl);
> +
>  	/* Local loopback mode? */
>  	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
>  	if (mctrl & TIOCM_LOOP)
> @@ -346,7 +385,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
>   */
>  static u_int atmel_get_mctrl(struct uart_port *port)
>  {
> -	unsigned int status, ret = 0;
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int ret = 0, status;
>  
>  	status = UART_GET_CSR(port);
>  
> @@ -362,7 +402,7 @@ static u_int atmel_get_mctrl(struct uart_port *port)
>  	if (!(status & ATMEL_US_RI))
>  		ret |= TIOCM_RI;
>  
> -	return ret;
> +	return mctrl_gpio_get(atmel_port->gpios, &ret);
>  }
>  
>  /*
> @@ -1042,7 +1082,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
>  	unsigned int status, pending, pass_counter = 0;
>  
>  	do {
> -		status = UART_GET_CSR(port);
> +		status = atmel_get_lines_status(port);
>  		pending = status & UART_GET_IMR(port);
>  		if (!pending)
>  			break;
> @@ -1568,7 +1608,7 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	/* Save current CSR for comparison in atmel_tasklet_func() */
> -	atmel_port->irq_status_prev = UART_GET_CSR(port);
> +	atmel_port->irq_status_prev = atmel_get_lines_status(port);
>  	atmel_port->irq_status = atmel_port->irq_status_prev;
>  
>  	/*
> @@ -2324,6 +2364,15 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  #define atmel_serial_resume NULL
>  #endif
>  
> +static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
> +{
> +	p->gpios = mctrl_gpio_init(dev, 0);
> +	if (IS_ERR_OR_NULL(p->gpios))
> +		return -1;
> +
> +	return 0;
> +}
> +
>  static int atmel_serial_probe(struct platform_device *pdev)
>  {
>  	struct atmel_uart_port *port;
> @@ -2359,25 +2408,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
>  	port = &atmel_ports[ret];
>  	port->backup_imr = 0;
>  	port->uart.line = ret;
> -	port->rts_gpio = -EINVAL; /* Invalid, zero could be valid */
> -	if (pdata)
> -		port->rts_gpio = pdata->rts_gpio;
> -	else if (np)
> -		port->rts_gpio = of_get_named_gpio(np, "rts-gpios", 0);
> -
> -	if (gpio_is_valid(port->rts_gpio)) {
> -		ret = devm_gpio_request(&pdev->dev, port->rts_gpio, "RTS");
> -		if (ret) {
> -			dev_err(&pdev->dev, "error requesting RTS GPIO\n");
> -			goto err;
> -		}
> -		/* Default to 1 as RTS is active low */
> -		ret = gpio_direction_output(port->rts_gpio, 1);
> -		if (ret) {
> -			dev_err(&pdev->dev, "error setting up RTS GPIO\n");
> -			goto err;
> -		}
> -	}
> +
> +	ret = atmel_init_gpios(port, &pdev->dev);
> +	if (ret < 0)
> +		dev_err(&pdev->dev, "%s",
> +			"Failed to initialize GPIOs. The serial port may not work as expected");
>  
>  	ret = atmel_init_port(port, pdev);
>  	if (ret)
> diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
> index e26b0c14edea..cea9f70133c5 100644
> --- a/include/linux/platform_data/atmel.h
> +++ b/include/linux/platform_data/atmel.h
> @@ -84,7 +84,6 @@ struct atmel_uart_data {
>  	short			use_dma_rx;	/* use receive DMA? */
>  	void __iomem		*regs;		/* virt. base address, if any */
>  	struct serial_rs485	rs485;		/* rs485 settings */
> -	int			rts_gpio;	/* optional RTS GPIO */
>  };
>  
>   /* Touchscreen Controller */
> 


-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 3/3] tty/serial: at91: add interrupts for modem control lines
  2014-03-10 16:45   ` Richard Genoud
@ 2014-03-10 17:21     ` Nicolas Ferre
  -1 siblings, 0 replies; 30+ messages in thread
From: Nicolas Ferre @ 2014-03-10 17:21 UTC (permalink / raw)
  To: Richard Genoud, Greg Kroah-Hartman
  Cc: Uwe Kleine-König, Linus Walleij, Alexander Shiyan,
	linux-serial, linux-arm-kernel, Richard Genoud

On 10/03/2014 17:45, Richard Genoud :
> Handle CTS/DSR/RI/DCD GPIO interrupts in atmel_serial.
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Thanks Richard.

> ---
>  drivers/tty/serial/atmel_serial.c | 125 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 122 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 43ca659c1d4b..3fceae099c44 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -45,6 +45,7 @@
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/err.h>
> +#include <linux/irq.h>
>  
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
> @@ -167,7 +168,9 @@ struct atmel_uart_port {
>  
>  	struct serial_rs485	rs485;		/* rs485 settings */
>  	struct mctrl_gpios	*gpios;
> +	int			gpio_irq[UART_GPIO_MAX];
>  	unsigned int		tx_done_mask;
> +	bool			ms_irq_enabled;
>  	bool			is_usart;	/* usart or uart */
>  	struct timer_list	uart_timer;	/* uart timer */
>  	int (*prepare_rx)(struct uart_port *port);
> @@ -489,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
>   */
>  static void atmel_enable_ms(struct uart_port *port)
>  {
> -	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
> -			| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	uint32_t ier = 0;
> +
> +	/*
> +	 * Interrupt should not be enabled twice
> +	 */
> +	if (atmel_port->ms_irq_enabled)
> +		return;
> +
> +	atmel_port->ms_irq_enabled = true;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
> +	else
> +		ier |= ATMEL_US_CTSIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
> +	else
> +		ier |= ATMEL_US_DSRIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
> +	else
> +		ier |= ATMEL_US_RIIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
> +	else
> +		ier |= ATMEL_US_DCDIC;
> +
> +	UART_PUT_IER(port, ier);
>  }
>  
>  /*
> @@ -1079,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
>  static irqreturn_t atmel_interrupt(int irq, void *dev_id)
>  {
>  	struct uart_port *port = dev_id;
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	unsigned int status, pending, pass_counter = 0;
> +	bool gpio_handled = false;
>  
>  	do {
>  		status = atmel_get_lines_status(port);
>  		pending = status & UART_GET_IMR(port);
> +		if (!gpio_handled) {
> +			/*
> +			 * Dealing with GPIO interrupt
> +			 */
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
> +				pending |= ATMEL_US_CTSIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
> +				pending |= ATMEL_US_DSRIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
> +				pending |= ATMEL_US_RIIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
> +				pending |= ATMEL_US_DCDIC;
> +
> +			gpio_handled = true;
> +		}
>  		if (!pending)
>  			break;
>  
> @@ -1563,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
>  	}
>  }
>  
> +static void atmel_free_gpio_irq(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	enum mctrl_gpio_idx i;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++)
> +		if (atmel_port->gpio_irq[i] >= 0)
> +			free_irq(atmel_port->gpio_irq[i], port);
> +}
> +
> +static int atmel_request_gpio_irq(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	int *irq = atmel_port->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], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
> +				  "atmel_serial", port);
> +		if (err)
> +			dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
> +				irq[i]);
> +	}
> +
> +	/*
> +	 * If something went wrong, rollback.
> +	 */
> +	while (err && (--i >= 0))
> +		if (irq[i] >= 0)
> +			free_irq(irq[i], port);
> +
> +	return err;
> +}
> +
>  /*
>   * Perform initialization and enable port for reception
>   */
> @@ -1579,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
>  	 * handle an unexpected interrupt
>  	 */
>  	UART_PUT_IDR(port, -1);
> +	atmel_port->ms_irq_enabled = false;
>  
>  	/*
>  	 * Allocate the IRQ
> @@ -1591,6 +1684,13 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	/*
> +	 * Get the GPIO lines IRQ
> +	 */
> +	retval = atmel_request_gpio_irq(port);
> +	if (retval)
> +		goto free_irq;
> +
> +	/*
>  	 * Initialize DMA (if necessary)
>  	 */
>  	atmel_init_property(atmel_port, pdev);
> @@ -1654,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	return 0;
> +
> +free_irq:
> +	free_irq(port->irq, port);
> +
> +	return retval;
>  }
>  
>  /*
> @@ -1701,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
>  	atmel_port->rx_ring.tail = 0;
>  
>  	/*
> -	 * Free the interrupt
> +	 * Free the interrupts
>  	 */
>  	free_irq(port->irq, port);
> +	atmel_free_gpio_irq(port);
> +
> +	atmel_port->ms_irq_enabled = false;
>  }
>  
>  /*
> @@ -2366,10 +2474,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  
>  static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
>  {
> +	enum mctrl_gpio_idx i;
> +	struct gpio_desc *gpiod;
> +
>  	p->gpios = mctrl_gpio_init(dev, 0);
>  	if (IS_ERR_OR_NULL(p->gpios))
>  		return -1;
>  
> +	for (i = 0; i < UART_GPIO_MAX; i++) {
> +		gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
> +		if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
> +			p->gpio_irq[i] = gpiod_to_irq(gpiod);
> +		else
> +			p->gpio_irq[i] = -EINVAL;
> +	}
> +
>  	return 0;
>  }
>  
> 


-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 3/3] tty/serial: at91: add interrupts for modem control lines
@ 2014-03-10 17:21     ` Nicolas Ferre
  0 siblings, 0 replies; 30+ messages in thread
From: Nicolas Ferre @ 2014-03-10 17:21 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/03/2014 17:45, Richard Genoud :
> Handle CTS/DSR/RI/DCD GPIO interrupts in atmel_serial.
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>

Thanks Richard.

> ---
>  drivers/tty/serial/atmel_serial.c | 125 +++++++++++++++++++++++++++++++++++++-
>  1 file changed, 122 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 43ca659c1d4b..3fceae099c44 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -45,6 +45,7 @@
>  #include <linux/gpio.h>
>  #include <linux/gpio/consumer.h>
>  #include <linux/err.h>
> +#include <linux/irq.h>
>  
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
> @@ -167,7 +168,9 @@ struct atmel_uart_port {
>  
>  	struct serial_rs485	rs485;		/* rs485 settings */
>  	struct mctrl_gpios	*gpios;
> +	int			gpio_irq[UART_GPIO_MAX];
>  	unsigned int		tx_done_mask;
> +	bool			ms_irq_enabled;
>  	bool			is_usart;	/* usart or uart */
>  	struct timer_list	uart_timer;	/* uart timer */
>  	int (*prepare_rx)(struct uart_port *port);
> @@ -489,8 +492,38 @@ static void atmel_stop_rx(struct uart_port *port)
>   */
>  static void atmel_enable_ms(struct uart_port *port)
>  {
> -	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC
> -			| ATMEL_US_DCDIC | ATMEL_US_CTSIC);
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	uint32_t ier = 0;
> +
> +	/*
> +	 * Interrupt should not be enabled twice
> +	 */
> +	if (atmel_port->ms_irq_enabled)
> +		return;
> +
> +	atmel_port->ms_irq_enabled = true;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_CTS] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_CTS]);
> +	else
> +		ier |= ATMEL_US_CTSIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_DSR] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DSR]);
> +	else
> +		ier |= ATMEL_US_DSRIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_RI] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_RI]);
> +	else
> +		ier |= ATMEL_US_RIIC;
> +
> +	if (atmel_port->gpio_irq[UART_GPIO_DCD] >= 0)
> +		enable_irq(atmel_port->gpio_irq[UART_GPIO_DCD]);
> +	else
> +		ier |= ATMEL_US_DCDIC;
> +
> +	UART_PUT_IER(port, ier);
>  }
>  
>  /*
> @@ -1079,11 +1112,31 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
>  static irqreturn_t atmel_interrupt(int irq, void *dev_id)
>  {
>  	struct uart_port *port = dev_id;
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	unsigned int status, pending, pass_counter = 0;
> +	bool gpio_handled = false;
>  
>  	do {
>  		status = atmel_get_lines_status(port);
>  		pending = status & UART_GET_IMR(port);
> +		if (!gpio_handled) {
> +			/*
> +			 * Dealing with GPIO interrupt
> +			 */
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_CTS])
> +				pending |= ATMEL_US_CTSIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_DSR])
> +				pending |= ATMEL_US_DSRIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_RI])
> +				pending |= ATMEL_US_RIIC;
> +
> +			if (irq == atmel_port->gpio_irq[UART_GPIO_DCD])
> +				pending |= ATMEL_US_DCDIC;
> +
> +			gpio_handled = true;
> +		}
>  		if (!pending)
>  			break;
>  
> @@ -1563,6 +1616,45 @@ static void atmel_get_ip_name(struct uart_port *port)
>  	}
>  }
>  
> +static void atmel_free_gpio_irq(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	enum mctrl_gpio_idx i;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++)
> +		if (atmel_port->gpio_irq[i] >= 0)
> +			free_irq(atmel_port->gpio_irq[i], port);
> +}
> +
> +static int atmel_request_gpio_irq(struct uart_port *port)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	int *irq = atmel_port->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], atmel_interrupt, IRQ_TYPE_EDGE_BOTH,
> +				  "atmel_serial", port);
> +		if (err)
> +			dev_err(port->dev, "atmel_startup - Can't get %d irq\n",
> +				irq[i]);
> +	}
> +
> +	/*
> +	 * If something went wrong, rollback.
> +	 */
> +	while (err && (--i >= 0))
> +		if (irq[i] >= 0)
> +			free_irq(irq[i], port);
> +
> +	return err;
> +}
> +
>  /*
>   * Perform initialization and enable port for reception
>   */
> @@ -1579,6 +1671,7 @@ static int atmel_startup(struct uart_port *port)
>  	 * handle an unexpected interrupt
>  	 */
>  	UART_PUT_IDR(port, -1);
> +	atmel_port->ms_irq_enabled = false;
>  
>  	/*
>  	 * Allocate the IRQ
> @@ -1591,6 +1684,13 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	/*
> +	 * Get the GPIO lines IRQ
> +	 */
> +	retval = atmel_request_gpio_irq(port);
> +	if (retval)
> +		goto free_irq;
> +
> +	/*
>  	 * Initialize DMA (if necessary)
>  	 */
>  	atmel_init_property(atmel_port, pdev);
> @@ -1654,6 +1754,11 @@ static int atmel_startup(struct uart_port *port)
>  	}
>  
>  	return 0;
> +
> +free_irq:
> +	free_irq(port->irq, port);
> +
> +	return retval;
>  }
>  
>  /*
> @@ -1701,9 +1806,12 @@ static void atmel_shutdown(struct uart_port *port)
>  	atmel_port->rx_ring.tail = 0;
>  
>  	/*
> -	 * Free the interrupt
> +	 * Free the interrupts
>  	 */
>  	free_irq(port->irq, port);
> +	atmel_free_gpio_irq(port);
> +
> +	atmel_port->ms_irq_enabled = false;
>  }
>  
>  /*
> @@ -2366,10 +2474,21 @@ static int atmel_serial_resume(struct platform_device *pdev)
>  
>  static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev)
>  {
> +	enum mctrl_gpio_idx i;
> +	struct gpio_desc *gpiod;
> +
>  	p->gpios = mctrl_gpio_init(dev, 0);
>  	if (IS_ERR_OR_NULL(p->gpios))
>  		return -1;
>  
> +	for (i = 0; i < UART_GPIO_MAX; i++) {
> +		gpiod = mctrl_gpio_to_gpiod(p->gpios, i);
> +		if (gpiod && (gpiod_get_direction(gpiod) == GPIOF_DIR_IN))
> +			p->gpio_irq[i] = gpiod_to_irq(gpiod);
> +		else
> +			p->gpio_irq[i] = -EINVAL;
> +	}
> +
>  	return 0;
>  }
>  
> 


-- 
Nicolas Ferre

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-10 16:45   ` Richard Genoud
@ 2014-03-17 23:23     ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 30+ messages in thread
From: Greg Kroah-Hartman @ 2014-03-17 23:23 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Uwe Kleine-König, Nicolas Ferre, Linus Walleij,
	Alexander Shiyan, linux-serial, linux-arm-kernel, Richard Genoud

On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> GPIO.
> This will be useful for many boards which have a serial controller that
> only handle CTS/RTS pins (or even just RX/TX).
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

I can't take this series through my tty tree as the non-tty patches
don't apply, so feel free to take them through whatever tree is needed.

greg k-h

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-03-17 23:23     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 30+ messages in thread
From: Greg Kroah-Hartman @ 2014-03-17 23:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> GPIO.
> This will be useful for many boards which have a serial controller that
> only handle CTS/RTS pins (or even just RX/TX).
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

I can't take this series through my tty tree as the non-tty patches
don't apply, so feel free to take them through whatever tree is needed.

greg k-h

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-17 23:23     ` Greg Kroah-Hartman
@ 2014-03-18 10:13       ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-18 10:13 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Richard Genoud, Uwe Kleine-König, Nicolas Ferre,
	Linus Walleij, Alexander Shiyan, linux-serial, linux-arm-kernel

2014-03-18 0:23 GMT+01:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> I can't take this series through my tty tree as the non-tty patches
> don't apply, so feel free to take them through whatever tree is needed.
>
> greg k-h

To clarify things, here are the patches that this series needs, on top
of 3.14-rc6:
tty/tty-next tree: ddaa603739fe tty/serial: at91: use dev_err instead of printk
tty/tty-next tree: a3c1fa99f4d2 tty/serial: at91: remove unused open/close hooks
ukl/dropmachtimexh-fixup: 354e57f3a0a2 ARM/serial: at91: switch atmel
serial to use gpiolib
tree unknown: [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
pinctrl/for-next: 8af584b86836 pinctrl: at91: implement get_direction

after that, the series applies cleanly.
the patch "[PATCH v3 5/7] ARM: at91: gpio: implement get_direction"
has been acked-by Linus, but I didn't found it in a tree.

onto next-20140318, it only needs "[PATCH v3 5/7] ARM: at91: gpio:
implement get_direction" .

trees:
tty: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
ukl: git://git.pengutronix.de/git/ukl/linux.git
pinctrl: git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git


Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-03-18 10:13       ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-18 10:13 UTC (permalink / raw)
  To: linux-arm-kernel

2014-03-18 0:23 GMT+01:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>
> I can't take this series through my tty tree as the non-tty patches
> don't apply, so feel free to take them through whatever tree is needed.
>
> greg k-h

To clarify things, here are the patches that this series needs, on top
of 3.14-rc6:
tty/tty-next tree: ddaa603739fe tty/serial: at91: use dev_err instead of printk
tty/tty-next tree: a3c1fa99f4d2 tty/serial: at91: remove unused open/close hooks
ukl/dropmachtimexh-fixup: 354e57f3a0a2 ARM/serial: at91: switch atmel
serial to use gpiolib
tree unknown: [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
pinctrl/for-next: 8af584b86836 pinctrl: at91: implement get_direction

after that, the series applies cleanly.
the patch "[PATCH v3 5/7] ARM: at91: gpio: implement get_direction"
has been acked-by Linus, but I didn't found it in a tree.

onto next-20140318, it only needs "[PATCH v3 5/7] ARM: at91: gpio:
implement get_direction" .

trees:
tty: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
ukl: git://git.pengutronix.de/git/ukl/linux.git
pinctrl: git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git


Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-18 10:13       ` Richard Genoud
@ 2014-03-22 10:14         ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-22 10:14 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Nicolas Ferre, Linus Walleij, Uwe Kleine-König
  Cc: Richard Genoud, Alexander Shiyan, linux-serial, linux-arm-kernel

2014-03-18 11:13 GMT+01:00 Richard Genoud <richard.genoud@gmail.com>:
> 2014-03-18 0:23 GMT+01:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
>> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>>> GPIO.
>>> This will be useful for many boards which have a serial controller that
>>> only handle CTS/RTS pins (or even just RX/TX).
>>>
>>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>>
>> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>
>> I can't take this series through my tty tree as the non-tty patches
>> don't apply, so feel free to take them through whatever tree is needed.
>>
>> greg k-h
>
> To clarify things, here are the patches that this series needs, on top
> of 3.14-rc6:
> tty/tty-next tree: ddaa603739fe tty/serial: at91: use dev_err instead of printk
> tty/tty-next tree: a3c1fa99f4d2 tty/serial: at91: remove unused open/close hooks
> ukl/dropmachtimexh-fixup: 354e57f3a0a2 ARM/serial: at91: switch atmel
> serial to use gpiolib
> tree unknown: [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
> pinctrl/for-next: 8af584b86836 pinctrl: at91: implement get_direction
>
> after that, the series applies cleanly.
> the patch "[PATCH v3 5/7] ARM: at91: gpio: implement get_direction"
> has been acked-by Linus, but I didn't found it in a tree.
>
> onto next-20140318, it only needs "[PATCH v3 5/7] ARM: at91: gpio:
> implement get_direction" .
>
> trees:
> tty: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
> ukl: git://git.pengutronix.de/git/ukl/linux.git
> pinctrl: git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
>
>
> Richard.

If it helps, I've prepared some branches on github that can be pulled
from tty-next (or pinctrl-next, or dropmachtimexh-fixup)
(I didn't find which branch to base this on in the AT91 tree)

the address is:
git@github.com:rgenoud/linux.git

branch for_upstream/gpiolib-helpers-for-tty-next has the gpiolib
series rebased onto tty-next
branch for_upstream/gpiolib-helpers-for-pinctrl-next : same thing on
pinctrl-next
branch for_upstream/gpiolib-helpers-for-dropmachtimexh-fixup : same on
dropmachtimexh-fixup
branch for_upstream/atmel_serial-final is just the series onto 3.14-rc6

I'm not sure this is the right way to do it though.

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-03-22 10:14         ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-03-22 10:14 UTC (permalink / raw)
  To: linux-arm-kernel

2014-03-18 11:13 GMT+01:00 Richard Genoud <richard.genoud@gmail.com>:
> 2014-03-18 0:23 GMT+01:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
>> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>>> GPIO.
>>> This will be useful for many boards which have a serial controller that
>>> only handle CTS/RTS pins (or even just RX/TX).
>>>
>>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>>
>> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>>
>> I can't take this series through my tty tree as the non-tty patches
>> don't apply, so feel free to take them through whatever tree is needed.
>>
>> greg k-h
>
> To clarify things, here are the patches that this series needs, on top
> of 3.14-rc6:
> tty/tty-next tree: ddaa603739fe tty/serial: at91: use dev_err instead of printk
> tty/tty-next tree: a3c1fa99f4d2 tty/serial: at91: remove unused open/close hooks
> ukl/dropmachtimexh-fixup: 354e57f3a0a2 ARM/serial: at91: switch atmel
> serial to use gpiolib
> tree unknown: [PATCH v3 5/7] ARM: at91: gpio: implement get_direction
> pinctrl/for-next: 8af584b86836 pinctrl: at91: implement get_direction
>
> after that, the series applies cleanly.
> the patch "[PATCH v3 5/7] ARM: at91: gpio: implement get_direction"
> has been acked-by Linus, but I didn't found it in a tree.
>
> onto next-20140318, it only needs "[PATCH v3 5/7] ARM: at91: gpio:
> implement get_direction" .
>
> trees:
> tty: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
> ukl: git://git.pengutronix.de/git/ukl/linux.git
> pinctrl: git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
>
>
> Richard.

If it helps, I've prepared some branches on github that can be pulled
from tty-next (or pinctrl-next, or dropmachtimexh-fixup)
(I didn't find which branch to base this on in the AT91 tree)

the address is:
git at github.com:rgenoud/linux.git

branch for_upstream/gpiolib-helpers-for-tty-next has the gpiolib
series rebased onto tty-next
branch for_upstream/gpiolib-helpers-for-pinctrl-next : same thing on
pinctrl-next
branch for_upstream/gpiolib-helpers-for-dropmachtimexh-fixup : same on
dropmachtimexh-fixup
branch for_upstream/atmel_serial-final is just the series onto 3.14-rc6

I'm not sure this is the right way to do it though.

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-17 23:23     ` Greg Kroah-Hartman
@ 2014-04-02 15:09       ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-02 15:09 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Richard Genoud, Uwe Kleine-König, Nicolas Ferre,
	Linus Walleij, Alexander Shiyan, linux-serial, linux-arm-kernel

On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> 
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
> I can't take this series through my tty tree as the non-tty patches
> don't apply, so feel free to take them through whatever tree is needed.
> 
> greg k-h
> 

I guess this series won't make it for 3.15, as it doesn't apply on any tree.
However, I'd like to know if I did something wrong, or if there's no
solution when a series depends on several patches that are in different
trees ?

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-02 15:09       ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-02 15:09 UTC (permalink / raw)
  To: linux-arm-kernel

On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
> On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> 
> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
> I can't take this series through my tty tree as the non-tty patches
> don't apply, so feel free to take them through whatever tree is needed.
> 
> greg k-h
> 

I guess this series won't make it for 3.15, as it doesn't apply on any tree.
However, I'd like to know if I did something wrong, or if there's no
solution when a series depends on several patches that are in different
trees ?

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-04-02 15:09       ` Richard Genoud
@ 2014-04-02 23:13         ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 30+ messages in thread
From: Greg Kroah-Hartman @ 2014-04-02 23:13 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Richard Genoud, Uwe Kleine-König, Nicolas Ferre,
	Linus Walleij, Alexander Shiyan, linux-serial, linux-arm-kernel

On Wed, Apr 02, 2014 at 05:09:03PM +0200, Richard Genoud wrote:
> On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
> > On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
> >> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> >> GPIO.
> >> This will be useful for many boards which have a serial controller that
> >> only handle CTS/RTS pins (or even just RX/TX).
> >>
> >> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> > 
> > Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > 
> > I can't take this series through my tty tree as the non-tty patches
> > don't apply, so feel free to take them through whatever tree is needed.
> > 
> > greg k-h
> > 
> 
> I guess this series won't make it for 3.15, as it doesn't apply on any tree.
> However, I'd like to know if I did something wrong, or if there's no
> solution when a series depends on several patches that are in different
> trees ?

That's a hard problem, either wait a release cycle for everything to get
merged properly (like should be done in time for 3.15-rc1 now) and then
submit the code, or ask for different maintainers to either allow other
trees to take the patches, put the patches in different trees at the
same time, or have "topic branches" that different maintainers can pull
from.

Care to send me the patches after 3.15-rc1 is out, as there should not
be any dependancy issues then, right?

greg k-h

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-02 23:13         ` Greg Kroah-Hartman
  0 siblings, 0 replies; 30+ messages in thread
From: Greg Kroah-Hartman @ 2014-04-02 23:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 02, 2014 at 05:09:03PM +0200, Richard Genoud wrote:
> On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
> > On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
> >> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> >> GPIO.
> >> This will be useful for many boards which have a serial controller that
> >> only handle CTS/RTS pins (or even just RX/TX).
> >>
> >> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
> > 
> > Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > 
> > I can't take this series through my tty tree as the non-tty patches
> > don't apply, so feel free to take them through whatever tree is needed.
> > 
> > greg k-h
> > 
> 
> I guess this series won't make it for 3.15, as it doesn't apply on any tree.
> However, I'd like to know if I did something wrong, or if there's no
> solution when a series depends on several patches that are in different
> trees ?

That's a hard problem, either wait a release cycle for everything to get
merged properly (like should be done in time for 3.15-rc1 now) and then
submit the code, or ask for different maintainers to either allow other
trees to take the patches, put the patches in different trees at the
same time, or have "topic branches" that different maintainers can pull
from.

Care to send me the patches after 3.15-rc1 is out, as there should not
be any dependancy issues then, right?

greg k-h

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-04-02 23:13         ` Greg Kroah-Hartman
@ 2014-04-03  9:35           ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-03  9:35 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Richard Genoud, Uwe Kleine-König, Nicolas Ferre,
	Linus Walleij, Alexander Shiyan, linux-serial, linux-arm-kernel

2014-04-03 1:13 GMT+02:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
> On Wed, Apr 02, 2014 at 05:09:03PM +0200, Richard Genoud wrote:
>> On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
>> > On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> >> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> >> GPIO.
>> >> This will be useful for many boards which have a serial controller that
>> >> only handle CTS/RTS pins (or even just RX/TX).
>> >>
>> >> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>> >
>> > Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> >
>> > I can't take this series through my tty tree as the non-tty patches
>> > don't apply, so feel free to take them through whatever tree is needed.
>> >
>> > greg k-h
>> >
>>
>> I guess this series won't make it for 3.15, as it doesn't apply on any tree.
>> However, I'd like to know if I did something wrong, or if there's no
>> solution when a series depends on several patches that are in different
>> trees ?
>
> That's a hard problem, either wait a release cycle for everything to get
> merged properly (like should be done in time for 3.15-rc1 now) and then
> submit the code, or ask for different maintainers to either allow other
> trees to take the patches, put the patches in different trees at the
> same time, or have "topic branches" that different maintainers can pull
> from.
>
> Care to send me the patches after 3.15-rc1 is out, as there should not
> be any dependancy issues then, right?
>
> greg k-h

Ok, I'll do that.
Thanks for the explanation !

I will just send a little patch for 3.15rc1 or rc2 to prevent a DTS
ABI change in 3.16.
Something like this in Documentation/devicetree/bindings/serial/atmel-usart.txt
-rts-gpios = <&pioD 15 0>;
+rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
I guess it could go in AT91 tree
I'll send it soon.

Thanks !


Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-03  9:35           ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-03  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

2014-04-03 1:13 GMT+02:00 Greg Kroah-Hartman <gregkh@linuxfoundation.org>:
> On Wed, Apr 02, 2014 at 05:09:03PM +0200, Richard Genoud wrote:
>> On 18/03/2014 00:23, Greg Kroah-Hartman wrote:
>> > On Mon, Mar 10, 2014 at 05:45:49PM +0100, Richard Genoud wrote:
>> >> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> >> GPIO.
>> >> This will be useful for many boards which have a serial controller that
>> >> only handle CTS/RTS pins (or even just RX/TX).
>> >>
>> >> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>> >
>> > Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
>> >
>> > I can't take this series through my tty tree as the non-tty patches
>> > don't apply, so feel free to take them through whatever tree is needed.
>> >
>> > greg k-h
>> >
>>
>> I guess this series won't make it for 3.15, as it doesn't apply on any tree.
>> However, I'd like to know if I did something wrong, or if there's no
>> solution when a series depends on several patches that are in different
>> trees ?
>
> That's a hard problem, either wait a release cycle for everything to get
> merged properly (like should be done in time for 3.15-rc1 now) and then
> submit the code, or ask for different maintainers to either allow other
> trees to take the patches, put the patches in different trees at the
> same time, or have "topic branches" that different maintainers can pull
> from.
>
> Care to send me the patches after 3.15-rc1 is out, as there should not
> be any dependancy issues then, right?
>
> greg k-h

Ok, I'll do that.
Thanks for the explanation !

I will just send a little patch for 3.15rc1 or rc2 to prevent a DTS
ABI change in 3.16.
Something like this in Documentation/devicetree/bindings/serial/atmel-usart.txt
-rts-gpios = <&pioD 15 0>;
+rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
I guess it could go in AT91 tree
I'll send it soon.

Thanks !


Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-03-10 16:45   ` Richard Genoud
@ 2014-04-22 13:08     ` Yegor Yefremov
  -1 siblings, 0 replies; 30+ messages in thread
From: Yegor Yefremov @ 2014-04-22 13:08 UTC (permalink / raw)
  To: Richard Genoud, Greg Kroah-Hartman
  Cc: Alexander Shiyan, Richard Genoud, Linus Walleij, Nicolas Ferre,
	linux-serial, Uwe Kleine-König, linux-arm-kernel,
	linux-omap, mpfj-list, balbi

On 10.03.2014 17:45, Richard Genoud wrote:
> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> GPIO.
> This will be useful for many boards which have a serial controller that
> only handle CTS/RTS pins (or even just RX/TX).
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

....

> +
> +struct mctrl_gpios {
> +	struct gpio_desc *gpio[UART_GPIO_MAX];
> +};
> +
> +static const struct {
> +	const char *name;
> +	unsigned int mctrl;
> +	bool dir_out;
> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
> +	{ "cts", TIOCM_CTS, false, },
> +	{ "dsr", TIOCM_DSR, false, },
> +	{ "dcd", TIOCM_CD, false, },
> +	{ "rng", TIOCM_RNG, false, },
> +	{ "rts", TIOCM_RTS, true, },
> +	{ "dtr", TIOCM_DTR, true, },
> +	{ "out1", TIOCM_OUT1, true, },
> +	{ "out2", TIOCM_OUT2, true, },
> +};
> +
> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
> +{
> +	enum mctrl_gpio_idx i;
> +
> +	if (IS_ERR_OR_NULL(gpios))
> +		return;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++)
> +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
> +		    mctrl_gpios_desc[i].dir_out)
> +			gpiod_set_value(gpios->gpio[i],
> +					!!(mctrl & mctrl_gpios_desc[i].mctrl));
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
> +
> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
> +				      enum mctrl_gpio_idx gidx)
> +{
> +	if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
> +		return gpios->gpio[gidx];
> +	else
> +		return NULL;
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
> +
> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
> +{
> +	enum mctrl_gpio_idx i;
> +
> +	/*
> +	 * return it unchanged if the structure is not allocated
> +	 */
> +	if (IS_ERR_OR_NULL(gpios))
> +		return *mctrl;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++) {
> +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
> +		    !mctrl_gpios_desc[i].dir_out) {
> +			if (gpiod_get_value(gpios->gpio[i]))
> +				*mctrl |= mctrl_gpios_desc[i].mctrl;
> +			else
> +				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
> +		}
> +	}
> +
> +	return *mctrl;
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);

Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?

I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.

What would be the best solution for this task using this new API?

Yegor

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-22 13:08     ` Yegor Yefremov
  0 siblings, 0 replies; 30+ messages in thread
From: Yegor Yefremov @ 2014-04-22 13:08 UTC (permalink / raw)
  To: linux-arm-kernel

On 10.03.2014 17:45, Richard Genoud wrote:
> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
> GPIO.
> This will be useful for many boards which have a serial controller that
> only handle CTS/RTS pins (or even just RX/TX).
> 
> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>

....

> +
> +struct mctrl_gpios {
> +	struct gpio_desc *gpio[UART_GPIO_MAX];
> +};
> +
> +static const struct {
> +	const char *name;
> +	unsigned int mctrl;
> +	bool dir_out;
> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
> +	{ "cts", TIOCM_CTS, false, },
> +	{ "dsr", TIOCM_DSR, false, },
> +	{ "dcd", TIOCM_CD, false, },
> +	{ "rng", TIOCM_RNG, false, },
> +	{ "rts", TIOCM_RTS, true, },
> +	{ "dtr", TIOCM_DTR, true, },
> +	{ "out1", TIOCM_OUT1, true, },
> +	{ "out2", TIOCM_OUT2, true, },
> +};
> +
> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
> +{
> +	enum mctrl_gpio_idx i;
> +
> +	if (IS_ERR_OR_NULL(gpios))
> +		return;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++)
> +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
> +		    mctrl_gpios_desc[i].dir_out)
> +			gpiod_set_value(gpios->gpio[i],
> +					!!(mctrl & mctrl_gpios_desc[i].mctrl));
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
> +
> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
> +				      enum mctrl_gpio_idx gidx)
> +{
> +	if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
> +		return gpios->gpio[gidx];
> +	else
> +		return NULL;
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
> +
> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
> +{
> +	enum mctrl_gpio_idx i;
> +
> +	/*
> +	 * return it unchanged if the structure is not allocated
> +	 */
> +	if (IS_ERR_OR_NULL(gpios))
> +		return *mctrl;
> +
> +	for (i = 0; i < UART_GPIO_MAX; i++) {
> +		if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
> +		    !mctrl_gpios_desc[i].dir_out) {
> +			if (gpiod_get_value(gpios->gpio[i]))
> +				*mctrl |= mctrl_gpios_desc[i].mctrl;
> +			else
> +				*mctrl &= ~mctrl_gpios_desc[i].mctrl;
> +		}
> +	}
> +
> +	return *mctrl;
> +}
> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);

Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?

I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.

What would be the best solution for this task using this new API?

Yegor

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-04-22 13:08     ` Yegor Yefremov
@ 2014-04-25 14:56       ` Richard Genoud
  -1 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-25 14:56 UTC (permalink / raw)
  To: yegor_sub1
  Cc: Richard Genoud, Greg Kroah-Hartman, Alexander Shiyan,
	Linus Walleij, Nicolas Ferre, linux-serial,
	Uwe Kleine-König, linux-arm-kernel, linux-omap, mpfj-list,
	Felipe Balbi

2014-04-22 15:08 GMT+02:00 Yegor Yefremov <yegor_sub1@visionsystems.de>:
> On 10.03.2014 17:45, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>
> ....
>
>> +
>> +struct mctrl_gpios {
>> +     struct gpio_desc *gpio[UART_GPIO_MAX];
>> +};
>> +
>> +static const struct {
>> +     const char *name;
>> +     unsigned int mctrl;
>> +     bool dir_out;
>> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
>> +     { "cts", TIOCM_CTS, false, },
>> +     { "dsr", TIOCM_DSR, false, },
>> +     { "dcd", TIOCM_CD, false, },
>> +     { "rng", TIOCM_RNG, false, },
>> +     { "rts", TIOCM_RTS, true, },
>> +     { "dtr", TIOCM_DTR, true, },
>> +     { "out1", TIOCM_OUT1, true, },
>> +     { "out2", TIOCM_OUT2, true, },
>> +};
>> +
>> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
>> +{
>> +     enum mctrl_gpio_idx i;
>> +
>> +     if (IS_ERR_OR_NULL(gpios))
>> +             return;
>> +
>> +     for (i = 0; i < UART_GPIO_MAX; i++)
>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>> +                 mctrl_gpios_desc[i].dir_out)
>> +                     gpiod_set_value(gpios->gpio[i],
>> +                                     !!(mctrl & mctrl_gpios_desc[i].mctrl));
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
>> +
>> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
>> +                                   enum mctrl_gpio_idx gidx)
>> +{
>> +     if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
>> +             return gpios->gpio[gidx];
>> +     else
>> +             return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
>> +
>> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
>> +{
>> +     enum mctrl_gpio_idx i;
>> +
>> +     /*
>> +      * return it unchanged if the structure is not allocated
>> +      */
>> +     if (IS_ERR_OR_NULL(gpios))
>> +             return *mctrl;
>> +
>> +     for (i = 0; i < UART_GPIO_MAX; i++) {
>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>> +                 !mctrl_gpios_desc[i].dir_out) {
>> +                     if (gpiod_get_value(gpios->gpio[i]))
>> +                             *mctrl |= mctrl_gpios_desc[i].mctrl;
>> +                     else
>> +                             *mctrl &= ~mctrl_gpios_desc[i].mctrl;
>> +             }
>> +     }
>> +
>> +     return *mctrl;
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);
>
> Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?
>
> I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.
>
> What would be the best solution for this task using this new API?
Sorry, but I don't really get what you're trying to do.
Could you explain a little bit more ?

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-25 14:56       ` Richard Genoud
  0 siblings, 0 replies; 30+ messages in thread
From: Richard Genoud @ 2014-04-25 14:56 UTC (permalink / raw)
  To: linux-arm-kernel

2014-04-22 15:08 GMT+02:00 Yegor Yefremov <yegor_sub1@visionsystems.de>:
> On 10.03.2014 17:45, Richard Genoud wrote:
>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>> GPIO.
>> This will be useful for many boards which have a serial controller that
>> only handle CTS/RTS pins (or even just RX/TX).
>>
>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>
> ....
>
>> +
>> +struct mctrl_gpios {
>> +     struct gpio_desc *gpio[UART_GPIO_MAX];
>> +};
>> +
>> +static const struct {
>> +     const char *name;
>> +     unsigned int mctrl;
>> +     bool dir_out;
>> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
>> +     { "cts", TIOCM_CTS, false, },
>> +     { "dsr", TIOCM_DSR, false, },
>> +     { "dcd", TIOCM_CD, false, },
>> +     { "rng", TIOCM_RNG, false, },
>> +     { "rts", TIOCM_RTS, true, },
>> +     { "dtr", TIOCM_DTR, true, },
>> +     { "out1", TIOCM_OUT1, true, },
>> +     { "out2", TIOCM_OUT2, true, },
>> +};
>> +
>> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
>> +{
>> +     enum mctrl_gpio_idx i;
>> +
>> +     if (IS_ERR_OR_NULL(gpios))
>> +             return;
>> +
>> +     for (i = 0; i < UART_GPIO_MAX; i++)
>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>> +                 mctrl_gpios_desc[i].dir_out)
>> +                     gpiod_set_value(gpios->gpio[i],
>> +                                     !!(mctrl & mctrl_gpios_desc[i].mctrl));
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
>> +
>> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
>> +                                   enum mctrl_gpio_idx gidx)
>> +{
>> +     if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
>> +             return gpios->gpio[gidx];
>> +     else
>> +             return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
>> +
>> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
>> +{
>> +     enum mctrl_gpio_idx i;
>> +
>> +     /*
>> +      * return it unchanged if the structure is not allocated
>> +      */
>> +     if (IS_ERR_OR_NULL(gpios))
>> +             return *mctrl;
>> +
>> +     for (i = 0; i < UART_GPIO_MAX; i++) {
>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>> +                 !mctrl_gpios_desc[i].dir_out) {
>> +                     if (gpiod_get_value(gpios->gpio[i]))
>> +                             *mctrl |= mctrl_gpios_desc[i].mctrl;
>> +                     else
>> +                             *mctrl &= ~mctrl_gpios_desc[i].mctrl;
>> +             }
>> +     }
>> +
>> +     return *mctrl;
>> +}
>> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);
>
> Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?
>
> I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.
>
> What would be the best solution for this task using this new API?
Sorry, but I don't really get what you're trying to do.
Could you explain a little bit more ?

Richard.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
  2014-04-25 14:56       ` Richard Genoud
@ 2014-04-25 18:37         ` Yegor Yefremov
  -1 siblings, 0 replies; 30+ messages in thread
From: Yegor Yefremov @ 2014-04-25 18:37 UTC (permalink / raw)
  To: Richard Genoud
  Cc: Yegor Yefremov, Richard Genoud, Greg Kroah-Hartman,
	Alexander Shiyan, Linus Walleij, Nicolas Ferre, linux-serial,
	Uwe Kleine-König, linux-arm-kernel, linux-omap, mpfj-list,
	Felipe Balbi

On Fri, Apr 25, 2014 at 4:56 PM, Richard Genoud
<richard.genoud@gmail.com> wrote:
> 2014-04-22 15:08 GMT+02:00 Yegor Yefremov <yegor_sub1@visionsystems.de>:
>> On 10.03.2014 17:45, Richard Genoud wrote:
>>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>>> GPIO.
>>> This will be useful for many boards which have a serial controller that
>>> only handle CTS/RTS pins (or even just RX/TX).
>>>
>>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>>
>> ....
>>
>>> +
>>> +struct mctrl_gpios {
>>> +     struct gpio_desc *gpio[UART_GPIO_MAX];
>>> +};
>>> +
>>> +static const struct {
>>> +     const char *name;
>>> +     unsigned int mctrl;
>>> +     bool dir_out;
>>> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
>>> +     { "cts", TIOCM_CTS, false, },
>>> +     { "dsr", TIOCM_DSR, false, },
>>> +     { "dcd", TIOCM_CD, false, },
>>> +     { "rng", TIOCM_RNG, false, },
>>> +     { "rts", TIOCM_RTS, true, },
>>> +     { "dtr", TIOCM_DTR, true, },
>>> +     { "out1", TIOCM_OUT1, true, },
>>> +     { "out2", TIOCM_OUT2, true, },
>>> +};
>>> +
>>> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
>>> +{
>>> +     enum mctrl_gpio_idx i;
>>> +
>>> +     if (IS_ERR_OR_NULL(gpios))
>>> +             return;
>>> +
>>> +     for (i = 0; i < UART_GPIO_MAX; i++)
>>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>>> +                 mctrl_gpios_desc[i].dir_out)
>>> +                     gpiod_set_value(gpios->gpio[i],
>>> +                                     !!(mctrl & mctrl_gpios_desc[i].mctrl));
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
>>> +
>>> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
>>> +                                   enum mctrl_gpio_idx gidx)
>>> +{
>>> +     if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
>>> +             return gpios->gpio[gidx];
>>> +     else
>>> +             return NULL;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
>>> +
>>> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
>>> +{
>>> +     enum mctrl_gpio_idx i;
>>> +
>>> +     /*
>>> +      * return it unchanged if the structure is not allocated
>>> +      */
>>> +     if (IS_ERR_OR_NULL(gpios))
>>> +             return *mctrl;
>>> +
>>> +     for (i = 0; i < UART_GPIO_MAX; i++) {
>>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>>> +                 !mctrl_gpios_desc[i].dir_out) {
>>> +                     if (gpiod_get_value(gpios->gpio[i]))
>>> +                             *mctrl |= mctrl_gpios_desc[i].mctrl;
>>> +                     else
>>> +                             *mctrl &= ~mctrl_gpios_desc[i].mctrl;
>>> +             }
>>> +     }
>>> +
>>> +     return *mctrl;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);
>>
>> Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?
>>
>> I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.
>>
>> What would be the best solution for this task using this new API?
> Sorry, but I don't really get what you're trying to do.
> Could you explain a little bit more ?

Never mind, I've solved this in this patch:
http://www.spinics.net/lists/arm-kernel/msg325197.html via using

gpiod_set_value() and gpiod_get_value() directly.


Yegor

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines
@ 2014-04-25 18:37         ` Yegor Yefremov
  0 siblings, 0 replies; 30+ messages in thread
From: Yegor Yefremov @ 2014-04-25 18:37 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Apr 25, 2014 at 4:56 PM, Richard Genoud
<richard.genoud@gmail.com> wrote:
> 2014-04-22 15:08 GMT+02:00 Yegor Yefremov <yegor_sub1@visionsystems.de>:
>> On 10.03.2014 17:45, Richard Genoud wrote:
>>> This patch add some helpers to control modem lines (CTS/RTS/DSR...) via
>>> GPIO.
>>> This will be useful for many boards which have a serial controller that
>>> only handle CTS/RTS pins (or even just RX/TX).
>>>
>>> Signed-off-by: Richard Genoud <richard.genoud@gmail.com>
>>
>> ....
>>
>>> +
>>> +struct mctrl_gpios {
>>> +     struct gpio_desc *gpio[UART_GPIO_MAX];
>>> +};
>>> +
>>> +static const struct {
>>> +     const char *name;
>>> +     unsigned int mctrl;
>>> +     bool dir_out;
>>> +} mctrl_gpios_desc[UART_GPIO_MAX] = {
>>> +     { "cts", TIOCM_CTS, false, },
>>> +     { "dsr", TIOCM_DSR, false, },
>>> +     { "dcd", TIOCM_CD, false, },
>>> +     { "rng", TIOCM_RNG, false, },
>>> +     { "rts", TIOCM_RTS, true, },
>>> +     { "dtr", TIOCM_DTR, true, },
>>> +     { "out1", TIOCM_OUT1, true, },
>>> +     { "out2", TIOCM_OUT2, true, },
>>> +};
>>> +
>>> +void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
>>> +{
>>> +     enum mctrl_gpio_idx i;
>>> +
>>> +     if (IS_ERR_OR_NULL(gpios))
>>> +             return;
>>> +
>>> +     for (i = 0; i < UART_GPIO_MAX; i++)
>>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>>> +                 mctrl_gpios_desc[i].dir_out)
>>> +                     gpiod_set_value(gpios->gpio[i],
>>> +                                     !!(mctrl & mctrl_gpios_desc[i].mctrl));
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_set);
>>> +
>>> +struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
>>> +                                   enum mctrl_gpio_idx gidx)
>>> +{
>>> +     if (!IS_ERR_OR_NULL(gpios) && !IS_ERR_OR_NULL(gpios->gpio[gidx]))
>>> +             return gpios->gpio[gidx];
>>> +     else
>>> +             return NULL;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
>>> +
>>> +unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
>>> +{
>>> +     enum mctrl_gpio_idx i;
>>> +
>>> +     /*
>>> +      * return it unchanged if the structure is not allocated
>>> +      */
>>> +     if (IS_ERR_OR_NULL(gpios))
>>> +             return *mctrl;
>>> +
>>> +     for (i = 0; i < UART_GPIO_MAX; i++) {
>>> +             if (!IS_ERR_OR_NULL(gpios->gpio[i]) &&
>>> +                 !mctrl_gpios_desc[i].dir_out) {
>>> +                     if (gpiod_get_value(gpios->gpio[i]))
>>> +                             *mctrl |= mctrl_gpios_desc[i].mctrl;
>>> +                     else
>>> +                             *mctrl &= ~mctrl_gpios_desc[i].mctrl;
>>> +             }
>>> +     }
>>> +
>>> +     return *mctrl;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mctrl_gpio_get);
>>
>> Should this routine be renamed to msr_gpio_get() or perhaps better to give all values (inputs and outputs)?
>>
>> I'm trying to port this approach to omap-serial to implement RS485 switching. I need to know if RTS is already on or not and set it accordingly.
>>
>> What would be the best solution for this task using this new API?
> Sorry, but I don't really get what you're trying to do.
> Could you explain a little bit more ?

Never mind, I've solved this in this patch:
http://www.spinics.net/lists/arm-kernel/msg325197.html via using

gpiod_set_value() and gpiod_get_value() directly.


Yegor

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2014-04-25 18:37 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-10 16:45 [PATCH v6 0/3] tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c Richard Genoud
2014-03-10 16:45 ` Richard Genoud
2014-03-10 16:45 ` [PATCH v6 1/3] tty/serial: Add GPIOLIB helpers for controlling modem lines Richard Genoud
2014-03-10 16:45   ` Richard Genoud
2014-03-17 23:23   ` Greg Kroah-Hartman
2014-03-17 23:23     ` Greg Kroah-Hartman
2014-03-18 10:13     ` Richard Genoud
2014-03-18 10:13       ` Richard Genoud
2014-03-22 10:14       ` Richard Genoud
2014-03-22 10:14         ` Richard Genoud
2014-04-02 15:09     ` Richard Genoud
2014-04-02 15:09       ` Richard Genoud
2014-04-02 23:13       ` Greg Kroah-Hartman
2014-04-02 23:13         ` Greg Kroah-Hartman
2014-04-03  9:35         ` Richard Genoud
2014-04-03  9:35           ` Richard Genoud
2014-04-22 13:08   ` Yegor Yefremov
2014-04-22 13:08     ` Yegor Yefremov
2014-04-25 14:56     ` Richard Genoud
2014-04-25 14:56       ` Richard Genoud
2014-04-25 18:37       ` Yegor Yefremov
2014-04-25 18:37         ` Yegor Yefremov
2014-03-10 16:45 ` [PATCH v6 2/3] tty/serial: at91: use mctrl_gpio helpers Richard Genoud
2014-03-10 16:45   ` Richard Genoud
2014-03-10 17:20   ` Nicolas Ferre
2014-03-10 17:20     ` Nicolas Ferre
2014-03-10 16:45 ` [PATCH v6 3/3] tty/serial: at91: add interrupts for modem control lines Richard Genoud
2014-03-10 16:45   ` Richard Genoud
2014-03-10 17:21   ` Nicolas Ferre
2014-03-10 17:21     ` Nicolas Ferre

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.