From d1c4bdadcdb9702fc99651912a421bd663557500 Mon Sep 17 00:00:00 2001 From: Kyungwoo Kang Date: Wed, 3 Jan 2018 12:50:15 +0900 Subject: [PATCH] [COMMON] serial: samsung: Add pinctrl fucntion. For some devices like Bluetooth, RTS line should be protected while suspending or SICD in and out in case of unexpected data flow. Change-Id: I42fb8c3009c4642b0f5fb74e18e8a6151e5b3b3f Signed-off-by: Kyungwoo Kang --- drivers/tty/serial/samsung.c | 63 +++++++++++++++++++++++++++++++++++- drivers/tty/serial/samsung.h | 5 +++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 3df8070c37a0..b8e98d27d4ee 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -106,6 +106,30 @@ EXPORT_SYMBOL_GPL(s3c2410_serial_wake_peer); #define UART_LOOPBACK_MODE (0x1 << 0) #define UART_DBG_MODE (0x1 << 1) +#define RTS_PINCTRL (1) +#define DEFAULT_PINCTRL (0) + +static void change_uart_gpio(int value, struct s3c24xx_uart_port *ourport) +{ + int status = 0; + + if (value) { + if (!IS_ERR(ourport->uart_pinctrl_rts)) { + ourport->default_uart_pinctrl->state = NULL; + status = pinctrl_select_state(ourport->default_uart_pinctrl, ourport->uart_pinctrl_rts); + if (status) + dev_err(ourport->port.dev, "Can't set RTS uart pins!!!\n"); + } + } else { + if (!IS_ERR(ourport->uart_pinctrl_default)) { + ourport->default_uart_pinctrl->state = NULL; + status = pinctrl_select_state(ourport->default_uart_pinctrl, ourport->uart_pinctrl_default); + if (status) + dev_err(ourport->port.dev, "Can't set default uart pins!!!\n"); + } + } +} + static void print_uart_mode(struct uart_port *port, struct ktermios *termios, unsigned int baud) { @@ -1016,6 +1040,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, port->ignore_status_mask |= RXSTAT_DUMMY_READ; spin_unlock_irqrestore(&port->lock, flags); + } static const char *s3c24xx_serial_type(struct uart_port *port) @@ -1522,6 +1547,9 @@ static int s3c24xx_serial_notifier(struct notifier_block *self, wr_regl(port, S3C2410_UMCON, umcon); spin_unlock_irqrestore(&port->lock, flags); + + if (ourport->rts_control) + change_uart_gpio(RTS_PINCTRL, ourport); } break; @@ -1544,6 +1572,9 @@ static int s3c24xx_serial_notifier(struct notifier_block *self, wr_regl(port, S3C2410_UMCON, umcon); spin_unlock_irqrestore(&port->lock, flags); + + if (ourport->rts_control) + change_uart_gpio(DEFAULT_PINCTRL, ourport); } break; @@ -1610,6 +1641,24 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) else ourport->usi_v2 = 0; + if (of_get_property(pdev->dev.of_node, "samsung,rts-gpio-control", NULL)) { + ourport->rts_control = 1; + ourport->default_uart_pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(ourport->default_uart_pinctrl)) + dev_err(&pdev->dev, "Can't get uart pinctrl!!!\n"); + else { + ourport->uart_pinctrl_rts = pinctrl_lookup_state(ourport->default_uart_pinctrl, + "rts"); + if (IS_ERR(ourport->uart_pinctrl_rts)) + dev_err(&pdev->dev, "Can't get RTS pinstate!!!\n"); + + ourport->uart_pinctrl_default = pinctrl_lookup_state(ourport->default_uart_pinctrl, + "default"); + if (IS_ERR(ourport->uart_pinctrl_default)) + dev_err(&pdev->dev, "Can't get Default pinstate!!!\n"); + } + } + if (!of_property_read_u32(pdev->dev.of_node, "samsung,fifo-size", &fifo_size)) { ourport->port.fifosize = fifo_size; @@ -1734,12 +1783,19 @@ static int s3c24xx_serial_suspend(struct device *dev) #endif if (port) { + /* + * If rts line must be protected while suspending + * we change the gpio pad as output high + */ + if (ourport->rts_control) + change_uart_gpio(RTS_PINCTRL, ourport); + uart_suspend_port(&s3c24xx_uart_drv, port); #ifdef CONFIG_SERIAL_SAMSUNG_HWACG uart_clock_enable(ourport); /* disable Tx, Rx mode bit for suspend in case of HWACG */ ucon = rd_regl(port, S3C2410_UCON); - ucon &= ~(S3C2410_UCON_RXIRQMODE | S3C2410_UCON_TXIRQMODE) ; + ucon &= ~(S3C2410_UCON_RXIRQMODE | S3C2410_UCON_TXIRQMODE); wr_regl(port, S3C2410_UCON, ucon); exynos_usi_stop(port); uart_clock_disable(ourport); @@ -1766,6 +1822,10 @@ static int s3c24xx_serial_resume(struct device *dev) uart_clock_disable(ourport); uart_resume_port(&s3c24xx_uart_drv, port); + + if (ourport->rts_control) + change_uart_gpio(DEFAULT_PINCTRL, ourport); + if (ourport->dbg_mode & UART_DBG_MODE) dev_err(dev, "UART resume notification for tty framework.\n"); } @@ -1782,6 +1842,7 @@ static int s3c24xx_serial_resume_noirq(struct device *dev) /* restore IRQ mask */ if (s3c24xx_serial_has_interrupt_mask(port)) { unsigned int uintm = 0xf; + if (tx_enabled(port)) uintm &= ~S3C64XX_UINTM_TXD_MSK; if (rx_enabled(port)) diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h index bba203233f53..a60bf514878d 100644 --- a/drivers/tty/serial/samsung.h +++ b/drivers/tty/serial/samsung.h @@ -73,6 +73,10 @@ struct s3c24xx_uart_port { u32 use_default_irq; unsigned long qos_timeout; unsigned int usi_v2; + struct pinctrl_state *uart_pinctrl_rts; + struct pinctrl_state *uart_pinctrl_default; + struct pinctrl *default_uart_pinctrl; + unsigned int rts_control; /* reference to platform data */ struct s3c2410_uartcfg *cfg; @@ -85,6 +89,7 @@ struct s3c24xx_uart_port { unsigned int in_band_wakeup; unsigned int dbg_mode; + }; /* conversion functions */ -- 2.20.1