Skip to content
atmel_serial.c 79.8 KiB
Newer Older
// SPDX-License-Identifier: GPL-2.0+
 *  Driver for Atmel AT91 Serial ports
 *  Copyright (C) 2003 Rick Bronson
 *
 *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
 *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
 *
 *  DMA support added by Chip Coldwell.
 */
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/suspend.h>
#include <linux/mm.h>
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/ioctls.h>
#define PDC_BUFFER_SIZE		512
/* Revisit: We should calculate this based on the actual port settings */
#define PDC_RX_TIMEOUT		(3 * 10)		/* 3 bytes */

/* The minium number of data FIFOs should be able to contain */
#define ATMEL_MIN_FIFO_SIZE	8
/*
 * These two offsets are substracted from the RX FIFO size to define the RTS
 * high and low thresholds
 */
#define ATMEL_RTS_HIGH_OFFSET	16
#define ATMEL_RTS_LOW_OFFSET	20

#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif

#include <linux/serial_core.h>

#include "serial_mctrl_gpio.h"
static void atmel_start_rx(struct uart_port *port);
static void atmel_stop_rx(struct uart_port *port);

#ifdef CONFIG_SERIAL_ATMEL_TTYAT

/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
 * should coexist with the 8250 driver, such as if we have an external 16C550
 * UART. */
#define SERIAL_ATMEL_MAJOR	204
#define MINOR_START		154
#define ATMEL_DEVICENAME	"ttyAT"

#else

/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
 * name, but it is legally reserved for the 8250 driver. */
#define SERIAL_ATMEL_MAJOR	TTY_MAJOR
#define MINOR_START		64
#define ATMEL_DEVICENAME	"ttyS"
#define ATMEL_ISR_PASS_LIMIT	256
struct atmel_dma_buffer {
	unsigned char	*buf;
	dma_addr_t	dma_addr;
	unsigned int	dma_size;
	unsigned int	ofs;
};

struct atmel_uart_char {
	u16		status;
	u16		ch;
};

/*
 * Be careful, the real size of the ring buffer is
 * sizeof(atmel_uart_char) * ATMEL_SERIAL_RINGSIZE. It means that ring buffer
 * can contain up to 1024 characters in PIO mode and up to 4096 characters in
 * DMA mode.
 */
#define ATMEL_SERIAL_RINGSIZE 1024

/*
 * at91: 6 USARTs and one DBGU port (SAM9260)
 * samx7: 3 USARTs and 5 UARTs
#define ATMEL_MAX_UART		8
/*
 * We wrap our port structure around the generic uart_port.
 */
struct atmel_uart_port {
	struct uart_port	uart;		/* uart */
	struct clk		*clk;		/* uart clock */
	int			may_wakeup;	/* cached value of device_may_wakeup for times we need to disable it */
	u32			backup_imr;	/* IMR saved during suspend */
	int			break_active;	/* break being received */
	bool			use_dma_rx;	/* enable DMA receiver */
	bool			use_pdc_rx;	/* enable PDC receiver */
	short			pdc_rx_idx;	/* current PDC RX buffer */
	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */

	bool			use_dma_tx;     /* enable DMA transmitter */
	bool			use_pdc_tx;	/* enable PDC transmitter */
	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */

	spinlock_t			lock_tx;	/* port lock */
	spinlock_t			lock_rx;	/* port lock */
	struct dma_chan			*chan_tx;
	struct dma_chan			*chan_rx;
	struct dma_async_tx_descriptor	*desc_tx;
	struct dma_async_tx_descriptor	*desc_rx;
	dma_cookie_t			cookie_tx;
	dma_cookie_t			cookie_rx;
	struct scatterlist		sg_tx;
	struct scatterlist		sg_rx;
	struct tasklet_struct	tasklet_rx;
	struct tasklet_struct	tasklet_tx;
	unsigned int		irq_status_prev;

