147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer/*
247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Freescale STMP37XX/STMP378X Application UART driver
347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *
447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Author: dmitry pervushin <dimka@embeddedalley.com>
547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *
647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Copyright 2008-2010 Freescale Semiconductor, Inc.
747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *
947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * The code contained herein is licensed under the GNU General Public
1047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * License. You may obtain a copy of the GNU General Public License
1147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * Version 2 or later at the following locations:
1247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer *
1347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * http://www.opensource.org/licenses/gpl-license.html
1447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer * http://www.gnu.org/copyleft/gpl.html
1547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer */
1647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
1747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/kernel.h>
1847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/errno.h>
1947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/init.h>
2047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/console.h>
2147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/interrupt.h>
2247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/module.h>
2347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/slab.h>
2447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/wait.h>
2547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty.h>
2647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty_driver.h>
2747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/tty_flip.h>
2847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/serial.h>
2947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/serial_core.h>
3047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/platform_device.h>
3147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/device.h>
3247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/clk.h>
3347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/delay.h>
3447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <linux/io.h>
3547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
3647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#include <asm/cacheflush.h>
3747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
3847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define MXS_AUART_PORTS 5
3947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
4047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0			0x00000000
4147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_SET			0x00000004
4247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_CLR			0x00000008
4347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_TOG			0x0000000c
4447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1			0x00000010
4547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_SET			0x00000014
4647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_CLR			0x00000018
4747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL1_TOG			0x0000001c
4847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2			0x00000020
4947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_SET			0x00000024
5047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_CLR			0x00000028
5147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_TOG			0x0000002c
5247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL			0x00000030
5347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_SET		0x00000034
5447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_CLR		0x00000038
5547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_TOG		0x0000003c
5647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2			0x00000040
5747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_SET		0x00000044
5847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_CLR		0x00000048
5947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL2_TOG		0x0000004c
6047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR			0x00000050
6147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_SET			0x00000054
6247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CLR			0x00000058
6347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TOG			0x0000005c
6447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_DATA			0x00000060
6547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT			0x00000070
6647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_DEBUG			0x00000080
6747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_VERSION			0x00000090
6847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_AUTOBAUD			0x000000a0
6947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
7047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_SFTRST			(1 << 31)
7147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL0_CLKGATE			(1 << 30)
7247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
7347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_CTSEN			(1 << 15)
7447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_RTS				(1 << 11)
7547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_RXE				(1 << 9)
7647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_TXE				(1 << 8)
7747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_CTRL2_UARTEN			(1 << 0)
7847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
7947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT_SHIFT	16
8047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT_MASK		0xffff0000
8147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVINT(v)		(((v) & 0xffff) << 16)
8247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC_SHIFT	8
8347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC_MASK	0x00003f00
8447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BAUD_DIVFRAC(v)		(((v) & 0x3f) << 8)
8547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_WLEN_MASK		0x00000060
8647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_WLEN(v)			(((v) & 0x3) << 5)
8747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_FEN			(1 << 4)
8847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_STP2			(1 << 3)
8947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_EPS			(1 << 2)
9047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_PEN			(1 << 1)
9147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_LINECTRL_BRK			(1 << 0)
9247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
9347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RTIEN			(1 << 22)
9447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TXIEN			(1 << 21)
9547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RXIEN			(1 << 20)
9647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CTSMIEN			(1 << 17)
9747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RTIS				(1 << 6)
9847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_TXIS				(1 << 5)
9947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_RXIS				(1 << 4)
10047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_INTR_CTSMIS			(1 << 1)
10147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
10247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_BUSY				(1 << 29)
10347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_CTS				(1 << 28)
10447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_TXFE				(1 << 27)
10547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_TXFF				(1 << 25)
10647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_RXFE				(1 << 24)
10747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_OERR				(1 << 19)
10847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_BERR				(1 << 18)
10947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_PERR				(1 << 17)
11047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define AUART_STAT_FERR				(1 << 16)
11147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
11247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_driver auart_driver;
11347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
11447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstruct mxs_auart_port {
11547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct uart_port port;
11647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
11747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int flags;
11847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int ctrl;
11947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
12047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int irq;
12147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
12247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct clk *clk;
12347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct device *dev;
12447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer};
12547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
12647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_tx(struct uart_port *u);
12747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
12847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#define to_auart_port(u) container_of(u, struct mxs_auart_port, port)
12947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
13047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic inline void mxs_auart_tx_chars(struct mxs_auart_port *s)
13147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
13247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct circ_buf *xmit = &s->port.state->xmit;
13347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
13447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	while (!(readl(s->port.membase + AUART_STAT) &
13547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		 AUART_STAT_TXFF)) {
13647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (s->port.x_char) {
13747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			s->port.icount.tx++;
13847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			writel(s->port.x_char,
13947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				     s->port.membase + AUART_DATA);
14047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			s->port.x_char = 0;
14147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			continue;
14247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		}
14347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
14447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			s->port.icount.tx++;
14547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			writel(xmit->buf[xmit->tail],
14647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				     s->port.membase + AUART_DATA);
14747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
14847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		} else
14947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			break;
15047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
151d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
152d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König		uart_write_wakeup(&s->port);
153d0758a285caaf86192cdb22136a5eb84ed72f276Uwe Kleine-König
15447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (uart_circ_empty(&(s->port.state->xmit)))
15547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		writel(AUART_INTR_TXIEN,
15647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			     s->port.membase + AUART_INTR_CLR);
15747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
15847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		writel(AUART_INTR_TXIEN,
15947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			     s->port.membase + AUART_INTR_SET);
16047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
16147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (uart_tx_stopped(&s->port))
16247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mxs_auart_stop_tx(&s->port);
16347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
16447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
16547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_rx_char(struct mxs_auart_port *s)
16647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
16747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int flag;
16847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 stat;
16947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u8 c;
17047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
17147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	c = readl(s->port.membase + AUART_DATA);
17247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	stat = readl(s->port.membase + AUART_STAT);
17347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
17447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	flag = TTY_NORMAL;
17547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.icount.rx++;
17647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
17747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (stat & AUART_STAT_BERR) {
17847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		s->port.icount.brk++;
17947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (uart_handle_break(&s->port))
18047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			goto out;
18147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	} else if (stat & AUART_STAT_PERR) {
18247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		s->port.icount.parity++;
18347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	} else if (stat & AUART_STAT_FERR) {
18447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		s->port.icount.frame++;
18547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
18647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
18747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
18847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * Mask off conditions which should be ingored.
18947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
19047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	stat &= s->port.read_status_mask;
19147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
19247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (stat & AUART_STAT_BERR) {
19347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		flag = TTY_BREAK;
19447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	} else if (stat & AUART_STAT_PERR)
19547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		flag = TTY_PARITY;
19647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else if (stat & AUART_STAT_FERR)
19747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		flag = TTY_FRAME;
19847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
19947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (stat & AUART_STAT_OERR)
20047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		s->port.icount.overrun++;
20147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
20247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (uart_handle_sysrq_char(&s->port, c))
20347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out;
20447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
20547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	uart_insert_char(&s->port, stat, AUART_STAT_OERR, c, flag);
20647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout:
20747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(stat, s->port.membase + AUART_STAT);
20847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
20947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
21047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_rx_chars(struct mxs_auart_port *s)
21147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
21247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct tty_struct *tty = s->port.state->port.tty;
21347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 stat = 0;
21447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
21547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	for (;;) {
21647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		stat = readl(s->port.membase + AUART_STAT);
21747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (stat & AUART_STAT_RXFE)
21847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			break;
21947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mxs_auart_rx_char(s);
22047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
22147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
22247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(stat, s->port.membase + AUART_STAT);
22347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	tty_flip_buffer_push(tty);
22447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
22547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
22647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_request_port(struct uart_port *u)
22747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
22847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
22947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
23047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
23147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_verify_port(struct uart_port *u,
23247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				    struct serial_struct *ser)
23347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
23447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (u->type != PORT_UNKNOWN && u->type != PORT_IMX)
23547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return -EINVAL;
23647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
23747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
23847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
23947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_config_port(struct uart_port *u, int flags)
24047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
24147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
24247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
24347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic const char *mxs_auart_type(struct uart_port *u)
24447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
24547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
24647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
24747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return dev_name(s->dev);
24847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
24947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
25047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_release_port(struct uart_port *u)
25147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
25247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
25347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
25447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
25547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
25647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
25747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
25847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 ctrl = readl(u->membase + AUART_CTRL2);
25947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
26047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl &= ~AUART_CTRL2_RTS;
26147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (mctrl & TIOCM_RTS)
26247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl |= AUART_CTRL2_RTS;
26347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->ctrl = mctrl;
26447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(ctrl, u->membase + AUART_CTRL2);
26547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
26647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
26747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic u32 mxs_auart_get_mctrl(struct uart_port *u)
26847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
26947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
27047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 stat = readl(u->membase + AUART_STAT);
27147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int ctrl2 = readl(u->membase + AUART_CTRL2);
27247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 mctrl = s->ctrl;
27347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
27447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	mctrl &= ~TIOCM_CTS;
27547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (stat & AUART_STAT_CTS)
27647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mctrl |= TIOCM_CTS;
27747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
27847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (ctrl2 & AUART_CTRL2_RTS)
27947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mctrl |= TIOCM_RTS;
28047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
28147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return mctrl;
28247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
28347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
28447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_settermios(struct uart_port *u,
28547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				 struct ktermios *termios,
28647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				 struct ktermios *old)
28747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
28847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 bm, ctrl, ctrl2, div;
28947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int cflag, baud;
29047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
29147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	cflag = termios->c_cflag;
29247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
29347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl = AUART_LINECTRL_FEN;
29447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl2 = readl(u->membase + AUART_CTRL2);
29547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
29647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* byte size */
29747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	switch (cflag & CSIZE) {
29847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	case CS5:
29947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		bm = 0;
30047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		break;
30147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	case CS6:
30247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		bm = 1;
30347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		break;
30447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	case CS7:
30547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		bm = 2;
30647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		break;
30747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	case CS8:
30847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		bm = 3;
30947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		break;
31047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	default:
31147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return;
31247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
31347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
31447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl |= AUART_LINECTRL_WLEN(bm);
31547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
31647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* parity */
31747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (cflag & PARENB) {
31847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl |= AUART_LINECTRL_PEN;
31947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if ((cflag & PARODD) == 0)
32047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			ctrl |= AUART_LINECTRL_EPS;
32147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
32247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
32347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u->read_status_mask = 0;
32447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
32547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (termios->c_iflag & INPCK)
32647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		u->read_status_mask |= AUART_STAT_PERR;
32747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (termios->c_iflag & (BRKINT | PARMRK))
32847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		u->read_status_mask |= AUART_STAT_BERR;
32947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
33047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
33147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * Characters to ignore
33247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
33347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u->ignore_status_mask = 0;
33447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (termios->c_iflag & IGNPAR)
33547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		u->ignore_status_mask |= AUART_STAT_PERR;
33647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (termios->c_iflag & IGNBRK) {
33747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		u->ignore_status_mask |= AUART_STAT_BERR;
33847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		/*
33947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		 * If we're ignoring parity and break indicators,
34047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		 * ignore overruns too (for real raw support).
34147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		 */
34247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (termios->c_iflag & IGNPAR)
34347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			u->ignore_status_mask |= AUART_STAT_OERR;
34447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
34547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
34647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
34747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * ignore all characters if CREAD is not set
34847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
34947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (cflag & CREAD)
35047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl2 |= AUART_CTRL2_RXE;
35147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
35247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl2 &= ~AUART_CTRL2_RXE;
35347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
35447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* figure out the stop bits requested */
35547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (cflag & CSTOPB)
35647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl |= AUART_LINECTRL_STP2;
35747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
35847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* figure out the hardware flow control settings */
35947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (cflag & CRTSCTS)
36047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl2 |= AUART_CTRL2_CTSEN;
36147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
36247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ctrl2 &= ~AUART_CTRL2_CTSEN;
36347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
36447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* set baud rate */
36547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
36647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	div = u->uartclk * 32 / baud;
36747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F);
36847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6);
36947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
37047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(ctrl, u->membase + AUART_LINECTRL);
37147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(ctrl2, u->membase + AUART_CTRL2);
3722fa8ba3d8d0f49c4b087a026889a1154c3d94901Lothar Waßmann
3732fa8ba3d8d0f49c4b087a026889a1154c3d94901Lothar Waßmann	uart_update_timeout(u, termios->c_cflag, baud);
37447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
37547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
37647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic irqreturn_t mxs_auart_irq_handle(int irq, void *context)
37747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
37847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 istatus, istat;
37947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = context;
38047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 stat = readl(s->port.membase + AUART_STAT);
38147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
38247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	istatus = istat = readl(s->port.membase + AUART_INTR);
38347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
38447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (istat & AUART_INTR_CTSMIS) {
38547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
38647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		writel(AUART_INTR_CTSMIS,
38747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				s->port.membase + AUART_INTR_CLR);
38847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		istat &= ~AUART_INTR_CTSMIS;
38947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
39047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
39147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (istat & (AUART_INTR_RTIS | AUART_INTR_RXIS)) {
39247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mxs_auart_rx_chars(s);
39347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		istat &= ~(AUART_INTR_RTIS | AUART_INTR_RXIS);
39447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
39547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
39647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (istat & AUART_INTR_TXIS) {
39747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		mxs_auart_tx_chars(s);
39847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		istat &= ~AUART_INTR_TXIS;
39947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
40047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
40147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(istatus & (AUART_INTR_RTIS
40247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		| AUART_INTR_TXIS
40347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		| AUART_INTR_RXIS
40447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		| AUART_INTR_CTSMIS),
40547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			s->port.membase + AUART_INTR_CLR);
40647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
40747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return IRQ_HANDLED;
40847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
40947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
41047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_reset(struct uart_port *u)
41147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
41247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int i;
41347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int reg;
41447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
41547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_CLR);
41647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
41747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	for (i = 0; i < 10000; i++) {
41847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		reg = readl(u->membase + AUART_CTRL0);
41947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (!(reg & AUART_CTRL0_SFTRST))
42047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			break;
42147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		udelay(3);
42247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
42347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
42447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
42547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
42647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int mxs_auart_startup(struct uart_port *u)
42747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
42847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
42947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
430a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo	clk_prepare_enable(s->clk);
43147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
43247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
43347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
43447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET);
43547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
43647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
43747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			u->membase + AUART_INTR);
43847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
43947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
44047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * Enable fifo so all four bytes of a DMA word are written to
44147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * output (otherwise, only the LSB is written, ie. 1 in 4 bytes)
44247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
44347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_LINECTRL_FEN, u->membase + AUART_LINECTRL_SET);
44447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
44547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
44647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
44747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
44847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_shutdown(struct uart_port *u)
44947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
45047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
45147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
45247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR);
45347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
45447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET);
45547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
45647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN,
45747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			u->membase + AUART_INTR_CLR);
45847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
459a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo	clk_disable_unprepare(s->clk);
46047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
46147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
46247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic unsigned int mxs_auart_tx_empty(struct uart_port *u)
46347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
46447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (readl(u->membase + AUART_STAT) & AUART_STAT_TXFE)
46547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return TIOCSER_TEMT;
46647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
46747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return 0;
46847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
46947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
47047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_start_tx(struct uart_port *u)
47147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
47247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = to_auart_port(u);
47347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
47447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* enable transmitter */
47547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_SET);
47647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
47747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	mxs_auart_tx_chars(s);
47847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
47947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
48047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_tx(struct uart_port *u)
48147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
48247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_TXE, u->membase + AUART_CTRL2_CLR);
48347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
48447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
48547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_stop_rx(struct uart_port *u)
48647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
48747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_RXE, u->membase + AUART_CTRL2_CLR);
48847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
48947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
49047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_break_ctl(struct uart_port *u, int ctl)
49147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
49247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (ctl)
49347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		writel(AUART_LINECTRL_BRK,
49447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			     u->membase + AUART_LINECTRL_SET);
49547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
49647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		writel(AUART_LINECTRL_BRK,
49747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			     u->membase + AUART_LINECTRL_CLR);
49847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
49947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
50047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_enable_ms(struct uart_port *port)
50147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
50247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* just empty */
50347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
50447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
50547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_ops mxs_auart_ops = {
50647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.tx_empty       = mxs_auart_tx_empty,
50747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.start_tx       = mxs_auart_start_tx,
50847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.stop_tx	= mxs_auart_stop_tx,
50947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.stop_rx	= mxs_auart_stop_rx,
51047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.enable_ms      = mxs_auart_enable_ms,
51147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.break_ctl      = mxs_auart_break_ctl,
51247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.set_mctrl	= mxs_auart_set_mctrl,
51347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.get_mctrl      = mxs_auart_get_mctrl,
51447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.startup	= mxs_auart_startup,
51547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.shutdown       = mxs_auart_shutdown,
51647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.set_termios    = mxs_auart_settermios,
51747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.type	   	= mxs_auart_type,
51847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.release_port   = mxs_auart_release_port,
51947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.request_port   = mxs_auart_request_port,
52047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.config_port    = mxs_auart_config_port,
52147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.verify_port    = mxs_auart_verify_port,
52247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer};
52347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
52447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct mxs_auart_port *auart_port[MXS_AUART_PORTS];
52547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
52647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
52747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void mxs_auart_console_putchar(struct uart_port *port, int ch)
52847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
52947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int to = 1000;
53047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
53147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	while (readl(port->membase + AUART_STAT) & AUART_STAT_TXFF) {
53247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (!to--)
53347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			break;
53447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		udelay(1);
53547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
53647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
53747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(ch, port->membase + AUART_DATA);
53847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
53947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
54047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void
54147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_write(struct console *co, const char *str, unsigned int count)
54247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
54347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s;
54447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct uart_port *port;
54547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int old_ctrl0, old_ctrl2;
54647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int to = 1000;
54747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
54847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (co->index >	MXS_AUART_PORTS || co->index < 0)
54947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return;
55047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
55147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s = auart_port[co->index];
55247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	port = &s->port;
55347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
55447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	clk_enable(s->clk);
55547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
55647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/* First save the CR then disable the interrupts */
55747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	old_ctrl2 = readl(port->membase + AUART_CTRL2);
55847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	old_ctrl0 = readl(port->membase + AUART_CTRL0);
55947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
56047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL0_CLKGATE,
56147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		     port->membase + AUART_CTRL0_CLR);
56247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(AUART_CTRL2_UARTEN | AUART_CTRL2_TXE,
56347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		     port->membase + AUART_CTRL2_SET);
56447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
56547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	uart_console_write(port, str, count, mxs_auart_console_putchar);
56647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
56747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
56847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * Finally, wait for transmitter to become empty
56947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * and restore the TCR
57047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
57147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
57247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (!to--)
57347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			break;
57447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		udelay(1);
57547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
57647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
57747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(old_ctrl0, port->membase + AUART_CTRL0);
57847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	writel(old_ctrl2, port->membase + AUART_CTRL2);
57947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
58047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	clk_disable(s->clk);
58147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
58247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
58347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void __init
58447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_get_options(struct uart_port *port, int *baud,
58547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			  int *parity, int *bits)
58647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
58747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	unsigned int lcr_h, quot;
58847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
58947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (!(readl(port->membase + AUART_CTRL2) & AUART_CTRL2_UARTEN))
59047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return;
59147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
59247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	lcr_h = readl(port->membase + AUART_LINECTRL);
59347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
59447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	*parity = 'n';
59547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (lcr_h & AUART_LINECTRL_PEN) {
59647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		if (lcr_h & AUART_LINECTRL_EPS)
59747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			*parity = 'e';
59847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		else
59947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			*parity = 'o';
60047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
60147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
60247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if ((lcr_h & AUART_LINECTRL_WLEN_MASK) == AUART_LINECTRL_WLEN(2))
60347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		*bits = 7;
60447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
60547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		*bits = 8;
60647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
60747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	quot = ((readl(port->membase + AUART_LINECTRL)
60847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			& AUART_LINECTRL_BAUD_DIVINT_MASK))
60947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			    >> (AUART_LINECTRL_BAUD_DIVINT_SHIFT - 6);
61047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	quot |= ((readl(port->membase + AUART_LINECTRL)
61147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer			& AUART_LINECTRL_BAUD_DIVFRAC_MASK))
61247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer				>> AUART_LINECTRL_BAUD_DIVFRAC_SHIFT;
61347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (quot == 0)
61447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		quot = 1;
61547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
61647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	*baud = (port->uartclk << 2) / quot;
61747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
61847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
61947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __init
62047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerauart_console_setup(struct console *co, char *options)
62147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
62247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s;
62347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int baud = 9600;
62447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int bits = 8;
62547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int parity = 'n';
62647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int flow = 'n';
62747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int ret;
62847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
62947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	/*
63047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * Check whether an invalid uart number has been specified, and
63147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * if so, search for the first available port that does have
63247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 * console support.
63347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	 */
63447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (co->index == -1 || co->index >= ARRAY_SIZE(auart_port))
63547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		co->index = 0;
63647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s = auart_port[co->index];
63747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (!s)
63847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		return -ENODEV;
63947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
640a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo	clk_prepare_enable(s->clk);
64147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
64247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (options)
64347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		uart_parse_options(options, &baud, &parity, &bits, &flow);
64447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	else
64547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		auart_console_get_options(&s->port, &baud, &parity, &bits);
64647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
64747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ret = uart_set_options(&s->port, co, baud, parity, bits, flow);
64847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
649a481377013c1c07dac0421886db7a6b4c3081c49Shawn Guo	clk_disable_unprepare(s->clk);
65047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
65147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return ret;
65247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
65347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
65447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct console auart_console = {
65547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.name		= "ttyAPP",
65647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.write		= auart_console_write,
65747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.device		= uart_console_device,
65847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.setup		= auart_console_setup,
65947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.flags		= CON_PRINTBUFFER,
66047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.index		= -1,
66147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.data		= &auart_driver,
66247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer};
66347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#endif
66447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
66547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct uart_driver auart_driver = {
66647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.owner		= THIS_MODULE,
66747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.driver_name	= "ttyAPP",
66847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.dev_name	= "ttyAPP",
66947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.major		= 0,
67047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.minor		= 0,
67147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.nr		= MXS_AUART_PORTS,
67247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#ifdef CONFIG_SERIAL_MXS_AUART_CONSOLE
67347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.cons =		&auart_console,
67447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer#endif
67547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer};
67647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
67747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __devinit mxs_auart_probe(struct platform_device *pdev)
67847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
67947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s;
68047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	u32 version;
68147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int ret = 0;
68247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct resource *r;
68347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
68447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
68547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (!s) {
68647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ret = -ENOMEM;
68747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out;
68847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
68947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
69047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->clk = clk_get(&pdev->dev, NULL);
69147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (IS_ERR(s->clk)) {
69247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ret = PTR_ERR(s->clk);
69347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out_free;
69447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
69547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
69647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
69747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (!r) {
69847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		ret = -ENXIO;
69947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out_free_clk;
70047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	}
70147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
70247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.mapbase = r->start;
70347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.membase = ioremap(r->start, resource_size(r));
70447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.ops = &mxs_auart_ops;
70547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.iotype = UPIO_MEM;
70647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.line = pdev->id < 0 ? 0 : pdev->id;
70747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.fifosize = 16;
70847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.uartclk = clk_get_rate(s->clk);
70947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.type = PORT_IMX;
71047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.dev = s->dev = get_device(&pdev->dev);
71147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
71247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->flags = 0;
71347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->ctrl = 0;
71447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
71547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->irq = platform_get_irq(pdev, 0);
71647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	s->port.irq = s->irq;
71747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
71847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (ret)
71947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out_free_clk;
72047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
72147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	platform_set_drvdata(pdev, s);
72247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
72347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	auart_port[pdev->id] = s;
72447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
72547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	mxs_auart_reset(&s->port);
72647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
72747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	ret = uart_add_one_port(&auart_driver, &s->port);
72847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (ret)
72947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out_free_irq;
73047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
73147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	version = readl(s->port.membase + AUART_VERSION);
73247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	dev_info(&pdev->dev, "Found APPUART %d.%d.%d\n",
73347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	       (version >> 24) & 0xff,
73447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	       (version >> 16) & 0xff, version & 0xffff);
73547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
73647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
73747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
73847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free_irq:
73947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	auart_port[pdev->id] = NULL;
74047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	free_irq(s->irq, s);
74147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free_clk:
74247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	clk_put(s->clk);
74347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_free:
74447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	kfree(s);
74547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout:
74647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return ret;
74747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
74847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
74947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __devexit mxs_auart_remove(struct platform_device *pdev)
75047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
75147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	struct mxs_auart_port *s = platform_get_drvdata(pdev);
75247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
75347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	uart_remove_one_port(&auart_driver, &s->port);
75447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
75547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	auart_port[pdev->id] = NULL;
75647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
75747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	clk_put(s->clk);
75847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	free_irq(s->irq, s);
75947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	kfree(s);
76047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
76147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
76247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
76347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
76447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic struct platform_driver mxs_auart_driver = {
76547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.probe = mxs_auart_probe,
76647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.remove = __devexit_p(mxs_auart_remove),
76747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	.driver = {
76847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		.name = "mxs-auart",
76947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		.owner = THIS_MODULE,
77047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	},
77147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer};
77247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
77347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic int __init mxs_auart_init(void)
77447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
77547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	int r;
77647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
77747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	r = uart_register_driver(&auart_driver);
77847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (r)
77947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out;
78047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
78147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	r = platform_driver_register(&mxs_auart_driver);
78247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	if (r)
78347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer		goto out_err;
78447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
78547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return 0;
78647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout_err:
78747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	uart_unregister_driver(&auart_driver);
78847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerout:
78947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	return r;
79047d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
79147d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
79247d37d6f94ccf32d302492f969209930b2411f9eSascha Hauerstatic void __exit mxs_auart_exit(void)
79347d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer{
79447d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	platform_driver_unregister(&mxs_auart_driver);
79547d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer	uart_unregister_driver(&auart_driver);
79647d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer}
79747d37d6f94ccf32d302492f969209930b2411f9eSascha Hauer
79847d37d6f94ccf32d302492f969209930b2411f9eSascha Hauermodule_init(mxs_auart_init);
79947d37d6f94ccf32d302492f969209930b2411f9eSascha Hauermodule_exit(mxs_auart_exit);
80047d37d6f94ccf32d302492f969209930b2411f9eSascha HauerMODULE_LICENSE("GPL");
80147d37d6f94ccf32d302492f969209930b2411f9eSascha HauerMODULE_DESCRIPTION("Freescale MXS application uart driver");
802