Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: mxs-auart: use mctrl_gpio helpers for handling modem signals

Dedicated CTS and RTS pins are unusable together with a lot of other
peripherals because they share the same line. Pinctrl is limited.

Moreover, the AUART controller doesn't handle DTR/DSR/DCD/RI signals,
so we have to control them via GPIO.

This patch permits to use GPIOs to control the CTS/RTS/DTR/DSR/DCD/RI
signals.

Signed-off-by: Janusz Uzycki <j.uzycki@elproma.com.pl>
Reviewed-by: Richard Genoud <richard.genoud@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Janusz Uzycki and committed by
Greg Kroah-Hartman
7c573d7e 42b4eba0

+55 -6
+9 -1
Documentation/devicetree/bindings/serial/fsl-mxs-auart.txt
··· 11 11 - dma-names: "rx" for RX channel, "tx" for TX channel. 12 12 13 13 Optional properties: 14 - - fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines, 14 + - fsl,uart-has-rtscts : Indicate the UART has RTS and CTS lines 15 + for hardware flow control, 15 16 it also means you enable the DMA support for this UART. 17 + - {rts,cts,dtr,dsr,rng,dcd}-gpios: specify a GPIO for RTS/CTS/DTR/DSR/RI/DCD 18 + line respectively. It will use specified PIO instead of the peripheral 19 + function pin for the USART feature. 20 + If unsure, don't specify this property. 16 21 17 22 Example: 18 23 auart0: serial@8006a000 { ··· 26 21 interrupts = <112>; 27 22 dmas = <&dma_apbx 8>, <&dma_apbx 9>; 28 23 dma-names = "rx", "tx"; 24 + cts-gpios = <&gpio1 15 GPIO_ACTIVE_LOW>; 25 + dsr-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; 26 + dcd-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>; 29 27 }; 30 28 31 29 Note: Each auart port should have an alias correctly numbered in "aliases"
+1
drivers/tty/serial/Kconfig
··· 1408 1408 depends on ARCH_MXS 1409 1409 tristate "MXS AUART support" 1410 1410 select SERIAL_CORE 1411 + select SERIAL_MCTRL_GPIO if GPIOLIB 1411 1412 help 1412 1413 This driver supports the MXS Application UART (AUART) port. 1413 1414
+45 -5
drivers/tty/serial/mxs-auart.c
··· 42 42 43 43 #include <asm/cacheflush.h> 44 44 45 + #include <linux/err.h> 46 + #include "serial_mctrl_gpio.h" 47 + 45 48 #define MXS_AUART_PORTS 5 46 49 #define MXS_AUART_FIFO_SIZE 16 47 50 ··· 161 158 struct scatterlist rx_sgl; 162 159 struct dma_chan *rx_dma_chan; 163 160 void *rx_dma_buf; 161 + 162 + struct mctrl_gpios *gpios; 164 163 }; 165 164 166 165 static struct platform_device_id mxs_auart_devtype[] = { ··· 410 405 411 406 static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl) 412 407 { 408 + struct mxs_auart_port *s = to_auart_port(u); 409 + 413 410 u32 ctrl = readl(u->membase + AUART_CTRL2); 414 411 415 412 ctrl &= ~(AUART_CTRL2_RTSEN | AUART_CTRL2_RTS); ··· 423 416 } 424 417 425 418 writel(ctrl, u->membase + AUART_CTRL2); 419 + 420 + mctrl_gpio_set(s->gpios, mctrl); 426 421 } 427 422 428 423 static u32 mxs_auart_get_mctrl(struct uart_port *u) 429 424 { 425 + struct mxs_auart_port *s = to_auart_port(u); 430 426 u32 stat = readl(u->membase + AUART_STAT); 431 427 u32 mctrl = 0; 432 428 433 429 if (stat & AUART_STAT_CTS) 434 430 mctrl |= TIOCM_CTS; 435 431 436 - return mctrl; 432 + return mctrl_gpio_get(s->gpios, &mctrl); 437 433 } 438 434 439 435 static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s); ··· 564 554 565 555 } 566 556 557 + #define RTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ 558 + UART_GPIO_RTS)) 559 + #define CTS_AT_AUART() IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(s->gpios, \ 560 + UART_GPIO_CTS)) 567 561 static void mxs_auart_settermios(struct uart_port *u, 568 562 struct ktermios *termios, 569 563 struct ktermios *old) ··· 644 630 ctrl |= AUART_LINECTRL_STP2; 645 631 646 632 /* figure out the hardware flow control settings */ 633 + ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); 647 634 if (cflag & CRTSCTS) { 648 635 /* 649 636 * The DMA has a bug(see errata:2836) in mx23. ··· 659 644 ctrl2 |= AUART_CTRL2_TXDMAE | AUART_CTRL2_RXDMAE 660 645 | AUART_CTRL2_DMAONERR; 661 646 } 662 - ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN; 663 - } else { 664 - ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN); 647 + /* Even if RTS is GPIO line RTSEN can be enabled because 648 + * the pinctrl configuration decides about RTS pin function */ 649 + ctrl2 |= AUART_CTRL2_RTSEN; 650 + if (CTS_AT_AUART()) 651 + ctrl2 |= AUART_CTRL2_CTSEN; 665 652 } 666 653 667 654 /* set baud rate */ ··· 707 690 s->port.membase + AUART_INTR_CLR); 708 691 709 692 if (istat & AUART_INTR_CTSMIS) { 710 - uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS); 693 + if (CTS_AT_AUART()) 694 + uart_handle_cts_change(&s->port, 695 + stat & AUART_STAT_CTS); 711 696 writel(AUART_INTR_CTSMIS, 712 697 s->port.membase + AUART_INTR_CLR); 713 698 istat &= ~AUART_INTR_CTSMIS; ··· 1033 1014 return 0; 1034 1015 } 1035 1016 1017 + static bool mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) 1018 + { 1019 + s->gpios = mctrl_gpio_init(dev, 0); 1020 + if (IS_ERR_OR_NULL(s->gpios)) 1021 + return false; 1022 + 1023 + /* Block (enabled before) DMA option if RTS or CTS is GPIO line */ 1024 + if (!RTS_AT_AUART() || !CTS_AT_AUART()) { 1025 + if (test_bit(MXS_AUART_RTSCTS, &s->flags)) 1026 + dev_warn(dev, 1027 + "DMA and flow control via gpio may cause some problems. DMA disabled!\n"); 1028 + clear_bit(MXS_AUART_RTSCTS, &s->flags); 1029 + } 1030 + 1031 + return true; 1032 + } 1033 + 1036 1034 static int mxs_auart_probe(struct platform_device *pdev) 1037 1035 { 1038 1036 const struct of_device_id *of_id = ··· 1104 1068 goto out_free_clk; 1105 1069 1106 1070 platform_set_drvdata(pdev, s); 1071 + 1072 + if (!mxs_auart_init_gpios(s, &pdev->dev)) 1073 + dev_err(&pdev->dev, 1074 + "Failed to initialize GPIOs. The serial port may not work as expected\n"); 1107 1075 1108 1076 auart_port[s->port.line] = s; 1109 1077