diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r-- | drivers/tty/serial/imx.c | 189 |
1 files changed, 123 insertions, 66 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 016e4be05cec..9362f54c816c 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 */ @@ -148,8 +150,11 @@ #define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */ #define USR2_DTRF (1<<13) /* DTR edge interrupt flag */ #define USR2_IDLE (1<<12) /* Idle condition */ +#define USR2_RIDELT (1<<10) /* Ring Interrupt Delta */ +#define USR2_RIIN (1<<9) /* Ring Indicator Input */ #define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */ #define USR2_WAKE (1<<7) /* Wake */ +#define USR2_DCDIN (1<<5) /* Data Carrier Detect Input */ #define USR2_RTSF (1<<4) /* RTS edge interrupt flag */ #define USR2_TXDC (1<<3) /* Transmitter complete */ #define USR2_BRCD (1<<2) /* Break condition */ @@ -206,6 +211,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,49 +315,24 @@ static void imx_port_ucrs_restore(struct uart_port *port, } #endif -/* - * Handle any change of modem status signal since we were last called. - */ -static void imx_mctrl_check(struct imx_port *sport) +static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) { - unsigned int status, changed; - - status = sport->port.ops->get_mctrl(&sport->port); - changed = status ^ sport->old_status; - - if (changed == 0) - return; - - sport->old_status = status; + *ucr2 &= ~UCR2_CTSC; + *ucr2 |= UCR2_CTS; - if (changed & TIOCM_RI) - sport->port.icount.rng++; - if (changed & TIOCM_DSR) - sport->port.icount.dsr++; - if (changed & TIOCM_CAR) - uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); - if (changed & TIOCM_CTS) - uart_handle_cts_change(&sport->port, status & TIOCM_CTS); - - wake_up_interruptible(&sport->port.state->port.delta_msr_wait); + mctrl_gpio_set(sport->gpios, sport->port.mctrl | TIOCM_RTS); } -/* - * This is our per-port timeout handler, for checking the - * modem status signals. - */ -static void imx_timeout(unsigned long data) +static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) { - struct imx_port *sport = (struct imx_port *)data; - unsigned long flags; + *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); - if (sport->port.state) { - spin_lock_irqsave(&sport->port.lock, flags); - imx_mctrl_check(sport); - spin_unlock_irqrestore(&sport->port.lock, flags); + mctrl_gpio_set(sport->gpios, sport->port.mctrl & ~TIOCM_RTS); +} - mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); - } +static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) +{ + *ucr2 |= UCR2_CTSC; } /* @@ -376,9 +358,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); @@ -420,6 +402,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); @@ -579,14 +563,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); @@ -801,23 +785,35 @@ 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 | TIOCM_CAR; + unsigned int tmp = TIOCM_DSR; + unsigned usr1 = readl(sport->port.membase + USR1); - if (readl(sport->port.membase + USR1) & USR1_RTSS) + if (usr1 & USR1_RTSS) tmp |= TIOCM_CTS; - if (readl(sport->port.membase + UCR2) & UCR2_CTS) - tmp |= TIOCM_RTS; + /* in DCE mode DCDIN is always 0 */ + if (!(usr1 & USR2_DCDIN)) + tmp |= TIOCM_CAR; - if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP) - tmp |= TIOCM_LOOP; + /* in DCE mode RIIN is always 0 */ + if (readl(sport->port.membase + USR2) & USR2_RIIN) + tmp |= TIOCM_RI; 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; @@ -831,10 +827,17 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) writel(temp, sport->port.membase + UCR2); } + temp = readl(sport->port.membase + UCR3) & ~UCR3_DSR; + if (!(mctrl & TIOCM_DTR)) + temp |= UCR3_DSR; + writel(temp, sport->port.membase + UCR3); + temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) temp |= UTS_LOOP; writel(temp, sport->port.membase + uts_reg(sport)); + + mctrl_gpio_set(sport->gpios, mctrl); } /* @@ -857,6 +860,51 @@ static void imx_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&sport->port.lock, flags); } +/* + * Handle any change of modem status signal since we were last called. + */ +static void imx_mctrl_check(struct imx_port *sport) +{ + unsigned int status, changed; + + status = imx_get_hwmctrl(sport); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.state->port.delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void imx_timeout(unsigned long data) +{ + struct imx_port *sport = (struct imx_port *)data; + unsigned long flags; + + if (sport->port.state) { + spin_lock_irqsave(&sport->port.lock, flags); + imx_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + #define RX_BUF_SIZE (PAGE_SIZE) static void imx_rx_dma_done(struct imx_port *sport) { @@ -1207,6 +1255,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); @@ -1284,9 +1334,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_ucr2, baud, quot; + unsigned long ucr2, old_ucr1, old_ucr2; + 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; @@ -1315,19 +1366,25 @@ 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); } } 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; @@ -1568,11 +1625,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); } @@ -1857,11 +1913,10 @@ static int serial_imx_probe_dt(struct imx_port *sport, struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(imx_uart_dt_ids, &pdev->dev); int ret; - if (!np) + sport->devdata = of_device_get_match_data(&pdev->dev); + if (!sport->devdata) /* no device tree device */ return 1; @@ -1878,8 +1933,6 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "fsl,dte-mode", NULL)) sport->dte_mode = 1; - sport->devdata = of_id->data; - return 0; } #else @@ -1948,6 +2001,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); |