	struct circ_buf		rx_ring;
	struct mctrl_gpios	*gpios;
	u32			backup_mode;	/* MR saved during iso7816 operations */
	u32			backup_brgr;	/* BRGR saved during iso7816 operations */
	u32			fifo_size;
	u32			rts_high;
	u32			rts_low;
	u32			rtor;	/* address of receiver timeout register if it exists */
	bool			has_frac_baudrate;
	bool			has_hw_timer;
	struct timer_list	uart_timer;
	bool			suspended;
	unsigned int		pending;
	unsigned int		pending_status;
	spinlock_t		lock_suspended;

	/* ISO7816 */
	unsigned int		fidi_min;
	unsigned int		fidi_max;

	struct {
		u32		cr;
		u32		mr;
		u32		imr;
		u32		brgr;
		u32		rtor;
		u32		ttgr;
		u32		fmr;
		u32		fimr;
	} cache;
	int (*prepare_rx)(struct uart_port *port);
	int (*prepare_tx)(struct uart_port *port);
	void (*schedule_rx)(struct uart_port *port);
	void (*schedule_tx)(struct uart_port *port);
	void (*release_rx)(struct uart_port *port);
	void (*release_tx)(struct uart_port *port);
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART);
#ifdef SUPPORT_SYSRQ
static struct console atmel_console;
#if defined(CONFIG_OF)
static const struct of_device_id atmel_serial_dt_ids[] = {
	{ .compatible = "atmel,at91rm9200-usart-serial" },
static inline struct atmel_uart_port *
to_atmel_uart_port(struct uart_port *uart)
{
	return container_of(uart, struct atmel_uart_port, uart);
}

static inline u32 atmel_uart_readl(struct uart_port *port, u32 reg)
{
	return __raw_readl(port->membase + reg);
}

static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value)
{
	__raw_writel(value, port->membase + reg);
}

static inline u8 atmel_uart_read_char(struct uart_port *port)
	return __raw_readb(port->membase + ATMEL_US_RHR);
static inline void atmel_uart_write_char(struct uart_port *port, u8 value)
{
	__raw_writeb(value, port->membase + ATMEL_US_THR);
}

static inline int atmel_uart_is_half_duplex(struct uart_port *port)
{
	return ((port->rs485.flags & SER_RS485_ENABLED) &&
		!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
		(port->iso7816.flags & SER_ISO7816_ENABLED);
}

#ifdef CONFIG_SERIAL_ATMEL_PDC
static bool atmel_use_pdc_rx(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	return atmel_port->use_pdc_rx;
static bool atmel_use_pdc_tx(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	return atmel_port->use_pdc_tx;
static bool atmel_use_pdc_rx(struct uart_port *port)
static bool atmel_use_pdc_tx(struct uart_port *port)
{
	return false;
}
#endif

static bool atmel_use_dma_tx(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	return atmel_port->use_dma_tx;
}

static bool atmel_use_dma_rx(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	return atmel_port->use_dma_rx;
}

static bool atmel_use_fifo(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	return atmel_port->fifo_size;
}

static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
				   struct tasklet_struct *t)
{
	if (!atomic_read(&atmel_port->tasklet_shutdown))
		tasklet_schedule(t);
}

static unsigned int atmel_get_lines_status(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int status, ret = 0;

	status = atmel_uart_readl(port, ATMEL_US_CSR);

	mctrl_gpio_get(atmel_port->gpios, &ret);

	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
						UART_GPIO_CTS))) {
		if (ret & TIOCM_CTS)
			status &= ~ATMEL_US_CTS;
		else
			status |= ATMEL_US_CTS;
	}

	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
						UART_GPIO_DSR))) {
		if (ret & TIOCM_DSR)
			status &= ~ATMEL_US_DSR;
		else
			status |= ATMEL_US_DSR;
	}

	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
						UART_GPIO_RI))) {
		if (ret & TIOCM_RI)
			status &= ~ATMEL_US_RI;
		else
			status |= ATMEL_US_RI;
	}

	if (!IS_ERR_OR_NULL(mctrl_gpio_to_gpiod(atmel_port->gpios,
						UART_GPIO_DCD))) {
		if (ret & TIOCM_CD)
			status &= ~ATMEL_US_DCD;
		else
			status |= ATMEL_US_DCD;
	}

	return status;
}

