Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58362d5b authored by Uwe Kleine-König's avatar Uwe Kleine-König Committed by Greg Kroah-Hartman
Browse files

serial: imx: implement handshaking using gpios with the mctrl_gpio helper

parent 4f71a2e0
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -576,6 +576,7 @@ config SERIAL_IMX
	depends on ARCH_MXC || COMPILE_TEST
	depends on ARCH_MXC || COMPILE_TEST
	select SERIAL_CORE
	select SERIAL_CORE
	select RATIONAL
	select RATIONAL
	select SERIAL_MCTRL_GPIO if GPIOLIB
	help
	help
	  If you have a machine based on a Motorola IMX CPU you
	  If you have a machine based on a Motorola IMX CPU you
	  can enable its onboard serial port by enabling this option.
	  can enable its onboard serial port by enabling this option.
+69 −20
Original line number Original line Diff line number Diff line
@@ -44,6 +44,8 @@
#include <linux/platform_data/serial-imx.h>
#include <linux/platform_data/serial-imx.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/dma-imx.h>


#include "serial_mctrl_gpio.h"

/* Register definitions */
/* Register definitions */
#define URXD0 0x0  /* Receiver Register */
#define URXD0 0x0  /* Receiver Register */
#define URTX0 0x40 /* Transmitter Register */
#define URTX0 0x40 /* Transmitter Register */
@@ -209,6 +211,8 @@ struct imx_port {
	struct clk		*clk_per;
	struct clk		*clk_per;
	const struct imx_uart_data *devdata;
	const struct imx_uart_data *devdata;


	struct mctrl_gpios *gpios;

	/* DMA fields */
	/* DMA fields */
	unsigned int		dma_is_inited:1;
	unsigned int		dma_is_inited:1;
	unsigned int		dma_is_enabled:1;
	unsigned int		dma_is_enabled:1;
@@ -311,6 +315,26 @@ static void imx_port_ucrs_restore(struct uart_port *port,
}
}
#endif
#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
 * interrupts disabled on entry
 */
 */
@@ -334,9 +358,9 @@ static void imx_stop_tx(struct uart_port *port)
	    readl(port->membase + USR2) & USR2_TXDC) {
	    readl(port->membase + USR2) & USR2_TXDC) {
		temp = readl(port->membase + UCR2);
		temp = readl(port->membase + UCR2);
		if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
		if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
			temp &= ~UCR2_CTS;
			imx_port_rts_inactive(sport, &temp);
		else
		else
			temp |= UCR2_CTS;
			imx_port_rts_active(sport, &temp);
		writel(temp, port->membase + UCR2);
		writel(temp, port->membase + UCR2);


		temp = readl(port->membase + UCR4);
		temp = readl(port->membase + UCR4);
@@ -378,6 +402,8 @@ static void imx_enable_ms(struct uart_port *port)
	struct imx_port *sport = (struct imx_port *)port;
	struct imx_port *sport = (struct imx_port *)port;


	mod_timer(&sport->timer, jiffies);
	mod_timer(&sport->timer, jiffies);

	mctrl_gpio_enable_ms(sport->gpios);
}
}


static void imx_dma_tx(struct imx_port *sport);
static void imx_dma_tx(struct imx_port *sport);
@@ -537,14 +563,14 @@ static void imx_start_tx(struct uart_port *port)
	unsigned long temp;
	unsigned long temp;


	if (port->rs485.flags & SER_RS485_ENABLED) {
	if (port->rs485.flags & SER_RS485_ENABLED) {
		/* enable transmitter and shifter empty irq */
		temp = readl(port->membase + UCR2);
		temp = readl(port->membase + UCR2);
		if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
		if (port->rs485.flags & SER_RS485_RTS_ON_SEND)
			temp &= ~UCR2_CTS;
			imx_port_rts_inactive(sport, &temp);
		else
		else
			temp |= UCR2_CTS;
			imx_port_rts_active(sport, &temp);
		writel(temp, port->membase + UCR2);
		writel(temp, port->membase + UCR2);


		/* enable transmitter and shifter empty irq */
		temp = readl(port->membase + UCR4);
		temp = readl(port->membase + UCR4);
		temp |= UCR4_TCEN;
		temp |= UCR4_TCEN;
		writel(temp, port->membase + UCR4);
		writel(temp, port->membase + UCR4);
@@ -759,9 +785,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.
 * 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 int tmp = TIOCM_DSR;
	unsigned usr1 = readl(sport->port.membase + USR1);
	unsigned usr1 = readl(sport->port.membase + USR1);


@@ -779,6 +804,16 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
	return tmp;
	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)
static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
{
	struct imx_port *sport = (struct imx_port *)port;
	struct imx_port *sport = (struct imx_port *)port;
@@ -801,6 +836,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
	if (mctrl & TIOCM_LOOP)
	if (mctrl & TIOCM_LOOP)
		temp |= UTS_LOOP;
		temp |= UTS_LOOP;
	writel(temp, sport->port.membase + uts_reg(sport));
	writel(temp, sport->port.membase + uts_reg(sport));

	mctrl_gpio_set(sport->gpios, mctrl);
}
}


