Skip to contentSkip to conversation

tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

PATCH New Richard Genoud 4 participants 11 messages Apr 25, 2014 – May 3, 2014

Subsystems (7)
lore
Share & tools
lore
#0 lore raw

cover tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

This patch series is a leftover of http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts.

The 1st patch may be applied as a fix for 3.15-rc, since it correct a device tree binding documentation example.

Greg, for you to decide if it's worth it or not !

It's based on v3.15-rc2.

Richard Genoud (5):
tty/serial: atmel_serial: Fix device tree documetation
ARM: at91: gpio: implement get_direction 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 -
 arch/arm/mach-at91/gpio.c                          |  13 ++
 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 -
 15 files changed, 509 insertions(+), 73 deletions(-)
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.c
 create mode 100644 drivers/tty/serial/serial_mctrl_gpio.h
Signature · 1 line
1.8.5.5
#1 lore raw

PATCH 1/5 tty/serial: atmel_serial: Fix device tree documetation

RTS pin is an active low pin.
For now, this doesn't change anything as the ACTIVE_LOW flag is not handled in atmel_serial, but it will be in 3.16.

---
 Documentation/devicetree/bindings/serial/atmel-usart.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

This may be applied as a fix on 3.15-rc, or on 3.16, like the other if this correction is not a big deal.

Documentation/devicetree/bindings/serial/atmel-usart.txt +1 -1
index 17c1042b2df8..2f7aad71b3c9 100644
@@ -35,7 +35,7 @@ Example:
 		clock-names = "usart";
 		atmel,use-dma-rx;
 		atmel,use-dma-tx;
-		rts-gpios = <&pioD 15 0>;
+		rts-gpios = <&pioD 15 GPIO_ACTIVE_LOW>;
 	};
 
 - use DMA:
Signature · 1 line
1.8.5.5
#2 lore raw

PATCH 2/5 ARM: at91: gpio: implement get_direction

In reply to Richard Genoud

This is needed for gpiod_get_direction().
Otherwise, it returns -EINVAL.

---
 arch/arm/mach-at91/gpio.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/arm/mach-at91/gpio.c +13 -0
index a5afcf76550e..afbe34027e62 100644
@@ -49,6 +49,7 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
 static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
 static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
 static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
+static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset);
 static int at91_gpiolib_direction_output(struct gpio_chip *chip,
 					 unsigned offset, int val);
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
@@ -60,6 +61,7 @@ static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
 		.chip = {						\
 			.label		  = name,			\
 			.request	  = at91_gpiolib_request,	\
+			.get_direction    = at91_gpiolib_get_direction, \
 			.direction_input  = at91_gpiolib_direction_input, \
 			.direction_output = at91_gpiolib_direction_output, \
 			.get		  = at91_gpiolib_get,		\
@@ -799,6 +801,17 @@ static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
 	return 0;
 }
 
+static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+	u32 osr;
+
+	osr = __raw_readl(pio + PIO_OSR);
+	return !(osr & mask);
+}
+
 static int at91_gpiolib_direction_input(struct gpio_chip *chip,
 					unsigned offset)
 {
Signature · 1 line
1.8.5.5
#3 lore raw

PATCH 3/5 tty/serial: Add GPIOLIB helpers for controlling modem lines

In reply to 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).

---
 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
Documentation/serial/driver +25 -0
index c3a7689a90e6..3bba1aeb799c 100644
@@ -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.
drivers/tty/serial/Kconfig +3 -0
index 5d9b01aa54f4..95afd310d18e 100644
@@ -1510,4 +1510,7 @@ config SERIAL_ST_ASC_CONSOLE
 
 endmenu
 
+config SERIAL_MCTRL_GPIO
+	tristate
+
 endif # TTY
drivers/tty/serial/Makefile +3 -0
index 3680854fef41..bcf31da267dd 100644
@@ -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
drivers/tty/serial/serial_mctrl_gpio.c new file +143 -0

143 lines not on this page · raw message

drivers/tty/serial/serial_mctrl_gpio.h new file +110 -0

110 lines not on this page · raw message

Signature · 1 line
1.8.5.5
#5 lore raw

PATCH 4/5 tty/serial: at91: use mctrl_gpio helpers

In reply to 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.

---
 .../devicetree/bindings/serial/atmel-usart.txt     |  10 +-
 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, 89 insertions(+), 69 deletions(-)
Documentation/devicetree/bindings/serial/atmel-usart.txt +8 -2
index 2f7aad71b3c9..a6391e70a8fd 100644
@@ -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.
@@ -36,6 +37,11 @@ Example:
 		atmel,use-dma-rx;
 		atmel,use-dma-tx;
 		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:
arch/arm/mach-at91/at91rm9200_devices.c +10 -6
index f3f19f21352a..291a90a5b1d4 100644
@@ -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);
arch/arm/mach-at91/at91sam9260_devices.c +0 -7
index 8b1b0a870025..2d179f82aef8 100644
@@ -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);
arch/arm/mach-at91/at91sam9261_devices.c +0 -4
index 80e35895d28f..b5f7a7226ff8 100644
@@ -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);
arch/arm/mach-at91/at91sam9263_devices.c +0 -4
index 43d53d6156dd..39803c3296b2 100644
@@ -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);
arch/arm/mach-at91/at91sam9g45_devices.c +0 -5
index 77b04c2edd78..4e53d8d9737b 100644
@@ -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);
arch/arm/mach-at91/at91sam9rl_devices.c +0 -5
index 428fc412aaf1..f75985062913 100644
@@ -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);
drivers/tty/serial/Kconfig +1 -0
index 95afd310d18e..6e748dceaae3 100644
@@ -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.
drivers/tty/serial/atmel_serial.c +70 -35

177 lines not on this page · raw message

include/linux/platform_data/atmel.h +0 -1
index e26b0c14edea..cea9f70133c5 100644
@@ -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 */
Signature · 1 line
1.8.5.5
#6 lore raw

PATCH 5/5 tty/serial: at91: add interrupts for modem control lines

In reply to Richard Genoud

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

---
 drivers/tty/serial/atmel_serial.c | 125 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 3 deletions(-)
drivers/tty/serial/atmel_serial.c +122 -3
index 43ca659c1d4b..3fceae099c44 100644
@@ -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;
 }
 
Signature · 1 line
1.8.5.5
#7 lore raw

cover tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

In reply to Richard Genoud
Quoted 7 lines · Richard Genoud

This patch series is a leftover of http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts.

The 1st patch may be applied as a fix for 3.15-rc, since it correct a device tree binding documentation example.

Greg, for you to decide if it's worth it or not !

Why am I the one tho decides if it is worth it? If it's up to me, I'll just say "no", as I sure don't need this for any of my machines...

See, that was easy :)

greg k-h

#8 lore raw

cover tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

2014-04-25 17:58 GMT+02:00 Greg Kroah-Hartman <[email protected]>:

Quoted 11 lines · Richard Genoud
Quoted 7 lines

This patch series is a leftover of http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts.

The 1st patch may be applied as a fix for 3.15-rc, since it correct a device tree binding documentation example.

Greg, for you to decide if it's worth it or not !

Why am I the one tho decides if it is worth it? If it's up to me, I'll just say "no", as I sure don't need this for any of my machines...

Ok, let me reformulate :) :

This patch series is a leftover of
http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts (you acked the series and ask me to resend it during 3.15-rc cycle).

I think that "[PATCH 1/5] tty/serial: atmel_serial: Fix device tree documentation" should be applied on 3.15-rc,
since it corrects a device tree binding documentation example.

The patches 2-5/5 are for 3.16.

#9 lore raw

cover tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

On 27/04/2014 02:58, Richard Genoud :

Quoted 12 lines

2014-04-25 17:58 GMT+02:00 Greg Kroah-Hartman <[email protected]>:

Quoted 11 lines · Richard Genoud
Quoted 7 lines

This patch series is a leftover of http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts.

The 1st patch may be applied as a fix for 3.15-rc, since it correct a device tree binding documentation example.

Greg, for you to decide if it's worth it or not !

Why am I the one tho decides if it is worth it? If it's up to me, I'll just say "no", as I sure don't need this for any of my machines...

Ok, so I need to speak up and say that the patch series is useful for me :-)

Quoted 7 lines

Ok, let me reformulate :) :

This patch series is a leftover of
http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts (you acked the series and ask me to resend it during 3.15-rc cycle).

Quoted 5 lines

I think that "[PATCH 1/5] tty/serial: atmel_serial: Fix device tree documentation" should be applied on 3.15-rc,
since it corrects a device tree binding documentation example.

The patches 2-5/5 are for 3.16.

BTW, patches 4 and 5 were "Acked" by me in v6 revision of this series.

Thanks, bye,

Signature · 1 line
Nicolas Ferre
#10 lore raw

cover tty/serial: Add helpers to use GPIOs to control modem lines and implement atmel_serial.c

In reply to Richard Genoud
Quoted 20 lines · Richard Genoud

2014-04-25 17:58 GMT+02:00 Greg Kroah-Hartman <[email protected]>:

Quoted 11 lines · Richard Genoud
Quoted 7 lines

This patch series is a leftover of http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts.

The 1st patch may be applied as a fix for 3.15-rc, since it correct a device tree binding documentation example.

Greg, for you to decide if it's worth it or not !

Why am I the one tho decides if it is worth it? If it's up to me, I'll just say "no", as I sure don't need this for any of my machines...

Ok, let me reformulate :) :

This patch series is a leftover of
http://www.spinics.net/lists/arm-kernel/msg314242.html
that missed 3.15 because it caused merge conflicts (you acked the series and ask me to resend it during 3.15-rc cycle).

Quoted 5 lines

I think that "[PATCH 1/5] tty/serial: atmel_serial: Fix device tree documentation" should be applied on 3.15-rc,
since it corrects a device tree binding documentation example.

The patches 2-5/5 are for 3.16.

Ok, can you resend these, with a note that the first one should make it to 3.15-final, and I'll queue them up?

thanks,

greg k-h