/* Enable or disable the rs485 support */
static int atmel_config_rs485(struct uart_port *port,
			      struct serial_rs485 *rs485conf)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int mode;

	/* Disable interrupts */
	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
	mode = atmel_uart_readl(port, ATMEL_US_MR);

	/* Resetting serial mode to RS232 (0x0) */
	mode &= ~ATMEL_US_USMODE;

	port->rs485 = *rs485conf;

	if (rs485conf->flags & SER_RS485_ENABLED) {
		dev_dbg(port->dev, "Setting UART to RS485\n");
		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
		atmel_uart_writel(port, ATMEL_US_TTGR,
				  rs485conf->delay_rts_after_send);
		mode |= ATMEL_US_USMODE_RS485;
	} else {
		dev_dbg(port->dev, "Setting UART to RS232\n");
		if (atmel_use_pdc_tx(port))
			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
				ATMEL_US_TXBUFE;
		else
			atmel_port->tx_done_mask = ATMEL_US_TXRDY;
	}
	atmel_uart_writel(port, ATMEL_US_MR, mode);
	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
static unsigned int atmel_calc_cd(struct uart_port *port,
				  struct serial_iso7816 *iso7816conf)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int cd;
	u64 mck_rate;

	mck_rate = (u64)clk_get_rate(atmel_port->clk);
	do_div(mck_rate, iso7816conf->clk);
	cd = mck_rate;
	return cd;
}

static unsigned int atmel_calc_fidi(struct uart_port *port,
				    struct serial_iso7816 *iso7816conf)
{
	u64 fidi = 0;

	if (iso7816conf->sc_fi && iso7816conf->sc_di) {
		fidi = (u64)iso7816conf->sc_fi;
		do_div(fidi, iso7816conf->sc_di);
	}
	return (u32)fidi;
}

/* Enable or disable the iso7816 support */
/* Called with interrupts disabled */
static int atmel_config_iso7816(struct uart_port *port,
				struct serial_iso7816 *iso7816conf)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int mode;
	unsigned int cd, fidi;
	int ret = 0;

	/* Disable interrupts */
	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);

	mode = atmel_uart_readl(port, ATMEL_US_MR);

	if (iso7816conf->flags & SER_ISO7816_ENABLED) {
		mode &= ~ATMEL_US_USMODE;

		if (iso7816conf->tg > 255) {
			dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
			ret = -EINVAL;
			goto err_out;
		}

		if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
		    == SER_ISO7816_T(0)) {
			mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
		} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
			   == SER_ISO7816_T(1)) {
			mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
		} else {
			dev_err(port->dev, "ISO7816: Type not supported\n");
			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
			ret = -EINVAL;
			goto err_out;
		}

		mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);

		/* select mck clock, and output  */
		mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
		/* set parity for normal/inverse mode + max iterations */
		mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);

		cd = atmel_calc_cd(port, iso7816conf);
		fidi = atmel_calc_fidi(port, iso7816conf);
		if (fidi == 0) {
			dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
		} else if (fidi < atmel_port->fidi_min
			   || fidi > atmel_port->fidi_max) {
			dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
			ret = -EINVAL;
			goto err_out;
		}

		if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
			/* port not yet in iso7816 mode: store configuration */
			atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
			atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
		}

		atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
		atmel_uart_writel(port, ATMEL_US_BRGR, cd);
		atmel_uart_writel(port, ATMEL_US_FIDI, fidi);

		atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
	} else {
		dev_dbg(port->dev, "Setting UART back to RS232\n");
		/* back to last RS232 settings */
		mode = atmel_port->backup_mode;
		memset(iso7816conf, 0, sizeof(struct serial_iso7816));
		atmel_uart_writel(port, ATMEL_US_TTGR, 0);
		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
		atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);

		if (atmel_use_pdc_tx(port))
			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
						   ATMEL_US_TXBUFE;
		else
			atmel_port->tx_done_mask = ATMEL_US_TXRDY;
	}

	port->iso7816 = *iso7816conf;

	atmel_uart_writel(port, ATMEL_US_MR, mode);

