11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Based on drivers/serial/8250.c by Russell King.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Author:	Nicolas Pitre
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Created:	Feb 20, 2003
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright:	(C) 2003 Monta Vista Software, Inc.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note 1: This driver is made separate from the already too overloaded
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 8250.c because it needs some kirks of its own and that'll make it
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * easier to add DMA support.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note 2: I'm too sick of device allocation policies for serial ports.
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If someone else wants to request an "official" allocation of major/minor
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this driver please be my guest.  And don't forget that new hardware
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * hope for a better port registration and dynamic device allocation scheme
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with the serial core maintainer satisfaction to appear soon.
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SUPPORT_SYSRQ
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/console.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sysrq.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_reg.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/circ_buf.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
39699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang#include <linux/of.h>
40d052d1beff706920e82c5d55006b08e256b5df09Russell King#include <linux/platform_device.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/serial_core.h>
44b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King#include <linux/clk.h>
45290a5589ce83540d0aba811c3d15af34aa373533Eric Miao#include <linux/io.h>
465a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang#define PXA_NAME_LEN		8
49699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_pxa_port {
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_port        port;
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char           ier;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char           lcr;
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char           mcr;
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int            lsr_break_flag;
56b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	struct clk		*clk;
57699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	char			name[PXA_NAME_LEN];
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset <<= 2;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return readl(up->port.membase + offset);
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void serial_out(struct uart_pxa_port *up, int offset, int value)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	offset <<= 2;
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(value, up->port.membase + offset);
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_enable_ms(struct uart_port *port)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->ier |= UART_IER_MSI;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, up->ier);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void serial_pxa_stop_tx(struct uart_port *port)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (up->ier & UART_IER_THRI) {
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->ier &= ~UART_IER_THRI;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		serial_out(up, UART_IER, up->ier);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_stop_rx(struct uart_port *port)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->ier &= ~UART_IER_RLSI;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.read_status_mask &= ~UART_LSR_DR;
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, up->ier);
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
997d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic inline void receive_chars(struct uart_pxa_port *up, int *status)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
101ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox	struct tty_struct *tty = up->port.state->port.tty;
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ch, flag;
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int max_count = 256;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
106e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		/* work around Errata #20 according to
107e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 * Intel(R) PXA27x Processor Family
108e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 * Specification Update (May 2005)
109e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 *
110e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 * Step 2
111e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 * Disable the Reciever Time Out Interrupt via IER[RTOEI]
112e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		 */
113e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		up->ier &= ~UART_IER_RTOIE;
114e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson		serial_out(up, UART_IER, up->ier);
115e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ch = serial_in(up, UART_RX);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flag = TTY_NORMAL;
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.icount.rx++;
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       UART_LSR_FE | UART_LSR_OE))) {
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * For statistics only
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*status & UART_LSR_BI) {
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*status &= ~(UART_LSR_FE | UART_LSR_PE);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				up->port.icount.brk++;
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/*
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * We do the SysRQ and SAK checking
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * here because otherwise the break
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * may get masked by ignore_status_mask
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 * or read_status_mask.
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 */
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (uart_handle_break(&up->port))
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto ignore_char;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (*status & UART_LSR_PE)
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				up->port.icount.parity++;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (*status & UART_LSR_FE)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				up->port.icount.frame++;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*status & UART_LSR_OE)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				up->port.icount.overrun++;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/*
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * Mask off conditions which should be ignored.
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*status &= up->port.read_status_mask;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_SERIAL_PXA_CONSOLE
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (up->port.line == up->port.cons->index) {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* Recover the break flag from console xmit */
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*status |= up->lsr_break_flag;
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				up->lsr_break_flag = 0;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (*status & UART_LSR_BI) {
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flag = TTY_BREAK;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else if (*status & UART_LSR_PE)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flag = TTY_PARITY;
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (*status & UART_LSR_FE)
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				flag = TTY_FRAME;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
16205ab3014636ff60a319d37cdf37dca594b015eecRussell King
1637d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells		if (uart_handle_sysrq_char(&up->port, ch))
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto ignore_char;
16505ab3014636ff60a319d37cdf37dca594b015eecRussell King
16605ab3014636ff60a319d37cdf37dca594b015eecRussell King		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
16705ab3014636ff60a319d37cdf37dca594b015eecRussell King
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ignore_char:
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*status = serial_in(up, UART_LSR);
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tty_flip_buffer_push(tty);
172e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson
173e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	/* work around Errata #20 according to
174e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 * Intel(R) PXA27x Processor Family
175e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 * Specification Update (May 2005)
176e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 *
177e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 * Step 6:
178e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
179e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	 */
180e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	up->ier |= UART_IER_RTOIE;
181e44aabd649c80e8be16ede3ed3cbff6fb2561ca9Marcus Folkesson	serial_out(up, UART_IER, up->ier);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void transmit_chars(struct uart_pxa_port *up)
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
186ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox	struct circ_buf *xmit = &up->port.state->xmit;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (up->port.x_char) {
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		serial_out(up, UART_TX, up->port.x_char);
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.icount.tx++;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.x_char = 0;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
196b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King		serial_pxa_stop_tx(&up->port);
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	count = up->port.fifosize / 2;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.icount.tx++;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (uart_circ_empty(xmit))
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (--count > 0);
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_write_wakeup(&up->port);
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (uart_circ_empty(xmit))
214b129a8ccd53f74c43e4c83c8e0031a4990040830Russell King		serial_pxa_stop_tx(&up->port);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
217b129a8ccd53f74c43e4c83c8e0031a4990040830Russell Kingstatic void serial_pxa_start_tx(struct uart_port *port)
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(up->ier & UART_IER_THRI)) {
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->ier |= UART_IER_THRI;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		serial_out(up, UART_IER, up->ier);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void check_modem_status(struct uart_pxa_port *up)
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int status;
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = serial_in(up, UART_MSR);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((status & UART_MSR_ANY_DELTA) == 0)
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_TERI)
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.icount.rng++;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_DDSR)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.icount.dsr++;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_DDCD)
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_DCTS)
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
245bdc04e3174e18f475289fa8f4144f66686326b7eAlan Cox	wake_up_interruptible(&up->port.state->port.delta_msr_wait);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This handles the interrupt from one port.
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2517d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
253c7bec5aba52392aa8d675b8722735caf4a8b7265Jeff Garzik	struct uart_pxa_port *up = dev_id;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int iir, lsr;
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	iir = serial_in(up, UART_IIR);
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (iir & UART_IIR_NO_INT)
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lsr = serial_in(up, UART_LSR);
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lsr & UART_LSR_DR)
2617d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells		receive_chars(up, &lsr);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	check_modem_status(up);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (lsr & UART_LSR_THRE)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		transmit_chars(up);
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int serial_pxa_tx_empty(struct uart_port *port)
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ret;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&up->port.lock, flags);
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&up->port.lock, flags);
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int serial_pxa_get_mctrl(struct uart_port *port)
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char status;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ret;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	status = serial_in(up, UART_MSR);
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = 0;
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_DCD)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= TIOCM_CAR;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_RI)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= TIOCM_RNG;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_DSR)
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= TIOCM_DSR;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (status & UART_MSR_CTS)
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret |= TIOCM_CTS;
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char mcr = 0;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & TIOCM_RTS)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr |= UART_MCR_RTS;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & TIOCM_DTR)
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr |= UART_MCR_DTR;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & TIOCM_OUT1)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr |= UART_MCR_OUT1;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & TIOCM_OUT2)
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr |= UART_MCR_OUT2;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (mctrl & TIOCM_LOOP)
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mcr |= UART_MCR_LOOP;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mcr |= up->mcr;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_MCR, mcr);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_break_ctl(struct uart_port *port, int break_state)
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&up->port.lock, flags);
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (break_state == -1)
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->lcr |= UART_LCR_SBC;
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->lcr &= ~UART_LCR_SBC;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_LCR, up->lcr);
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&up->port.lock, flags);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_dma_init(struct pxa_uart *up)
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->rxdma =
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_receive_dma, up);
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (up->rxdma < 0)
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->txdma =
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_transmit_dma, up);
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (up->txdma < 0)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_txdma;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->dmadesc = kmalloc(4 * sizeof(pxa_dma_desc), GFP_KERNEL);
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!up->dmadesc)
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto err_alloc;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ... */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_alloc:
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxa_free_dma(up->txdma);
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserr_rxdma:
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pxa_free_dma(up->rxdma);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serial_pxa_startup(struct uart_port *port)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int retval;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
367d9e29649875df82828167dd45c802d942db863baMatt Reimer	if (port->line == 3) /* HWUART */
368d9e29649875df82828167dd45c802d942db863baMatt Reimer		up->mcr |= UART_MCR_AFE;
369d9e29649875df82828167dd45c802d942db863baMatt Reimer	else
370f02aa3f9a3dea4375759ae1d87bebf2467719b72Erik Hovland		up->mcr = 0;
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
372b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	up->port.uartclk = clk_get_rate(up->clk);
373b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Allocate the IRQ
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (retval)
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return retval;
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Clear the FIFO buffers and disable them.
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (they will be reenabled in set_termios())
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, 0);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Clear the interrupt registers.
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_LSR);
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_RX);
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_IIR);
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_MSR);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Now, initialize the UART
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_LCR, UART_LCR_WLEN8);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&up->port.lock, flags);
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.mctrl |= TIOCM_OUT2;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&up->port.lock, flags);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Finally, enable interrupts.  Note: Modem status interrupts
41080f7228b59e4bbe9d840af3ff0f2fe480d6e7c79Adrian Bunk	 * are set via set_termios(), which will be occurring imminently
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * anyway, so we don't enable them here.
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, up->ier);
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * And clear the interrupt registers again for luck.
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_LSR);
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_RX);
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_IIR);
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) serial_in(up, UART_MSR);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_shutdown(struct uart_port *port)
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_irq(up->port.irq, up);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Disable interrupts from this port
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->ier = 0;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, 0);
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&up->port.lock, flags);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.mctrl &= ~TIOCM_OUT2;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&up->port.lock, flags);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Disable break condition and FIFOs
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  UART_FCR_CLEAR_RCVR |
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  UART_FCR_CLEAR_XMIT);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, 0);
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
456606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Coxserial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
457606d099cdd1080bbb50ea50dc52d98252f8f10a1Alan Cox		       struct ktermios *old)
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char cval, fcr = 0;
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int baud, quot;
463c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	unsigned int dll;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (termios->c_cflag & CSIZE) {
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS5:
4670a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King		cval = UART_LCR_WLEN5;
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS6:
4700a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King		cval = UART_LCR_WLEN6;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS7:
4730a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King		cval = UART_LCR_WLEN7;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case CS8:
4770a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King		cval = UART_LCR_WLEN8;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_cflag & CSTOPB)
4820a8b80c52f44a6e84206618a8a450ba13a5809dcRussell King		cval |= UART_LCR_STOP;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_cflag & PARENB)
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval |= UART_LCR_PARITY;
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!(termios->c_cflag & PARODD))
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cval |= UART_LCR_EPAR;
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ask the core to calculate the divisor for us.
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	quot = uart_get_divisor(port, baud);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((up->port.uartclk / quot) < (2400 * 16))
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
496d9e29649875df82828167dd45c802d942db863baMatt Reimer	else if ((up->port.uartclk / quot) < (230400 * 16))
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
498d9e29649875df82828167dd45c802d942db863baMatt Reimer	else
499d9e29649875df82828167dd45c802d942db863baMatt Reimer		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ok, we're now changing the port state.  Do it with
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * interrupts disabled.
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&up->port.lock, flags);
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Ensure the port will be enabled.
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is required especially for serial console.
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
511290a5589ce83540d0aba811c3d15af34aa373533Eric Miao	up->ier |= UART_IER_UUE;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Update the per-port timeout.
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
516e6158b4a5647624ceb90074bfcc248ea3152c906Lothar Wassmann	uart_update_timeout(port, termios->c_cflag, baud);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & INPCK)
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & (BRKINT | PARMRK))
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.read_status_mask |= UART_LSR_BI;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Characters to ignore
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.ignore_status_mask = 0;
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & IGNPAR)
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (termios->c_iflag & IGNBRK) {
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.ignore_status_mask |= UART_LSR_BI;
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/*
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * If we're ignoring parity and break indicators,
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * ignore overruns too (for real raw support).
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (termios->c_iflag & IGNPAR)
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			up->port.ignore_status_mask |= UART_LSR_OE;
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * ignore all characters if CREAD is not set
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((termios->c_cflag & CREAD) == 0)
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->port.ignore_status_mask |= UART_LSR_DR;
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * CTS flow control flag and modem status interrupts
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->ier &= ~UART_IER_MSI;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		up->ier |= UART_IER_MSI;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, up->ier);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5552276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik	if (termios->c_cflag & CRTSCTS)
5562276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik		up->mcr |= UART_MCR_AFE;
5572276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik	else
5582276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik		up->mcr &= ~UART_MCR_AFE;
5592276f03b745c297733e41470dde7f32bdd4b52afRobert Jarzmik
560c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */
562c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König
563c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	/*
564c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	 * work around Errata #75 according to Intel(R) PXA27x Processor Family
565c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	 * Specification Update (Nov 2005)
566c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	 */
567c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	dll = serial_in(up, UART_DLL);
568c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	WARN_ON(dll != (quot & 0xff));
569c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */
571c934878cc09fdd4a06ffa554c5149b11d972456fUwe Kleine-König	serial_out(up, UART_LCR, cval);			/* reset DLAB */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->lcr = cval;					/* Save LCR */
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_FCR, fcr);
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&up->port.lock, flags);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_pm(struct uart_port *port, unsigned int state,
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	      unsigned int oldstate)
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
583b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!state)
585fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel		clk_prepare_enable(up->clk);
586b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	else
587fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel		clk_disable_unprepare(up->clk);
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_release_port(struct uart_port *port)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int serial_pxa_request_port(struct uart_port *port)
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void serial_pxa_config_port(struct uart_port *port, int flags)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	up->port.type = PORT_PXA;
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we don't want the core code to modify any port params */
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const char *
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_type(struct uart_port *port)
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return up->name;
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
619e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell Kingstatic struct uart_pxa_port *serial_pxa_ports[4];
6202d93486c6c110cf81db720359b4ec20de9c91450Vincent Sandersstatic struct uart_driver serial_pxa_reg;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
622fa7f1518e8a107e1feab0357b18c745b9a6927c5Philipp Zabel#ifdef CONFIG_SERIAL_PXA_CONSOLE
623fa7f1518e8a107e1feab0357b18c745b9a6927c5Philipp Zabel
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Wait for transmitter & holding register to empty
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void wait_for_xmitr(struct uart_pxa_port *up)
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int status, tmout = 10000;
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait up to 10ms for the character(s) to be sent. */
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		status = serial_in(up, UART_LSR);
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (status & UART_LSR_BI)
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			up->lsr_break_flag = UART_LSR_BI;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (--tmout == 0)
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(1);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Wait up to 1s for flow control if necessary */
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (up->port.flags & UPF_CONS_FLOW) {
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		tmout = 1000000;
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (--tmout &&
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			udelay(1);
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
654d358788f3f30113e49882187d794832905e42592Russell Kingstatic void serial_pxa_console_putchar(struct uart_port *port, int ch)
655d358788f3f30113e49882187d794832905e42592Russell King{
656d358788f3f30113e49882187d794832905e42592Russell King	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
657d358788f3f30113e49882187d794832905e42592Russell King
658d358788f3f30113e49882187d794832905e42592Russell King	wait_for_xmitr(up);
659d358788f3f30113e49882187d794832905e42592Russell King	serial_out(up, UART_TX, ch);
660d358788f3f30113e49882187d794832905e42592Russell King}
661d358788f3f30113e49882187d794832905e42592Russell King
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print a string to the serial port trying not to disturb
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any possible real use of the port...
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The console_lock must be held when we get here.
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_console_write(struct console *co, const char *s, unsigned int count)
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
671e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	struct uart_pxa_port *up = serial_pxa_ports[co->index];
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int ier;
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
674fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel	clk_prepare_enable(up->clk);
675b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
677f02aa3f9a3dea4375759ae1d87bebf2467719b72Erik Hovland	 *	First save the IER then disable the interrupts
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ier = serial_in(up, UART_IER);
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, UART_IER_UUE);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
682d358788f3f30113e49882187d794832905e42592Russell King	uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	Finally, wait for transmitter to become empty
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 *	and restore the IER
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wait_for_xmitr(up);
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	serial_out(up, UART_IER, ier);
690b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King
691fb8ebec00b04f921ea1614a7303f1a8e5e9e47c5Philipp Zabel	clk_disable_unprepare(up->clk);
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsserial_pxa_console_setup(struct console *co, char *options)
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct uart_pxa_port *up;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int baud = 9600;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int bits = 8;
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int parity = 'n';
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int flow = 'n';
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		co->index = 0;
705e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	up = serial_pxa_ports[co->index];
706e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	if (!up)
707e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King		return -ENODEV;
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (options)
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_parse_options(options, &baud, &parity, &bits, &flow);
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return uart_set_options(&up->port, co, baud, parity, bits, flow);
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct console serial_pxa_console = {
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "ttyS",
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.write		= serial_pxa_console_write,
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.device		= uart_console_device,
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.setup		= serial_pxa_console_setup,
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.flags		= CON_PRINTBUFFER,
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.index		= -1,
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.data		= &serial_pxa_reg,
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PXA_CONSOLE	&serial_pxa_console
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PXA_CONSOLE	NULL
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct uart_ops serial_pxa_pops = {
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.tx_empty	= serial_pxa_tx_empty,
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_mctrl	= serial_pxa_set_mctrl,
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.get_mctrl	= serial_pxa_get_mctrl,
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop_tx	= serial_pxa_stop_tx,
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.start_tx	= serial_pxa_start_tx,
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.stop_rx	= serial_pxa_stop_rx,
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.enable_ms	= serial_pxa_enable_ms,
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.break_ctl	= serial_pxa_break_ctl,
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.startup	= serial_pxa_startup,
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.shutdown	= serial_pxa_shutdown,
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.set_termios	= serial_pxa_set_termios,
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.pm		= serial_pxa_pm,
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.type		= serial_pxa_type,
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release_port	= serial_pxa_release_port,
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.request_port	= serial_pxa_request_port,
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.config_port	= serial_pxa_config_port,
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.verify_port	= serial_pxa_verify_port,
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct uart_driver serial_pxa_reg = {
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.driver_name	= "PXA serial",
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dev_name	= "ttyS",
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.major		= TTY_MAJOR,
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.minor		= 64,
756e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	.nr		= 4,
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.cons		= PXA_CONSOLE,
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
760bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#ifdef CONFIG_PM
761bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoportstatic int serial_pxa_suspend(struct device *dev)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
763bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport        struct uart_pxa_port *sport = dev_get_drvdata(dev);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7659480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King        if (sport)
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                uart_suspend_port(&serial_pxa_reg, &sport->port);
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
771bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoportstatic int serial_pxa_resume(struct device *dev)
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
773bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport        struct uart_pxa_port *sport = dev_get_drvdata(dev);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7759480e307cd88ef09ec9294c7d97ebec18e6d2221Russell King        if (sport)
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds                uart_resume_port(&serial_pxa_reg, &sport->port);
7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return 0;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops serial_pxa_pm_ops = {
782bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport	.suspend	= serial_pxa_suspend,
783bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport	.resume		= serial_pxa_resume,
784bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport};
785bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#endif
786bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport
787699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuangstatic struct of_device_id serial_pxa_dt_ids[] = {
788699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	{ .compatible = "mrvl,pxa-uart", },
789699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	{ .compatible = "mrvl,mmp-uart", },
790699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	{}
791699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang};
792699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian ZhuangMODULE_DEVICE_TABLE(of, serial_pxa_dt_ids);
793699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang
794699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuangstatic int serial_pxa_probe_dt(struct platform_device *pdev,
795699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang			       struct uart_pxa_port *sport)
796699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang{
797699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	struct device_node *np = pdev->dev.of_node;
798699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	int ret;
799699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang
800699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	if (!np)
801699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		return 1;
802699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang
803699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	ret = of_alias_get_id(np, "serial");
804699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	if (ret < 0) {
805699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
806699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		return ret;
807699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	}
808699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	sport->port.line = ret;
809699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	return 0;
810699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang}
811699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang
8123ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int serial_pxa_probe(struct platform_device *dev)
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
814e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	struct uart_pxa_port *sport;
815e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	struct resource *mmres, *irqres;
816e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	int ret;
817e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
818e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
819e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
820e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	if (!mmres || !irqres)
821e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King		return -ENODEV;
822e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
823e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
824e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	if (!sport)
825e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King		return -ENOMEM;
826e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
827e0d8b13ae1e3ea747620580b6f777992148de182Russell King	sport->clk = clk_get(&dev->dev, NULL);
828b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	if (IS_ERR(sport->clk)) {
829b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King		ret = PTR_ERR(sport->clk);
830b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King		goto err_free;
831b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	}
832b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King
833e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.type = PORT_PXA;
834e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.iotype = UPIO_MEM;
835e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.mapbase = mmres->start;
836e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.irq = irqres->start;
837e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.fifosize = 64;
838e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.ops = &serial_pxa_pops;
839e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.dev = &dev->dev;
840e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
841b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	sport->port.uartclk = clk_get_rate(sport->clk);
842e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
843699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	ret = serial_pxa_probe_dt(dev, sport);
844699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	if (ret > 0)
845699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		sport->port.line = dev->id;
846699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	else if (ret < 0)
847699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		goto err_clk;
848699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
849e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
85028f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches	sport->port.membase = ioremap(mmres->start, resource_size(mmres));
851e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	if (!sport->port.membase) {
852e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King		ret = -ENOMEM;
853b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King		goto err_clk;
854e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	}
855e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
856699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang	serial_pxa_ports[sport->port.line] = sport;
857e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
858e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	uart_add_one_port(&serial_pxa_reg, &sport->port);
859e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	platform_set_drvdata(dev, sport);
860e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
862e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King
863b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King err_clk:
864b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	clk_put(sport->clk);
865e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King err_free:
866e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	kfree(sport);
867e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	return ret;
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8703ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic int serial_pxa_remove(struct platform_device *dev)
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8723ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	struct uart_pxa_port *sport = platform_get_drvdata(dev);
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8743ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_set_drvdata(dev, NULL);
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
876e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	uart_remove_one_port(&serial_pxa_reg, &sport->port);
877b049bd9de4959dd9e4b586d14b6de450a52c6f1fRussell King	clk_put(sport->clk);
878e259a3aecbfb61981175ddc7fc02dd180da7d73eRussell King	kfree(sport);
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8833ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell Kingstatic struct platform_driver serial_pxa_driver = {
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .probe          = serial_pxa_probe,
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        .remove         = serial_pxa_remove,
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8873ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	.driver		= {
8883ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	        .name	= "pxa2xx-uart",
889e169c139642fb4c682ec12a409725508dbefa520Kay Sievers		.owner	= THIS_MODULE,
890bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#ifdef CONFIG_PM
891bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport		.pm	= &serial_pxa_pm_ops,
892bf56c751fa25edf12528e7cef90fb276c3fff17aMike Rapoport#endif
893699c20f3e6310aa2ff18610c7d0885ed54d64337Haojian Zhuang		.of_match_table = serial_pxa_dt_ids,
8943ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	},
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint __init serial_pxa_init(void)
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = uart_register_driver(&serial_pxa_reg);
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 0)
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9053ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	ret = platform_driver_register(&serial_pxa_driver);
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 0)
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		uart_unregister_driver(&serial_pxa_reg);
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid __exit serial_pxa_exit(void)
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9143ae5eaec1d2d9c0cf53745352e7d4b152810ba24Russell King	platform_driver_unregister(&serial_pxa_driver);
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	uart_unregister_driver(&serial_pxa_reg);
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(serial_pxa_init);
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(serial_pxa_exit);
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
922e169c139642fb4c682ec12a409725508dbefa520Kay SieversMODULE_ALIAS("platform:pxa2xx-uart");
923