Signed-off-by: Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> --- drivers/tty/serial/Kconfig | 1 + drivers/tty/serial/imx.c | 89 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index cdd14d4feb43..d9dec5906c35 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -574,6 +574,7 @@ config SERIAL_IMX depends on ARCH_MXC || COMPILE_TEST select SERIAL_CORE select RATIONAL + select SERIAL_MCTRL_GPIO if GPIOLIB help If you have a machine based on a Motorola IMX CPU you can enable its onboard serial port by enabling this option. diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index a3eb74ee1c3c..c1c9d2a22686 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -44,6 +44,8 @@ #include <linux/platform_data/serial-imx.h> #include <linux/platform_data/dma-imx.h> +#include "serial_mctrl_gpio.h" + /* Register definitions */ #define URXD0 0x0 /* Receiver Register */ #define URTX0 0x40 /* Transmitter Register */ @@ -208,6 +210,8 @@ struct imx_port { struct clk *clk_per; const struct imx_uart_data *devdata; + struct mctrl_gpios *gpios; + /* DMA fields */ unsigned int dma_is_inited:1; unsigned int dma_is_enabled:1; @@ -308,6 +312,26 @@ static void imx_port_ucrs_restore(struct uart_port *port, } #endif +static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) +{ + *ucr2 &= ~UCR2_CTSC; + *ucr2 |= UCR2_CTS; + + mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); +} + +static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) +{ + *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); + + mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); +} + +static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) +{ + *ucr2 |= UCR2_CTSC; +} + /* * interrupts disabled on entry */ @@ -331,9 +355,9 @@ static void imx_stop_tx(struct uart_port *port) readl(port->membase + USR2) & USR2_TXDC) { temp = readl(port->membase + UCR2); if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - temp &= ~UCR2_CTS; + imx_port_rts_inactive(sport, &temp); else - temp |= UCR2_CTS; + imx_port_rts_active(sport, &temp); writel(temp, port->membase + UCR2); temp = readl(port->membase + UCR4); @@ -375,6 +399,8 @@ static void imx_enable_ms(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; mod_timer(&sport->timer, jiffies); + + mctrl_gpio_enable_ms(sport->gpios); } static void imx_dma_tx(struct imx_port *sport); @@ -534,14 +560,14 @@ static void imx_start_tx(struct uart_port *port) unsigned long temp; if (port->rs485.flags & SER_RS485_ENABLED) { - /* enable transmitter and shifter empty irq */ temp = readl(port->membase + UCR2); if (port->rs485.flags & SER_RS485_RTS_ON_SEND) - temp &= ~UCR2_CTS; + imx_port_rts_inactive(sport, &temp); else - temp |= UCR2_CTS; + imx_port_rts_active(sport, &temp); writel(temp, port->membase + UCR2); + /* enable transmitter and shifter empty irq */ temp = readl(port->membase + UCR4); temp |= UCR4_TCEN; writel(temp, port->membase + UCR4); @@ -752,9 +778,8 @@ static unsigned int imx_tx_empty(struct uart_port *port) /* * We have a modem side uart, so the meanings of RTS and CTS are inverted. */ -static unsigned int imx_get_mctrl(struct uart_port *port) +static unsigned int imx_get_hwmctrl(struct imx_port *sport) { - struct imx_port *sport = (struct imx_port *)port; unsigned int tmp = TIOCM_DSR; unsigned usr1 = readl(sport->port.membase + USR1); @@ -772,6 +797,16 @@ static unsigned int imx_get_mctrl(struct uart_port *port) return tmp; } +static unsigned int imx_get_mctrl(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned int ret = imx_get_hwmctrl(sport); + + mctrl_gpio_get(sport->gpios, &ret); + + return ret; +} + static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct imx_port *sport = (struct imx_port *)port; @@ -794,6 +829,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) temp |= UTS_LOOP; writel(temp, sport->port.membase + uts_reg(sport)); + + mctrl_gpio_set(sport->gpios, mctrl); } /* @@ -826,7 +863,7 @@ static void imx_mctrl_check(struct imx_port *sport) { unsigned int status, changed; - status = imx_get_mctrl(&sport->port); + status = imx_get_hwmctrl(sport); changed = status ^ sport->old_status; if (changed == 0) @@ -1205,6 +1242,8 @@ static void imx_shutdown(struct uart_port *port) imx_uart_dma_exit(sport); } + mctrl_gpio_disable_ms(sport->gpios); + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR2); temp &= ~(UCR2_TXEN); @@ -1282,9 +1321,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; + unsigned long ucr2, old_ucr1, old_txrxen; + unsigned int baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned int div, ufcr; + unsigned long div, ufcr; unsigned long num, denom; uint64_t tdiv64; @@ -1313,11 +1353,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, * it under manual control and keep transmitter * disabled. */ - if (!(port->rs485.flags & - SER_RS485_RTS_AFTER_SEND)) - ucr2 |= UCR2_CTS; + if (port->rs485.flags & + SER_RS485_RTS_AFTER_SEND) + imx_port_rts_inactive(sport, &ucr2); + else + imx_port_rts_active(sport, &ucr2); } else { - ucr2 |= UCR2_CTSC; + imx_port_rts_auto(sport, &ucr2); } /* Can we enable the DMA support? */ @@ -1327,10 +1369,14 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, } else { termios->c_cflag &= ~CRTSCTS; } - } else if (port->rs485.flags & SER_RS485_ENABLED) + } else if (port->rs485.flags & SER_RS485_ENABLED) { /* disable transmitter */ - if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) - ucr2 |= UCR2_CTS; + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + imx_port_rts_inactive(sport, &ucr2); + else + imx_port_rts_active(sport, &ucr2); + } + if (termios->c_cflag & CSTOPB) ucr2 |= UCR2_STPB; @@ -1573,11 +1619,10 @@ static int imx_rs485_config(struct uart_port *port, /* disable transmitter */ temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_CTSC; if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) - temp &= ~UCR2_CTS; + imx_port_rts_inactive(sport, &temp); else - temp |= UCR2_CTS; + imx_port_rts_active(sport, &temp); writel(temp, sport->port.membase + UCR2); } @@ -1951,6 +1996,10 @@ static int serial_imx_probe(struct platform_device *pdev) sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport; + sport->gpios = mctrl_gpio_init(&sport->port, 0); + if (IS_ERR(sport->gpios)) + return PTR_ERR(sport->gpios); + sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) { ret = PTR_ERR(sport->clk_ipg); -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html