err_out:
	/* Enable interrupts */
	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);

	return ret;
}

/*
 * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
 */
static u_int atmel_tx_empty(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	if (atmel_port->tx_stopped)
		return TIOCSER_TEMT;
	return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ?
		TIOCSER_TEMT :
		0;
}

/*
 * Set state of the modem control output lines
 */
static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
{
	unsigned int control = 0;
	unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR);
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	/* override mode to RS485 if needed, otherwise keep the current mode */
	if (port->rs485.flags & SER_RS485_ENABLED) {
		atmel_uart_writel(port, ATMEL_US_TTGR,
				  port->rs485.delay_rts_after_send);
		mode &= ~ATMEL_US_USMODE;
		mode |= ATMEL_US_USMODE_RS485;
	}

	/* set the RTS line state according to the mode */
	if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
		/* force RTS line to high level */
		rts_paused = ATMEL_US_RTSEN;

		/* give the control of the RTS line back to the hardware */
		rts_ready = ATMEL_US_RTSDIS;
	} else {
		/* force RTS line to high level */
		rts_paused = ATMEL_US_RTSDIS;

		/* force RTS line to low level */
		rts_ready = ATMEL_US_RTSEN;
	}

	if (mctrl & TIOCM_RTS)
		control |= ATMEL_US_DTREN;
		control |= ATMEL_US_DTRDIS;
	atmel_uart_writel(port, ATMEL_US_CR, control);
	mctrl_gpio_set(atmel_port->gpios, mctrl);

	/* Local loopback mode? */
	if (mctrl & TIOCM_LOOP)
		mode |= ATMEL_US_CHMODE_LOC_LOOP;
		mode |= ATMEL_US_CHMODE_NORMAL;
	atmel_uart_writel(port, ATMEL_US_MR, mode);
}

/*
 * Get state of the modem control input lines
 */
static u_int atmel_get_mctrl(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int ret = 0, status;
	status = atmel_uart_readl(port, ATMEL_US_CSR);

	/*
	 * The control signals are active low.
	 */
	if (!(status & ATMEL_US_DCD))
	if (!(status & ATMEL_US_CTS))
	if (!(status & ATMEL_US_DSR))
	if (!(status & ATMEL_US_RI))
	return mctrl_gpio_get(atmel_port->gpios, &ret);
static void atmel_stop_tx(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	if (atmel_use_pdc_tx(port)) {
		/* disable PDC transmit */
		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);

	/*
	 * Disable the transmitter.
	 * This is mandatory when DMA is used, otherwise the DMA buffer
	 * is fully transmitted.
	 */
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
	atmel_port->tx_stopped = true;
	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
	if (atmel_uart_is_half_duplex(port))
static void atmel_start_tx(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);

	if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
				       & ATMEL_PDC_TXTEN))
		/* The transmitter is already running.  Yes, we
		   really need this.*/
		return;
	if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
		if (atmel_uart_is_half_duplex(port))
	if (atmel_use_pdc_tx(port))
		/* re-enable PDC transmit */
		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);

	/* re-enable the transmitter */
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
	atmel_port->tx_stopped = false;
}

/*
 * start receiving - port is in process of being opened.
 */
static void atmel_start_rx(struct uart_port *port)
{
	/* reset status and receiver */
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN);
	if (atmel_use_pdc_rx(port)) {
		atmel_uart_writel(port, ATMEL_US_IER,
				  ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
				  port->read_status_mask);
		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
		atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY);
}

