12f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin/*
22f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
32f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin *
42f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * This program is free software; you can redistribute it and/or modify it
52f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * under the terms of the GNU General Public License version 2 as published
62f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * by the Free Software Foundation.
72f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin *
82f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * This program is distributed in the hope that it will be useful,
92f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * but WITHOUT ANY WARRANTY; without even the implied warranty of
102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * GNU General Public License for more details.
122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin *
132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * You should have received a copy of the GNU General Public License
142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * along with this program; if not, write to the Free Software
152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin *
172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * Copyright (C) 2004 Infineon IFAP DC COM CPE
182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com>
212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin */
222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/slab.h>
242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/module.h>
252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/ioport.h>
262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/init.h>
272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/console.h>
282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/sysrq.h>
292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/device.h>
302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/tty.h>
312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/tty_flip.h>
322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/serial_core.h>
332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/serial.h>
342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/platform_device.h>
352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/io.h>
362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <linux/clk.h>
372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#include <lantiq_soc.h>
392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define PORT_LTQ_ASC		111
412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define MAXPORTS		2
422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define UART_DUMMY_UER_RX	1
432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define DRVNAME			"ltq_asc"
442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#ifdef __BIG_ENDIAN
452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_TBUF		(0x0020 + 3)
462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_RBUF		(0x0024 + 3)
472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#else
482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_TBUF		0x0020
492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_RBUF		0x0024
502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#endif
512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_FSTAT		0x0048
522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_WHBSTATE	0x0018
532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_STATE		0x0014
542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_IRNCR		0x00F8
552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_CLC		0x0000
562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_ID		0x0008
572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_PISEL		0x0004
582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_TXFCON		0x0044
592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_RXFCON		0x0040
602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_CON		0x0010
612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_BG		0x0050
622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define LTQ_ASC_IRNREN		0x00F4
632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNREN_TX		0x1
652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNREN_RX		0x2
662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNREN_ERR		0x4
672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNREN_TX_BUF	0x8
682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNCR_TIR		0x1
692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNCR_RIR		0x2
702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASC_IRNCR_EIR		0x4
712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCOPT_CSIZE		0x3
732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define TXFIFO_FL		1
742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define RXFIFO_FL		1
752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCLC_DISS		0x2
762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCLC_RMCMASK		0x0000FF00
772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCLC_RMCOFFSET	8
782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_M_8ASYNC		0x0
792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_M_7ASYNC		0x2
802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_ODD		0x00000020
812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_STP		0x00000080
822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_BRS		0x00000100
832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_FDE		0x00000200
842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_R		0x00008000
852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_FEN		0x00020000
862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_ROEN		0x00080000
872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCCON_TOEN		0x00100000
882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCSTATE_PE		0x00010000
892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCSTATE_FE		0x00020000
902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCSTATE_ROE		0x00080000
912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCSTATE_ANY		(ASCSTATE_ROE|ASCSTATE_PE|ASCSTATE_FE)
922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCWHBSTATE_CLRREN	0x00000001
932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCWHBSTATE_SETREN	0x00000002
942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCWHBSTATE_CLRPE	0x00000004
952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCWHBSTATE_CLRFE	0x00000008
962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCWHBSTATE_CLRROE	0x00000020
972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCTXFCON_TXFEN		0x0001
982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCTXFCON_TXFFLU	0x0002
992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCTXFCON_TXFITLMASK	0x3F00
1002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCTXFCON_TXFITLOFF	8
1012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCRXFCON_RXFEN		0x0001
1022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCRXFCON_RXFFLU	0x0002
1032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCRXFCON_RXFITLMASK	0x3F00
1042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCRXFCON_RXFITLOFF	8
1052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCFSTAT_RXFFLMASK	0x003F
1062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCFSTAT_TXFFLMASK	0x3F00
1072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCFSTAT_TXFREEMASK	0x3F000000
1082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin#define ASCFSTAT_TXFREEOFF	24
1092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void lqasc_tx_chars(struct uart_port *port);
1112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct ltq_uart_port *lqasc_port[MAXPORTS];
1122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct uart_driver lqasc_reg;
1132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic DEFINE_SPINLOCK(ltq_asc_lock);
1142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstruct ltq_uart_port {
1162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port	port;
1172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct clk		*clk;
1182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int		tx_irq;
1192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int		rx_irq;
1202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int		err_irq;
1212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin};
1222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic inline struct
1242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinltq_uart_port *to_ltq_uart_port(struct uart_port *port)
1252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return container_of(port, struct ltq_uart_port, port);
1272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
1282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
1302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_stop_tx(struct uart_port *port)
1312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return;
1332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
1342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
1362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_start_tx(struct uart_port *port)
1372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
1392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
1402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	lqasc_tx_chars(port);
1412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
1422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return;
1432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
1442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
1462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_stop_rx(struct uart_port *port)
1472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE);
1492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
1502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
1522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_enable_ms(struct uart_port *port)
1532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
1552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int
1572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_rx_chars(struct uart_port *port)
1582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
1592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct tty_struct *tty = tty_port_tty_get(&port->state->port);
1602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int ch = 0, rsr = 0, fifocnt;
1612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!tty) {
1632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		dev_dbg(port->dev, "%s:tty is busy now", __func__);
1642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -EBUSY;
1652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
1662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	fifocnt =
1672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
1682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	while (fifocnt--) {
1692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		u8 flag = TTY_NORMAL;
1702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
1712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
1722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
1732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		tty_flip_buffer_push(tty);
1742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->icount.rx++;
1752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		/*
1772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 * Note that the error handling code is
1782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 * out of the main execution path
1792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 */
1802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (rsr & ASCSTATE_ANY) {
1812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			if (rsr & ASCSTATE_PE) {
1822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				port->icount.parity++;
1832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				ltq_w32_mask(0, ASCWHBSTATE_CLRPE,
1842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin					port->membase + LTQ_ASC_WHBSTATE);
1852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			} else if (rsr & ASCSTATE_FE) {
1862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				port->icount.frame++;
1872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				ltq_w32_mask(0, ASCWHBSTATE_CLRFE,
1882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin					port->membase + LTQ_ASC_WHBSTATE);
1892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			}
1902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			if (rsr & ASCSTATE_ROE) {
1912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				port->icount.overrun++;
1922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				ltq_w32_mask(0, ASCWHBSTATE_CLRROE,
1932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin					port->membase + LTQ_ASC_WHBSTATE);
1942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			}
1952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			rsr &= port->read_status_mask;
1972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
1982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			if (rsr & ASCSTATE_PE)
1992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				flag = TTY_PARITY;
2002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			else if (rsr & ASCSTATE_FE)
2012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin				flag = TTY_FRAME;
2022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		}
2032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if ((rsr & port->ignore_status_mask) == 0)
2052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			tty_insert_flip_char(tty, ch, flag);
2062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (rsr & ASCSTATE_ROE)
2082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			/*
2092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			 * Overrun is special, since it's reported
2102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			 * immediately, and doesn't affect the current
2112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			 * character
2122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			 */
2132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
2142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
2152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ch != 0)
2162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		tty_flip_buffer_push(tty);
2172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	tty_kref_put(tty);
2182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return 0;
2192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
2222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_tx_chars(struct uart_port *port)
2232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
2242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct circ_buf *xmit = &port->state->xmit;
2252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (uart_tx_stopped(port)) {
2262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		lqasc_stop_tx(port);
2272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return;
2282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
2292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) &
2312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) {
2322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (port->x_char) {
2332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF);
2342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			port->icount.tx++;
2352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			port->x_char = 0;
2362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			continue;
2372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		}
2382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (uart_circ_empty(xmit))
2402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			break;
2412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ltq_w8(port->state->xmit.buf[port->state->xmit.tail],
2432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			port->membase + LTQ_ASC_TBUF);
2442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
2452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->icount.tx++;
2462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
2472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
2492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		uart_write_wakeup(port);
2502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic irqreturn_t
2532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_tx_int(int irq, void *_port)
2542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
2552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
2562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port = (struct uart_port *)_port;
2572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
2582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR);
2592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
2602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	lqasc_start_tx(port);
2612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return IRQ_HANDLED;
2622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic irqreturn_t
2652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_err_int(int irq, void *_port)
2662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
2672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
2682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port = (struct uart_port *)_port;
2692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
2702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* clear any pending interrupts */
2712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
2722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
2732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
2742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return IRQ_HANDLED;
2752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic irqreturn_t
2782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_rx_int(int irq, void *_port)
2792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
2802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
2812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port = (struct uart_port *)_port;
2822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
2832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR);
2842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	lqasc_rx_chars(port);
2852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
2862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return IRQ_HANDLED;
2872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic unsigned int
2902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_tx_empty(struct uart_port *port)
2912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
2922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int status;
2932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK;
2942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return status ? 0 : TIOCSER_TEMT;
2952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
2962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
2972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic unsigned int
2982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_get_mctrl(struct uart_port *port)
2992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR;
3012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
3022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
3042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_set_mctrl(struct uart_port *port, u_int mctrl)
3052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
3072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
3092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_break_ctl(struct uart_port *port, int break_state)
3102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
3122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int
3142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_startup(struct uart_port *port)
3152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
3172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int retval;
3182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->uartclk = clk_get_rate(ltq_port->clk);
3202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET),
3222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_CLC);
3232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(0, port->membase + LTQ_ASC_PISEL);
3252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(
3262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) |
3272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU,
3282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_TXFCON);
3292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(
3302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK)
3312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		| ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU,
3322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_RXFCON);
3332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* make sure other settings are written to hardware before
3342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	 * setting enable bits
3352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	 */
3362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	wmb();
3372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN |
3382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ASCCON_ROEN, port->membase + LTQ_ASC_CON);
3392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	retval = request_irq(ltq_port->tx_irq, lqasc_tx_int,
3419cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang		0, "asc_tx", port);
3422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (retval) {
3432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		pr_err("failed to request lqasc_tx_int\n");
3442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return retval;
3452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
3462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	retval = request_irq(ltq_port->rx_irq, lqasc_rx_int,
3489cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang		0, "asc_rx", port);
3492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (retval) {
3502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		pr_err("failed to request lqasc_rx_int\n");
3512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		goto err1;
3522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
3532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	retval = request_irq(ltq_port->err_irq, lqasc_err_int,
3559cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang		0, "asc_err", port);
3562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (retval) {
3572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		pr_err("failed to request lqasc_err_int\n");
3582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		goto err2;
3592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
3602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX,
3622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_IRNREN);
3632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return 0;
3642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinerr2:
3662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	free_irq(ltq_port->rx_irq, port);
3672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinerr1:
3682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	free_irq(ltq_port->tx_irq, port);
3692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return retval;
3702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
3712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
3732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_shutdown(struct uart_port *port)
3742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
3762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	free_irq(ltq_port->tx_irq, port);
3772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	free_irq(ltq_port->rx_irq, port);
3782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	free_irq(ltq_port->err_irq, port);
3792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(0, port->membase + LTQ_ASC_CON);
3812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU,
3822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_RXFCON);
3832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU,
3842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase + LTQ_ASC_TXFCON);
3852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
3862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
3882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_set_termios(struct uart_port *port,
3892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ktermios *new, struct ktermios *old)
3902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
3912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int cflag;
3922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int iflag;
3932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int divisor;
3942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int baud;
3952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned int con = 0;
3962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
3972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
3982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	cflag = new->c_cflag;
3992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	iflag = new->c_iflag;
4002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	switch (cflag & CSIZE) {
4022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	case CS7:
4032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		con = ASCCON_M_7ASYNC;
4042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		break;
4052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	case CS5:
4072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	case CS6:
4082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	default:
4092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		new->c_cflag &= ~ CSIZE;
4102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		new->c_cflag |= CS8;
4112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		con = ASCCON_M_8ASYNC;
4122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		break;
4132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
4142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
4162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (cflag & CSTOPB)
4182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		con |= ASCCON_STP;
4192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (cflag & PARENB) {
4212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (!(cflag & PARODD))
4222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			con &= ~ASCCON_ODD;
4232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		else
4242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			con |= ASCCON_ODD;
4252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
4262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->read_status_mask = ASCSTATE_ROE;
4282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (iflag & INPCK)
4292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
4302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->ignore_status_mask = 0;
4322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (iflag & IGNPAR)
4332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE;
4342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (iflag & IGNBRK) {
4362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		/*
4372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 * If we're ignoring parity and break indicators,
4382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 * ignore overruns too (for real raw support).
4392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		 */
4402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (iflag & IGNPAR)
4412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			port->ignore_status_mask |= ASCSTATE_ROE;
4422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
4432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if ((cflag & CREAD) == 0)
4452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->ignore_status_mask |= UART_DUMMY_UER_RX;
4462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* set error signals  - framing, parity  and overrun, enable receiver */
4482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN;
4492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
4512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* set up CON */
4532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON);
4542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* Set baud rate - take a divider of 2 into account */
4562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
4572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	divisor = uart_get_divisor(port, baud);
4582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	divisor = divisor / 2 - 1;
4592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* disable the baudrate generator */
4612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON);
4622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* make sure the fractional divider is off */
4642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON);
4652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* set up to use divisor of 2 */
4672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON);
4682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* now we can write the new baudrate into the register */
4702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(divisor, port->membase + LTQ_ASC_BG);
4712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* turn the baudrate generator back on */
4732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON);
4742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* enable rx */
4762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE);
4772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
4792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	/* Don't rewrite B0 */
481b7867f1bfcb76c75d98d35f576fcd9d7759a96feJohn Crispin	if (tty_termios_baud_rate(new))
4822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		tty_termios_encode_baud_rate(new, baud, baud);
483b7867f1bfcb76c75d98d35f576fcd9d7759a96feJohn Crispin
484b7867f1bfcb76c75d98d35f576fcd9d7759a96feJohn Crispin	uart_update_timeout(port, cflag, baud);
4852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
4862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic const char*
4882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_type(struct uart_port *port)
4892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
4902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (port->type == PORT_LTQ_ASC)
4912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return DRVNAME;
4922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	else
4932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return NULL;
4942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
4952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
4962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
4972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_release_port(struct uart_port *port)
4982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
4992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (port->flags & UPF_IOREMAP) {
5002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		iounmap(port->membase);
5012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase = NULL;
5022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
5032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
5042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int
5062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_request_port(struct uart_port *port)
5072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
5082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct platform_device *pdev = to_platform_device(port->dev);
5092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct resource *res;
5102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int size;
5112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!res) {
5142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		dev_err(&pdev->dev, "cannot obtain I/O memory region");
5152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENODEV;
5162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
5172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	size = resource_size(res);
5182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	res = devm_request_mem_region(&pdev->dev, res->start,
5202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		size, dev_name(&pdev->dev));
5212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!res) {
5222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		dev_err(&pdev->dev, "cannot request I/O memory region");
5232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -EBUSY;
5242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
5252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (port->flags & UPF_IOREMAP) {
5272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->membase = devm_ioremap_nocache(&pdev->dev,
5282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			port->mapbase, size);
5292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		if (port->membase == NULL)
5302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			return -ENOMEM;
5312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
5322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return 0;
5332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
5342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
5362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_config_port(struct uart_port *port, int flags)
5372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
5382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (flags & UART_CONFIG_TYPE) {
5392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		port->type = PORT_LTQ_ASC;
5402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		lqasc_request_port(port);
5412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
5422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
5432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int
5452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_verify_port(struct uart_port *port,
5462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct serial_struct *ser)
5472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
5482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int ret = 0;
5492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LTQ_ASC)
5502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ret = -EINVAL;
5512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ser->irq < 0 || ser->irq >= NR_IRQS)
5522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ret = -EINVAL;
5532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ser->baud_base < 9600)
5542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		ret = -EINVAL;
5552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return ret;
5562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
5572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct uart_ops lqasc_pops = {
5592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.tx_empty =	lqasc_tx_empty,
5602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.set_mctrl =	lqasc_set_mctrl,
5612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.get_mctrl =	lqasc_get_mctrl,
5622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.stop_tx =	lqasc_stop_tx,
5632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.start_tx =	lqasc_start_tx,
5642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.stop_rx =	lqasc_stop_rx,
5652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.enable_ms =	lqasc_enable_ms,
5662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.break_ctl =	lqasc_break_ctl,
5672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.startup =	lqasc_startup,
5682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.shutdown =	lqasc_shutdown,
5692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.set_termios =	lqasc_set_termios,
5702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.type =		lqasc_type,
5712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.release_port =	lqasc_release_port,
5722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.request_port =	lqasc_request_port,
5732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.config_port =	lqasc_config_port,
5742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.verify_port =	lqasc_verify_port,
5752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin};
5762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
5782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_console_putchar(struct uart_port *port, int ch)
5792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
5802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int fifofree;
5812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!port->membase)
5832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return;
5842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	do {
5862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT)
5872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin			& ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF;
5882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	} while (fifofree == 0);
5892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_w8(ch, port->membase + LTQ_ASC_TBUF);
5902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
5912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
5932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic void
5942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_console_write(struct console *co, const char *s, u_int count)
5952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
5962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ltq_uart_port *ltq_port;
5972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port;
5982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	unsigned long flags;
5992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (co->index >= MAXPORTS)
6012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return;
6022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port = lqasc_port[co->index];
6042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!ltq_port)
6052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return;
6062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port = &ltq_port->port;
6082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_lock_irqsave(&ltq_asc_lock, flags);
6102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	uart_console_write(port, s, count, lqasc_console_putchar);
6112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	spin_unlock_irqrestore(&ltq_asc_lock, flags);
6122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
6132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int __init
6152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_console_setup(struct console *co, char *options)
6162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
6172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ltq_uart_port *ltq_port;
6182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port;
6192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int baud = 115200;
6202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int bits = 8;
6212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int parity = 'n';
6222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int flow = 'n';
6232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (co->index >= MAXPORTS)
6252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENODEV;
6262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port = lqasc_port[co->index];
6282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!ltq_port)
6292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENODEV;
6302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port = &ltq_port->port;
6322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->uartclk = clk_get_rate(ltq_port->clk);
6342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (options)
6362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		uart_parse_options(options, &baud, &parity, &bits, &flow);
6372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return uart_set_options(port, co, baud, parity, bits, flow);
6382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
6392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct console lqasc_console = {
6412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.name =		"ttyLTQ",
6422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.write =	lqasc_console_write,
6432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.device =	uart_console_device,
6442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.setup =	lqasc_console_setup,
6452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.flags =	CON_PRINTBUFFER,
6462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.index =	-1,
6472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.data =		&lqasc_reg,
6482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin};
6492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int __init
6512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_console_init(void)
6522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
6532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	register_console(&lqasc_console);
6542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return 0;
6552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
6562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinconsole_initcall(lqasc_console_init);
6572f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6582f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct uart_driver lqasc_reg = {
6592f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.owner =	THIS_MODULE,
6602f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.driver_name =	DRVNAME,
6612f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.dev_name =	"ttyLTQ",
6622f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.major =	0,
6632f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.minor =	0,
6642f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.nr =		MAXPORTS,
6652f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.cons =		&lqasc_console,
6662f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin};
6672f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6682f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic int __init
6692f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinlqasc_probe(struct platform_device *pdev)
6702f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
6712f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct ltq_uart_port *ltq_port;
6722f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct uart_port *port;
6732f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct resource *mmres, *irqres;
6742f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int tx_irq, rx_irq, err_irq;
6752f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	struct clk *clk;
6762f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int ret;
6772f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6782f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
6792f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
6802f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!mmres || !irqres)
6812f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENODEV;
6822f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6832f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (pdev->id >= MAXPORTS)
6842f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -EBUSY;
6852f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6862f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (lqasc_port[pdev->id] != NULL)
6872f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -EBUSY;
6882f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6892f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	clk = clk_get(&pdev->dev, "fpi");
6902f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (IS_ERR(clk)) {
6912f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		pr_err("failed to get fpi clk\n");
6922f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENOENT;
6932f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	}
6942f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
6952f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	tx_irq = platform_get_irq_byname(pdev, "tx");
6962f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	rx_irq = platform_get_irq_byname(pdev, "rx");
6972f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	err_irq = platform_get_irq_byname(pdev, "err");
6982f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if ((tx_irq < 0) | (rx_irq < 0) | (err_irq < 0))
6992f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENODEV;
7002f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7012f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port = kzalloc(sizeof(struct ltq_uart_port), GFP_KERNEL);
7022f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (!ltq_port)
7032f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return -ENOMEM;
7042f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7052f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port = &ltq_port->port;
7062f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7072f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->iotype	= SERIAL_IO_MEM;
7082f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->flags	= ASYNC_BOOT_AUTOCONF | UPF_IOREMAP;
7092f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->ops	= &lqasc_pops;
7102f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->fifosize	= 16;
7112f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->type	= PORT_LTQ_ASC,
7122f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->line	= pdev->id;
7132f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->dev	= &pdev->dev;
7142f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7152f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->irq	= tx_irq; /* unused, just to be backward-compatibe */
7162f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	port->mapbase	= mmres->start;
7172f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7182f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port->clk	= clk;
7192f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7202f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port->tx_irq = tx_irq;
7212f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port->rx_irq = rx_irq;
7222f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ltq_port->err_irq = err_irq;
7232f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7242f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	lqasc_port[pdev->id] = ltq_port;
7252f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	platform_set_drvdata(pdev, ltq_port);
7262f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7272f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ret = uart_add_one_port(&lqasc_reg, port);
7282f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7292f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return ret;
7302f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
7312f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7322f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinstatic struct platform_driver lqasc_driver = {
7332f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	.driver		= {
7342f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		.name	= DRVNAME,
7352f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		.owner	= THIS_MODULE,
7362f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	},
7372f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin};
7382f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7392f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinint __init
7402f0fc4159a6abc20b13569522c545150b99485cfJohn Crispininit_lqasc(void)
7412f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin{
7422f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	int ret;
7432f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7442f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ret = uart_register_driver(&lqasc_reg);
7452f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ret != 0)
7462f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		return ret;
7472f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7482f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	ret = platform_driver_probe(&lqasc_driver, lqasc_probe);
7492f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	if (ret != 0)
7502f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin		uart_unregister_driver(&lqasc_reg);
7512f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7522f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin	return ret;
7532f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin}
7542f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7552f0fc4159a6abc20b13569522c545150b99485cfJohn Crispinmodule_init(init_lqasc);
7562f0fc4159a6abc20b13569522c545150b99485cfJohn Crispin
7572f0fc4159a6abc20b13569522c545150b99485cfJohn CrispinMODULE_DESCRIPTION("Lantiq serial port driver");
7582f0fc4159a6abc20b13569522c545150b99485cfJohn CrispinMODULE_LICENSE("GPL");
759