/*
/*
@@ -830,7 +867,7 @@ static void imx_mctrl_check(struct imx_port *sport)
{
{
	unsigned int status, changed;
	unsigned int status, changed;


	status = imx_get_mctrl(&sport->port);
	status = imx_get_hwmctrl(sport);
	changed = status ^ sport->old_status;
	changed = status ^ sport->old_status;


	if (changed == 0)
	if (changed == 0)
@@ -1218,6 +1255,8 @@ static void imx_shutdown(struct uart_port *port)
		imx_uart_dma_exit(sport);
		imx_uart_dma_exit(sport);
	}
	}


	mctrl_gpio_disable_ms(sport->gpios);

	spin_lock_irqsave(&sport->port.lock, flags);
	spin_lock_irqsave(&sport->port.lock, flags);
	temp = readl(sport->port.membase + UCR2);
	temp = readl(sport->port.membase + UCR2);
	temp &= ~(UCR2_TXEN);
	temp &= ~(UCR2_TXEN);
@@ -1295,9 +1334,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
{
{
	struct imx_port *sport = (struct imx_port *)port;
	struct imx_port *sport = (struct imx_port *)port;
	unsigned long flags;
	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 old_csize = old ? old->c_cflag & CSIZE : CS8;
	unsigned int div, ufcr;
	unsigned long div, ufcr;
	unsigned long num, denom;
	unsigned long num, denom;
	uint64_t tdiv64;
	uint64_t tdiv64;


@@ -1326,19 +1366,25 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
				 * it under manual control and keep transmitter
				 * it under manual control and keep transmitter
				 * disabled.
				 * disabled.
				 */
				 */
				if (!(port->rs485.flags &
				if (port->rs485.flags &
				      SER_RS485_RTS_AFTER_SEND))
				    SER_RS485_RTS_AFTER_SEND)
					ucr2 |= UCR2_CTS;
					imx_port_rts_inactive(sport, &ucr2);
				else
					imx_port_rts_active(sport, &ucr2);
			} else {
			} else {
				ucr2 |= UCR2_CTSC;
				imx_port_rts_auto(sport, &ucr2);
			}
			}
		} else {
		} else {
			termios->c_cflag &= ~CRTSCTS;
			termios->c_cflag &= ~CRTSCTS;
		}
		}
	} else if (port->rs485.flags & SER_RS485_ENABLED)
	} else if (port->rs485.flags & SER_RS485_ENABLED) {
		/* disable transmitter */
		/* disable transmitter */
		if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND))
		if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
			ucr2 |= UCR2_CTS;
			imx_port_rts_inactive(sport, &ucr2);
		else
			imx_port_rts_active(sport, &ucr2);
	}



	if (termios->c_cflag & CSTOPB)
	if (termios->c_cflag & CSTOPB)
		ucr2 |= UCR2_STPB;
		ucr2 |= UCR2_STPB;
@@ -1579,11 +1625,10 @@ static int imx_rs485_config(struct uart_port *port,


		/* disable transmitter */
		/* disable transmitter */
		temp = readl(sport->port.membase + UCR2);
		temp = readl(sport->port.membase + UCR2);
		temp &= ~UCR2_CTSC;
		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
		if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND)
			temp &= ~UCR2_CTS;
			imx_port_rts_inactive(sport, &temp);
		else
		else
			temp |= UCR2_CTS;
			imx_port_rts_active(sport, &temp);
		writel(temp, sport->port.membase + UCR2);
		writel(temp, sport->port.membase + UCR2);
	}
	}


@@ -1956,6 +2001,10 @@ static int serial_imx_probe(struct platform_device *pdev)
	sport->timer.function = imx_timeout;
	sport->timer.function = imx_timeout;
	sport->timer.data     = (unsigned long)sport;
	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");
	sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
	if (IS_ERR(sport->clk_ipg)) {
	if (IS_ERR(sport->clk_ipg)) {
		ret = PTR_ERR(sport->clk_ipg);
		ret = PTR_ERR(sport->clk_ipg);