/*
 * Stop receiving - port is in process of being closed.
 */
static void atmel_stop_rx(struct uart_port *port)
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS);
	if (atmel_use_pdc_rx(port)) {
		/* disable PDC receive */
		atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS);
		atmel_uart_writel(port, ATMEL_US_IDR,
				  ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
				  port->read_status_mask);
		atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXRDY);
}

/*
 * Enable modem status interrupts
 */
static void atmel_enable_ms(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	uint32_t ier = 0;

	/*
	 * Interrupt should not be enabled twice
	 */
	if (atmel_port->ms_irq_enabled)
		return;

	atmel_port->ms_irq_enabled = true;

	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
	atmel_uart_writel(port, ATMEL_US_IER, ier);

	mctrl_gpio_enable_ms(atmel_port->gpios);
/*
 * Disable modem status interrupts
 */
static void atmel_disable_ms(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	uint32_t idr = 0;

	/*
	 * Interrupt should not be disabled twice
	 */
	if (!atmel_port->ms_irq_enabled)
		return;

	atmel_port->ms_irq_enabled = false;

	mctrl_gpio_disable_ms(atmel_port->gpios);

	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DSR))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_RI))
	if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_DCD))
	atmel_uart_writel(port, ATMEL_US_IDR, idr);
/*
 * Control the transmission of a break signal
 */
static void atmel_break_ctl(struct uart_port *port, int break_state)
{
	if (break_state != 0)
		/* start break */
		atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTBRK);
		/* stop break */
		atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STPBRK);
/*
 * Stores the incoming character in the ring buffer
 */
static void
atmel_buffer_rx_char(struct uart_port *port, unsigned int status,
		     unsigned int ch)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	struct circ_buf *ring = &atmel_port->rx_ring;
	struct atmel_uart_char *c;

	if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE))
		/* Buffer overflow, ignore char */
		return;

	c = &((struct atmel_uart_char *)ring->buf)[ring->head];
	c->status	= status;
	c->ch		= ch;

	/* Make sure the character is stored before we update head. */
	smp_wmb();

	ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1);
}

/*
 * Deal with parity, framing and overrun errors.
 */
static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
{
	/* clear error */
	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);

	if (status & ATMEL_US_RXBRK) {
		/* ignore side-effect */
		status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);
		port->icount.brk++;
	}
	if (status & ATMEL_US_PARE)
		port->icount.parity++;
	if (status & ATMEL_US_FRAME)
		port->icount.frame++;
	if (status & ATMEL_US_OVRE)
		port->icount.overrun++;
}

/*
 * Characters received (called from interrupt handler)
 */
static void atmel_rx_chars(struct uart_port *port)
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	unsigned int status, ch;
	status = atmel_uart_readl(port, ATMEL_US_CSR);
	while (status & ATMEL_US_RXRDY) {
		ch = atmel_uart_read_char(port);

		/*
		 * note that the error handling code is
		 * out of the main execution path
		 */
		if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
				       | ATMEL_US_OVRE | ATMEL_US_RXBRK)
			     || atmel_port->break_active)) {
			/* clear error */
			atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA);
			if (status & ATMEL_US_RXBRK
			    && !atmel_port->break_active) {
				atmel_port->break_active = 1;
				atmel_uart_writel(port, ATMEL_US_IER,
						  ATMEL_US_RXBRK);
			} else {
				/*
				 * This is either the end-of-break
				 * condition or we've received at
				 * least one character without RXBRK
				 * being set. In both cases, the next
				 * RXBRK will indicate start-of-break.
				 */
				atmel_uart_writel(port, ATMEL_US_IDR,
						  ATMEL_US_RXBRK);
				status &= ~ATMEL_US_RXBRK;
				atmel_port->break_active = 0;
		atmel_buffer_rx_char(port, status, ch);
		status = atmel_uart_readl(port, ATMEL_US_CSR);
	atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_rx);
 * Transmit characters (called from tasklet with TXRDY interrupt
 * disabled)
