From: Yegor Yefremov
This patch permits the usage for GPIOs to control
the CTS/RTS/DTR/DSR/DCD/RI signals.
Changed by Stefan:
Only call mctrl_gpio_init(), if the device has no ACPI companion device
to not break existing ACPI based systems. Also only use the mctrl_gpio_
functions when "gpios" is available.
Signed-off-by: Yegor Yefremov
Signed-off-by: Greg Kroah-Hartman
Signed-off-by: Stefan Roese
Cc: Mika Westerberg
Cc: Andy Shevchenko
Cc: Giulio Benetti
Cc: Yegor Yefremov
Cc: Greg Kroah-Hartman
---
v3:
- Only call mctrl_gpio_init(), if the device has no ACPI companion device
to not break existing ACPI based systems, as suggested by Andy
v2:
- No change
Please note that this patch was already applied before [1]. And later
reverted [2] because it introduced problems on some x86 based boards
(ACPI GPIO related). Here a detailed description of the issue at that
time:
https://lkml.org/lkml/2016/8/9/357
http://www.spinics.net/lists/linux-serial/msg23071.html
This is a re-send of the original patch that was applied at that time.
With patch 1/2 from this series this issue should be fixed now (please
note that I can't test it on such an x86 platform causing these
problems).
Andy (or Mika), perhaps it would be possible for you to test this
patch again, now with patch 1/2 of this series applied as well?
That would be really helpful.
Thanks,
Stefan
[1] 4ef03d328769 ("tty/serial/8250: use mctrl_gpio helpers")
[2] 5db4f7f80d16 ("Revert "tty/serial/8250: use mctrl_gpio helpers"")
.../devicetree/bindings/serial/8250.txt | 19 +
drivers/tty/serial/8250/8250.h| 40 ++-
drivers/tty/serial/8250/8250_core.c | 17
drivers/tty/serial/8250/8250_omap.c | 31 --
drivers/tty/serial/8250/8250_port.c | 9 +
drivers/tty/serial/8250/Kconfig | 1 +
include/linux/serial_8250.h | 1 +
7 files changed, 104 insertions(+), 14 deletions(-)
diff --git a/Documentation/devicetree/bindings/serial/8250.txt
b/Documentation/devicetree/bindings/serial/8250.txt
index 3cba12f855b7..20d351f268ef 100644
--- a/Documentation/devicetree/bindings/serial/8250.txt
+++ b/Documentation/devicetree/bindings/serial/8250.txt
@@ -53,6 +53,9 @@ Optional properties:
programmable TX FIFO thresholds.
- resets : phandle + reset specifier pairs
- overrun-throttle-ms : how long to pause uart rx when input overrun is
encountered.
+- {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD
+ line respectively. It will use specified GPIO instead of the peripheral
+ function pin for the UART feature. If unsure, don't specify this property.
Note:
* fsl,ns16550:
@@ -74,3 +77,19 @@ Example:
interrupts = <10>;
reg-shift = <2>;
};
+
+Example for OMAP UART using GPIO-based modem control signals:
+
+ uart4: serial@49042000 {
+ compatible = "ti,omap3-uart";
+ reg = <0x49042000 0x400>;
+ interrupts = <80>;
+ ti,hwmods = "uart4";
+ clock-frequency = <4800>;
+ cts-gpios = < 5 GPIO_ACTIVE_LOW>;
+ rts-gpios = < 6 GPIO_ACTIVE_LOW>;
+ dtr-gpios = < 12 GPIO_ACTIVE_LOW>;
+ dsr-gpios = < 13 GPIO_ACTIVE_LOW>;
+ dcd-gpios = < 14 GPIO_ACTIVE_LOW>;
+ rng-gpios = < 15 GPIO_ACTIVE_LOW>;
+ };
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index ebfb0bd5bef5..441aab94264b 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -11,6 +11,8 @@
#include
#include
+#include "../serial_mctrl_gpio.h"
+
struct uart_8250_dma {
int (*tx_dma)(struct uart_8250_port *p);
int (*rx_dma)(struct uart_8250_port *p);
@@ -142,11 +144,47 @@ void serial8250_em485_destroy(struct uart_8250_port *p);
static inline void serial8250_out_MCR(struct uart_8250_port *up, int value)
{
serial_out(up, UART_MCR, value);
+
+ if (up->gpios) {
+ int mctrl_gpio = 0;
+
+ if (value & UART_MCR_RTS)
+ mctrl_gpio |= TIOCM_RTS;
+ if (value & UART_MCR_DTR)
+ mctrl_gpio |= TIOCM_DTR;
+
+ mctrl_gpio_set(up->gpios, mctrl_gpio);
+ }
}
static inline int serial8250_in_MCR(struct uart_8250_port *up)
{
- return serial_in(up, UART_MCR);
+ int mctrl;
+
+ mctrl = serial_in(up, UART_MCR);
+
+ if (up->gpios) {
+ int mctrl_gpio = 0;
+
+ /* save current MCR values */
+ if (mctrl & UART_MCR_RTS)
+ mctrl_gpio |= TIOCM_RTS;
+ if (mctrl & UART_MCR_DTR)
+ mctrl_gpio |= TIOCM_DTR;
+
+ mctrl_gpio = mctrl_gpio_get_outputs(up->gpios, _gpio);
+ if (mctrl_gpio & TIOCM_RTS)
+ mctrl |= UART_MCR_RTS;
+