static void atmel_tx_chars(struct uart_port *port)
Alan Cox's avatar
Alan Cox committed
	struct circ_buf *xmit = &port->state->xmit;
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	if (port->x_char &&
	    (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) {
		atmel_uart_write_char(port, port->x_char);
		port->icount.tx++;
		port->x_char = 0;
	}
	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
	while (atmel_uart_readl(port, ATMEL_US_CSR) &
	       atmel_port->tx_done_mask) {
		atmel_uart_write_char(port, xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		port->icount.tx++;
		if (uart_circ_empty(xmit))
			break;
	}

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(port);

	if (!uart_circ_empty(xmit))
		atmel_uart_writel(port, ATMEL_US_IER,
				  atmel_port->tx_done_mask);
static void atmel_complete_tx_dma(void *arg)
{
	struct atmel_uart_port *atmel_port = arg;
	struct uart_port *port = &atmel_port->uart;
	struct circ_buf *xmit = &port->state->xmit;
	struct dma_chan *chan = atmel_port->chan_tx;
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);

	if (chan)
		dmaengine_terminate_all(chan);
	xmit->tail += atmel_port->tx_len;
	xmit->tail &= UART_XMIT_SIZE - 1;

	port->icount.tx += atmel_port->tx_len;

	spin_lock_irq(&atmel_port->lock_tx);
	async_tx_ack(atmel_port->desc_tx);
	atmel_port->cookie_tx = -EINVAL;
	atmel_port->desc_tx = NULL;
	spin_unlock_irq(&atmel_port->lock_tx);

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(port);

	/*
	 * xmit is a circular buffer so, if we have just send data from
	 * xmit->tail to the end of xmit->buf, now we have to transmit the
	 * remaining data from the beginning of xmit->buf to xmit->head.
	 */
	if (!uart_circ_empty(xmit))
		atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
	else if (atmel_uart_is_half_duplex(port)) {
		/* DMA done, stop TX, start RX for RS485 */
		atmel_start_rx(port);
	}

	spin_unlock_irqrestore(&port->lock, flags);
}

static void atmel_release_tx_dma(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	struct dma_chan *chan = atmel_port->chan_tx;

	if (chan) {
		dmaengine_terminate_all(chan);
		dma_release_channel(chan);
		dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
	}

	atmel_port->desc_tx = NULL;
	atmel_port->chan_tx = NULL;
	atmel_port->cookie_tx = -EINVAL;
}

/*
 * Called from tasklet with TXRDY interrupt is disabled.
 */
static void atmel_tx_dma(struct uart_port *port)
{
	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
	struct circ_buf *xmit = &port->state->xmit;
	struct dma_chan *chan = atmel_port->chan_tx;
	struct dma_async_tx_descriptor *desc;
	struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx;
	unsigned int tx_len, part1_len, part2_len, sg_len;
	dma_addr_t phys_addr;

	/* Make sure we have an idle channel */
	if (atmel_port->desc_tx != NULL)
		return;

	if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
		/*
		 * DMA is idle now.
		 * Port xmit buffer is already mapped,
		 * and it is one page... Just adjust
		 * offsets and lengths. Since it is a circular buffer,
		 * we have to transmit till the end, and then the rest.
		 * Take the port lock to get a
		 * consistent xmit buffer state.
		 */
		tx_len = CIRC_CNT_TO_END(xmit->head,
					 xmit->tail,
					 UART_XMIT_SIZE);

		if (atmel_port->fifo_size) {
			/* multi data mode */
			part1_len = (tx_len & ~0x3); /* DWORD access */
			part2_len = (tx_len & 0x3); /* BYTE access */
		} else {
			/* single data (legacy) mode */
			part1_len = 0;
			part2_len = tx_len; /* BYTE access only */
		}