xref: /linux/drivers/tty/serial/pxa.c (revision ca16c5a300c33fd9d0cda48ef08166f32b35a56d)
1ab4382d2SGreg Kroah-Hartman /*
2ab4382d2SGreg Kroah-Hartman  *  Based on drivers/serial/8250.c by Russell King.
3ab4382d2SGreg Kroah-Hartman  *
4ab4382d2SGreg Kroah-Hartman  *  Author:	Nicolas Pitre
5ab4382d2SGreg Kroah-Hartman  *  Created:	Feb 20, 2003
6ab4382d2SGreg Kroah-Hartman  *  Copyright:	(C) 2003 Monta Vista Software, Inc.
7ab4382d2SGreg Kroah-Hartman  *
8ab4382d2SGreg Kroah-Hartman  * This program is free software; you can redistribute it and/or modify
9ab4382d2SGreg Kroah-Hartman  * it under the terms of the GNU General Public License as published by
10ab4382d2SGreg Kroah-Hartman  * the Free Software Foundation; either version 2 of the License, or
11ab4382d2SGreg Kroah-Hartman  * (at your option) any later version.
12ab4382d2SGreg Kroah-Hartman  *
13ab4382d2SGreg Kroah-Hartman  * Note 1: This driver is made separate from the already too overloaded
14ab4382d2SGreg Kroah-Hartman  * 8250.c because it needs some kirks of its own and that'll make it
15ab4382d2SGreg Kroah-Hartman  * easier to add DMA support.
16ab4382d2SGreg Kroah-Hartman  *
17ab4382d2SGreg Kroah-Hartman  * Note 2: I'm too sick of device allocation policies for serial ports.
18ab4382d2SGreg Kroah-Hartman  * If someone else wants to request an "official" allocation of major/minor
19ab4382d2SGreg Kroah-Hartman  * for this driver please be my guest.  And don't forget that new hardware
20ab4382d2SGreg Kroah-Hartman  * to come from Intel might have more than 3 or 4 of those UARTs.  Let's
21ab4382d2SGreg Kroah-Hartman  * hope for a better port registration and dynamic device allocation scheme
22ab4382d2SGreg Kroah-Hartman  * with the serial core maintainer satisfaction to appear soon.
23ab4382d2SGreg Kroah-Hartman  */
24ab4382d2SGreg Kroah-Hartman 
25ab4382d2SGreg Kroah-Hartman 
26ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
27ab4382d2SGreg Kroah-Hartman #define SUPPORT_SYSRQ
28ab4382d2SGreg Kroah-Hartman #endif
29ab4382d2SGreg Kroah-Hartman 
30ab4382d2SGreg Kroah-Hartman #include <linux/ioport.h>
31ab4382d2SGreg Kroah-Hartman #include <linux/init.h>
32ab4382d2SGreg Kroah-Hartman #include <linux/console.h>
33ab4382d2SGreg Kroah-Hartman #include <linux/sysrq.h>
34ab4382d2SGreg Kroah-Hartman #include <linux/serial_reg.h>
35ab4382d2SGreg Kroah-Hartman #include <linux/circ_buf.h>
36ab4382d2SGreg Kroah-Hartman #include <linux/delay.h>
37ab4382d2SGreg Kroah-Hartman #include <linux/interrupt.h>
38699c20f3SHaojian Zhuang #include <linux/of.h>
39ab4382d2SGreg Kroah-Hartman #include <linux/platform_device.h>
40ab4382d2SGreg Kroah-Hartman #include <linux/tty.h>
41ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h>
42ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h>
43ab4382d2SGreg Kroah-Hartman #include <linux/clk.h>
44ab4382d2SGreg Kroah-Hartman #include <linux/io.h>
45ab4382d2SGreg Kroah-Hartman #include <linux/slab.h>
46ab4382d2SGreg Kroah-Hartman 
47699c20f3SHaojian Zhuang #define PXA_NAME_LEN		8
48699c20f3SHaojian Zhuang 
49ab4382d2SGreg Kroah-Hartman struct uart_pxa_port {
50ab4382d2SGreg Kroah-Hartman 	struct uart_port        port;
51ab4382d2SGreg Kroah-Hartman 	unsigned char           ier;
52ab4382d2SGreg Kroah-Hartman 	unsigned char           lcr;
53ab4382d2SGreg Kroah-Hartman 	unsigned char           mcr;
54ab4382d2SGreg Kroah-Hartman 	unsigned int            lsr_break_flag;
55ab4382d2SGreg Kroah-Hartman 	struct clk		*clk;
56699c20f3SHaojian Zhuang 	char			name[PXA_NAME_LEN];
57ab4382d2SGreg Kroah-Hartman };
58ab4382d2SGreg Kroah-Hartman 
59ab4382d2SGreg Kroah-Hartman static inline unsigned int serial_in(struct uart_pxa_port *up, int offset)
60ab4382d2SGreg Kroah-Hartman {
61ab4382d2SGreg Kroah-Hartman 	offset <<= 2;
62ab4382d2SGreg Kroah-Hartman 	return readl(up->port.membase + offset);
63ab4382d2SGreg Kroah-Hartman }
64ab4382d2SGreg Kroah-Hartman 
65ab4382d2SGreg Kroah-Hartman static inline void serial_out(struct uart_pxa_port *up, int offset, int value)
66ab4382d2SGreg Kroah-Hartman {
67ab4382d2SGreg Kroah-Hartman 	offset <<= 2;
68ab4382d2SGreg Kroah-Hartman 	writel(value, up->port.membase + offset);
69ab4382d2SGreg Kroah-Hartman }
70ab4382d2SGreg Kroah-Hartman 
71ab4382d2SGreg Kroah-Hartman static void serial_pxa_enable_ms(struct uart_port *port)
72ab4382d2SGreg Kroah-Hartman {
73ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
74ab4382d2SGreg Kroah-Hartman 
75ab4382d2SGreg Kroah-Hartman 	up->ier |= UART_IER_MSI;
76ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, up->ier);
77ab4382d2SGreg Kroah-Hartman }
78ab4382d2SGreg Kroah-Hartman 
79ab4382d2SGreg Kroah-Hartman static void serial_pxa_stop_tx(struct uart_port *port)
80ab4382d2SGreg Kroah-Hartman {
81ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
82ab4382d2SGreg Kroah-Hartman 
83ab4382d2SGreg Kroah-Hartman 	if (up->ier & UART_IER_THRI) {
84ab4382d2SGreg Kroah-Hartman 		up->ier &= ~UART_IER_THRI;
85ab4382d2SGreg Kroah-Hartman 		serial_out(up, UART_IER, up->ier);
86ab4382d2SGreg Kroah-Hartman 	}
87ab4382d2SGreg Kroah-Hartman }
88ab4382d2SGreg Kroah-Hartman 
89ab4382d2SGreg Kroah-Hartman static void serial_pxa_stop_rx(struct uart_port *port)
90ab4382d2SGreg Kroah-Hartman {
91ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
92ab4382d2SGreg Kroah-Hartman 
93ab4382d2SGreg Kroah-Hartman 	up->ier &= ~UART_IER_RLSI;
94ab4382d2SGreg Kroah-Hartman 	up->port.read_status_mask &= ~UART_LSR_DR;
95ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, up->ier);
96ab4382d2SGreg Kroah-Hartman }
97ab4382d2SGreg Kroah-Hartman 
98ab4382d2SGreg Kroah-Hartman static inline void receive_chars(struct uart_pxa_port *up, int *status)
99ab4382d2SGreg Kroah-Hartman {
100ab4382d2SGreg Kroah-Hartman 	unsigned int ch, flag;
101ab4382d2SGreg Kroah-Hartman 	int max_count = 256;
102ab4382d2SGreg Kroah-Hartman 
103ab4382d2SGreg Kroah-Hartman 	do {
104e44aabd6SMarcus Folkesson 		/* work around Errata #20 according to
105e44aabd6SMarcus Folkesson 		 * Intel(R) PXA27x Processor Family
106e44aabd6SMarcus Folkesson 		 * Specification Update (May 2005)
107e44aabd6SMarcus Folkesson 		 *
108e44aabd6SMarcus Folkesson 		 * Step 2
109e44aabd6SMarcus Folkesson 		 * Disable the Reciever Time Out Interrupt via IER[RTOEI]
110e44aabd6SMarcus Folkesson 		 */
111e44aabd6SMarcus Folkesson 		up->ier &= ~UART_IER_RTOIE;
112e44aabd6SMarcus Folkesson 		serial_out(up, UART_IER, up->ier);
113e44aabd6SMarcus Folkesson 
114ab4382d2SGreg Kroah-Hartman 		ch = serial_in(up, UART_RX);
115ab4382d2SGreg Kroah-Hartman 		flag = TTY_NORMAL;
116ab4382d2SGreg Kroah-Hartman 		up->port.icount.rx++;
117ab4382d2SGreg Kroah-Hartman 
118ab4382d2SGreg Kroah-Hartman 		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
119ab4382d2SGreg Kroah-Hartman 				       UART_LSR_FE | UART_LSR_OE))) {
120ab4382d2SGreg Kroah-Hartman 			/*
121ab4382d2SGreg Kroah-Hartman 			 * For statistics only
122ab4382d2SGreg Kroah-Hartman 			 */
123ab4382d2SGreg Kroah-Hartman 			if (*status & UART_LSR_BI) {
124ab4382d2SGreg Kroah-Hartman 				*status &= ~(UART_LSR_FE | UART_LSR_PE);
125ab4382d2SGreg Kroah-Hartman 				up->port.icount.brk++;
126ab4382d2SGreg Kroah-Hartman 				/*
127ab4382d2SGreg Kroah-Hartman 				 * We do the SysRQ and SAK checking
128ab4382d2SGreg Kroah-Hartman 				 * here because otherwise the break
129ab4382d2SGreg Kroah-Hartman 				 * may get masked by ignore_status_mask
130ab4382d2SGreg Kroah-Hartman 				 * or read_status_mask.
131ab4382d2SGreg Kroah-Hartman 				 */
132ab4382d2SGreg Kroah-Hartman 				if (uart_handle_break(&up->port))
133ab4382d2SGreg Kroah-Hartman 					goto ignore_char;
134ab4382d2SGreg Kroah-Hartman 			} else if (*status & UART_LSR_PE)
135ab4382d2SGreg Kroah-Hartman 				up->port.icount.parity++;
136ab4382d2SGreg Kroah-Hartman 			else if (*status & UART_LSR_FE)
137ab4382d2SGreg Kroah-Hartman 				up->port.icount.frame++;
138ab4382d2SGreg Kroah-Hartman 			if (*status & UART_LSR_OE)
139ab4382d2SGreg Kroah-Hartman 				up->port.icount.overrun++;
140ab4382d2SGreg Kroah-Hartman 
141ab4382d2SGreg Kroah-Hartman 			/*
142ab4382d2SGreg Kroah-Hartman 			 * Mask off conditions which should be ignored.
143ab4382d2SGreg Kroah-Hartman 			 */
144ab4382d2SGreg Kroah-Hartman 			*status &= up->port.read_status_mask;
145ab4382d2SGreg Kroah-Hartman 
146ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_PXA_CONSOLE
147ab4382d2SGreg Kroah-Hartman 			if (up->port.line == up->port.cons->index) {
148ab4382d2SGreg Kroah-Hartman 				/* Recover the break flag from console xmit */
149ab4382d2SGreg Kroah-Hartman 				*status |= up->lsr_break_flag;
150ab4382d2SGreg Kroah-Hartman 				up->lsr_break_flag = 0;
151ab4382d2SGreg Kroah-Hartman 			}
152ab4382d2SGreg Kroah-Hartman #endif
153ab4382d2SGreg Kroah-Hartman 			if (*status & UART_LSR_BI) {
154ab4382d2SGreg Kroah-Hartman 				flag = TTY_BREAK;
155ab4382d2SGreg Kroah-Hartman 			} else if (*status & UART_LSR_PE)
156ab4382d2SGreg Kroah-Hartman 				flag = TTY_PARITY;
157ab4382d2SGreg Kroah-Hartman 			else if (*status & UART_LSR_FE)
158ab4382d2SGreg Kroah-Hartman 				flag = TTY_FRAME;
159ab4382d2SGreg Kroah-Hartman 		}
160ab4382d2SGreg Kroah-Hartman 
161ab4382d2SGreg Kroah-Hartman 		if (uart_handle_sysrq_char(&up->port, ch))
162ab4382d2SGreg Kroah-Hartman 			goto ignore_char;
163ab4382d2SGreg Kroah-Hartman 
164ab4382d2SGreg Kroah-Hartman 		uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
165ab4382d2SGreg Kroah-Hartman 
166ab4382d2SGreg Kroah-Hartman 	ignore_char:
167ab4382d2SGreg Kroah-Hartman 		*status = serial_in(up, UART_LSR);
168ab4382d2SGreg Kroah-Hartman 	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
1692e124b4aSJiri Slaby 	tty_flip_buffer_push(&up->port.state->port);
170e44aabd6SMarcus Folkesson 
171e44aabd6SMarcus Folkesson 	/* work around Errata #20 according to
172e44aabd6SMarcus Folkesson 	 * Intel(R) PXA27x Processor Family
173e44aabd6SMarcus Folkesson 	 * Specification Update (May 2005)
174e44aabd6SMarcus Folkesson 	 *
175e44aabd6SMarcus Folkesson 	 * Step 6:
176e44aabd6SMarcus Folkesson 	 * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
177e44aabd6SMarcus Folkesson 	 */
178e44aabd6SMarcus Folkesson 	up->ier |= UART_IER_RTOIE;
179e44aabd6SMarcus Folkesson 	serial_out(up, UART_IER, up->ier);
180ab4382d2SGreg Kroah-Hartman }
181ab4382d2SGreg Kroah-Hartman 
182ab4382d2SGreg Kroah-Hartman static void transmit_chars(struct uart_pxa_port *up)
183ab4382d2SGreg Kroah-Hartman {
184ab4382d2SGreg Kroah-Hartman 	struct circ_buf *xmit = &up->port.state->xmit;
185ab4382d2SGreg Kroah-Hartman 	int count;
186ab4382d2SGreg Kroah-Hartman 
187ab4382d2SGreg Kroah-Hartman 	if (up->port.x_char) {
188ab4382d2SGreg Kroah-Hartman 		serial_out(up, UART_TX, up->port.x_char);
189ab4382d2SGreg Kroah-Hartman 		up->port.icount.tx++;
190ab4382d2SGreg Kroah-Hartman 		up->port.x_char = 0;
191ab4382d2SGreg Kroah-Hartman 		return;
192ab4382d2SGreg Kroah-Hartman 	}
193ab4382d2SGreg Kroah-Hartman 	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
194ab4382d2SGreg Kroah-Hartman 		serial_pxa_stop_tx(&up->port);
195ab4382d2SGreg Kroah-Hartman 		return;
196ab4382d2SGreg Kroah-Hartman 	}
197ab4382d2SGreg Kroah-Hartman 
198ab4382d2SGreg Kroah-Hartman 	count = up->port.fifosize / 2;
199ab4382d2SGreg Kroah-Hartman 	do {
200ab4382d2SGreg Kroah-Hartman 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
201ab4382d2SGreg Kroah-Hartman 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
202ab4382d2SGreg Kroah-Hartman 		up->port.icount.tx++;
203ab4382d2SGreg Kroah-Hartman 		if (uart_circ_empty(xmit))
204ab4382d2SGreg Kroah-Hartman 			break;
205ab4382d2SGreg Kroah-Hartman 	} while (--count > 0);
206ab4382d2SGreg Kroah-Hartman 
207ab4382d2SGreg Kroah-Hartman 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
208ab4382d2SGreg Kroah-Hartman 		uart_write_wakeup(&up->port);
209ab4382d2SGreg Kroah-Hartman 
210ab4382d2SGreg Kroah-Hartman 
211ab4382d2SGreg Kroah-Hartman 	if (uart_circ_empty(xmit))
212ab4382d2SGreg Kroah-Hartman 		serial_pxa_stop_tx(&up->port);
213ab4382d2SGreg Kroah-Hartman }
214ab4382d2SGreg Kroah-Hartman 
215ab4382d2SGreg Kroah-Hartman static void serial_pxa_start_tx(struct uart_port *port)
216ab4382d2SGreg Kroah-Hartman {
217ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
218ab4382d2SGreg Kroah-Hartman 
219ab4382d2SGreg Kroah-Hartman 	if (!(up->ier & UART_IER_THRI)) {
220ab4382d2SGreg Kroah-Hartman 		up->ier |= UART_IER_THRI;
221ab4382d2SGreg Kroah-Hartman 		serial_out(up, UART_IER, up->ier);
222ab4382d2SGreg Kroah-Hartman 	}
223ab4382d2SGreg Kroah-Hartman }
224ab4382d2SGreg Kroah-Hartman 
22550d1e7d1SDmitry Eremin-Solenikov /* should hold up->port.lock */
226ab4382d2SGreg Kroah-Hartman static inline void check_modem_status(struct uart_pxa_port *up)
227ab4382d2SGreg Kroah-Hartman {
228ab4382d2SGreg Kroah-Hartman 	int status;
229ab4382d2SGreg Kroah-Hartman 
230ab4382d2SGreg Kroah-Hartman 	status = serial_in(up, UART_MSR);
231ab4382d2SGreg Kroah-Hartman 
232ab4382d2SGreg Kroah-Hartman 	if ((status & UART_MSR_ANY_DELTA) == 0)
233ab4382d2SGreg Kroah-Hartman 		return;
234ab4382d2SGreg Kroah-Hartman 
235ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_TERI)
236ab4382d2SGreg Kroah-Hartman 		up->port.icount.rng++;
237ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_DDSR)
238ab4382d2SGreg Kroah-Hartman 		up->port.icount.dsr++;
239ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_DDCD)
240ab4382d2SGreg Kroah-Hartman 		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
241ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_DCTS)
242ab4382d2SGreg Kroah-Hartman 		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
243ab4382d2SGreg Kroah-Hartman 
244ab4382d2SGreg Kroah-Hartman 	wake_up_interruptible(&up->port.state->port.delta_msr_wait);
245ab4382d2SGreg Kroah-Hartman }
246ab4382d2SGreg Kroah-Hartman 
247ab4382d2SGreg Kroah-Hartman /*
248ab4382d2SGreg Kroah-Hartman  * This handles the interrupt from one port.
249ab4382d2SGreg Kroah-Hartman  */
250ab4382d2SGreg Kroah-Hartman static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
251ab4382d2SGreg Kroah-Hartman {
252ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = dev_id;
253ab4382d2SGreg Kroah-Hartman 	unsigned int iir, lsr;
254ab4382d2SGreg Kroah-Hartman 
255ab4382d2SGreg Kroah-Hartman 	iir = serial_in(up, UART_IIR);
256ab4382d2SGreg Kroah-Hartman 	if (iir & UART_IIR_NO_INT)
257ab4382d2SGreg Kroah-Hartman 		return IRQ_NONE;
25850d1e7d1SDmitry Eremin-Solenikov 	spin_lock(&up->port.lock);
259ab4382d2SGreg Kroah-Hartman 	lsr = serial_in(up, UART_LSR);
260ab4382d2SGreg Kroah-Hartman 	if (lsr & UART_LSR_DR)
261ab4382d2SGreg Kroah-Hartman 		receive_chars(up, &lsr);
262ab4382d2SGreg Kroah-Hartman 	check_modem_status(up);
263ab4382d2SGreg Kroah-Hartman 	if (lsr & UART_LSR_THRE)
264ab4382d2SGreg Kroah-Hartman 		transmit_chars(up);
26550d1e7d1SDmitry Eremin-Solenikov 	spin_unlock(&up->port.lock);
266ab4382d2SGreg Kroah-Hartman 	return IRQ_HANDLED;
267ab4382d2SGreg Kroah-Hartman }
268ab4382d2SGreg Kroah-Hartman 
269ab4382d2SGreg Kroah-Hartman static unsigned int serial_pxa_tx_empty(struct uart_port *port)
270ab4382d2SGreg Kroah-Hartman {
271ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
272ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
273ab4382d2SGreg Kroah-Hartman 	unsigned int ret;
274ab4382d2SGreg Kroah-Hartman 
275ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&up->port.lock, flags);
276ab4382d2SGreg Kroah-Hartman 	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
277ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&up->port.lock, flags);
278ab4382d2SGreg Kroah-Hartman 
279ab4382d2SGreg Kroah-Hartman 	return ret;
280ab4382d2SGreg Kroah-Hartman }
281ab4382d2SGreg Kroah-Hartman 
282ab4382d2SGreg Kroah-Hartman static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
283ab4382d2SGreg Kroah-Hartman {
284ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
285ab4382d2SGreg Kroah-Hartman 	unsigned char status;
286ab4382d2SGreg Kroah-Hartman 	unsigned int ret;
287ab4382d2SGreg Kroah-Hartman 
288ab4382d2SGreg Kroah-Hartman 	status = serial_in(up, UART_MSR);
289ab4382d2SGreg Kroah-Hartman 
290ab4382d2SGreg Kroah-Hartman 	ret = 0;
291ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_DCD)
292ab4382d2SGreg Kroah-Hartman 		ret |= TIOCM_CAR;
293ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_RI)
294ab4382d2SGreg Kroah-Hartman 		ret |= TIOCM_RNG;
295ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_DSR)
296ab4382d2SGreg Kroah-Hartman 		ret |= TIOCM_DSR;
297ab4382d2SGreg Kroah-Hartman 	if (status & UART_MSR_CTS)
298ab4382d2SGreg Kroah-Hartman 		ret |= TIOCM_CTS;
299ab4382d2SGreg Kroah-Hartman 	return ret;
300ab4382d2SGreg Kroah-Hartman }
301ab4382d2SGreg Kroah-Hartman 
302ab4382d2SGreg Kroah-Hartman static void serial_pxa_set_mctrl(struct uart_port *port, unsigned int mctrl)
303ab4382d2SGreg Kroah-Hartman {
304ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
305ab4382d2SGreg Kroah-Hartman 	unsigned char mcr = 0;
306ab4382d2SGreg Kroah-Hartman 
307ab4382d2SGreg Kroah-Hartman 	if (mctrl & TIOCM_RTS)
308ab4382d2SGreg Kroah-Hartman 		mcr |= UART_MCR_RTS;
309ab4382d2SGreg Kroah-Hartman 	if (mctrl & TIOCM_DTR)
310ab4382d2SGreg Kroah-Hartman 		mcr |= UART_MCR_DTR;
311ab4382d2SGreg Kroah-Hartman 	if (mctrl & TIOCM_OUT1)
312ab4382d2SGreg Kroah-Hartman 		mcr |= UART_MCR_OUT1;
313ab4382d2SGreg Kroah-Hartman 	if (mctrl & TIOCM_OUT2)
314ab4382d2SGreg Kroah-Hartman 		mcr |= UART_MCR_OUT2;
315ab4382d2SGreg Kroah-Hartman 	if (mctrl & TIOCM_LOOP)
316ab4382d2SGreg Kroah-Hartman 		mcr |= UART_MCR_LOOP;
317ab4382d2SGreg Kroah-Hartman 
318ab4382d2SGreg Kroah-Hartman 	mcr |= up->mcr;
319ab4382d2SGreg Kroah-Hartman 
320ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_MCR, mcr);
321ab4382d2SGreg Kroah-Hartman }
322ab4382d2SGreg Kroah-Hartman 
323ab4382d2SGreg Kroah-Hartman static void serial_pxa_break_ctl(struct uart_port *port, int break_state)
324ab4382d2SGreg Kroah-Hartman {
325ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
326ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
327ab4382d2SGreg Kroah-Hartman 
328ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&up->port.lock, flags);
329ab4382d2SGreg Kroah-Hartman 	if (break_state == -1)
330ab4382d2SGreg Kroah-Hartman 		up->lcr |= UART_LCR_SBC;
331ab4382d2SGreg Kroah-Hartman 	else
332ab4382d2SGreg Kroah-Hartman 		up->lcr &= ~UART_LCR_SBC;
333ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_LCR, up->lcr);
334ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&up->port.lock, flags);
335ab4382d2SGreg Kroah-Hartman }
336ab4382d2SGreg Kroah-Hartman 
337ab4382d2SGreg Kroah-Hartman static int serial_pxa_startup(struct uart_port *port)
338ab4382d2SGreg Kroah-Hartman {
339ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
340ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
341ab4382d2SGreg Kroah-Hartman 	int retval;
342ab4382d2SGreg Kroah-Hartman 
343ab4382d2SGreg Kroah-Hartman 	if (port->line == 3) /* HWUART */
344ab4382d2SGreg Kroah-Hartman 		up->mcr |= UART_MCR_AFE;
345ab4382d2SGreg Kroah-Hartman 	else
346ab4382d2SGreg Kroah-Hartman 		up->mcr = 0;
347ab4382d2SGreg Kroah-Hartman 
348ab4382d2SGreg Kroah-Hartman 	up->port.uartclk = clk_get_rate(up->clk);
349ab4382d2SGreg Kroah-Hartman 
350ab4382d2SGreg Kroah-Hartman 	/*
351ab4382d2SGreg Kroah-Hartman 	 * Allocate the IRQ
352ab4382d2SGreg Kroah-Hartman 	 */
353ab4382d2SGreg Kroah-Hartman 	retval = request_irq(up->port.irq, serial_pxa_irq, 0, up->name, up);
354ab4382d2SGreg Kroah-Hartman 	if (retval)
355ab4382d2SGreg Kroah-Hartman 		return retval;
356ab4382d2SGreg Kroah-Hartman 
357ab4382d2SGreg Kroah-Hartman 	/*
358ab4382d2SGreg Kroah-Hartman 	 * Clear the FIFO buffers and disable them.
359ab4382d2SGreg Kroah-Hartman 	 * (they will be reenabled in set_termios())
360ab4382d2SGreg Kroah-Hartman 	 */
361ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
362ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
363ab4382d2SGreg Kroah-Hartman 			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
364ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, 0);
365ab4382d2SGreg Kroah-Hartman 
366ab4382d2SGreg Kroah-Hartman 	/*
367ab4382d2SGreg Kroah-Hartman 	 * Clear the interrupt registers.
368ab4382d2SGreg Kroah-Hartman 	 */
369ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_LSR);
370ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_RX);
371ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_IIR);
372ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_MSR);
373ab4382d2SGreg Kroah-Hartman 
374ab4382d2SGreg Kroah-Hartman 	/*
375ab4382d2SGreg Kroah-Hartman 	 * Now, initialize the UART
376ab4382d2SGreg Kroah-Hartman 	 */
377ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_LCR, UART_LCR_WLEN8);
378ab4382d2SGreg Kroah-Hartman 
379ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&up->port.lock, flags);
380ab4382d2SGreg Kroah-Hartman 	up->port.mctrl |= TIOCM_OUT2;
381ab4382d2SGreg Kroah-Hartman 	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
382ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&up->port.lock, flags);
383ab4382d2SGreg Kroah-Hartman 
384ab4382d2SGreg Kroah-Hartman 	/*
385ab4382d2SGreg Kroah-Hartman 	 * Finally, enable interrupts.  Note: Modem status interrupts
386ab4382d2SGreg Kroah-Hartman 	 * are set via set_termios(), which will be occurring imminently
387ab4382d2SGreg Kroah-Hartman 	 * anyway, so we don't enable them here.
388ab4382d2SGreg Kroah-Hartman 	 */
389ab4382d2SGreg Kroah-Hartman 	up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
390ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, up->ier);
391ab4382d2SGreg Kroah-Hartman 
392ab4382d2SGreg Kroah-Hartman 	/*
393ab4382d2SGreg Kroah-Hartman 	 * And clear the interrupt registers again for luck.
394ab4382d2SGreg Kroah-Hartman 	 */
395ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_LSR);
396ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_RX);
397ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_IIR);
398ab4382d2SGreg Kroah-Hartman 	(void) serial_in(up, UART_MSR);
399ab4382d2SGreg Kroah-Hartman 
400ab4382d2SGreg Kroah-Hartman 	return 0;
401ab4382d2SGreg Kroah-Hartman }
402ab4382d2SGreg Kroah-Hartman 
403ab4382d2SGreg Kroah-Hartman static void serial_pxa_shutdown(struct uart_port *port)
404ab4382d2SGreg Kroah-Hartman {
405ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
406ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
407ab4382d2SGreg Kroah-Hartman 
408ab4382d2SGreg Kroah-Hartman 	free_irq(up->port.irq, up);
409ab4382d2SGreg Kroah-Hartman 
410ab4382d2SGreg Kroah-Hartman 	/*
411ab4382d2SGreg Kroah-Hartman 	 * Disable interrupts from this port
412ab4382d2SGreg Kroah-Hartman 	 */
413ab4382d2SGreg Kroah-Hartman 	up->ier = 0;
414ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, 0);
415ab4382d2SGreg Kroah-Hartman 
416ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&up->port.lock, flags);
417ab4382d2SGreg Kroah-Hartman 	up->port.mctrl &= ~TIOCM_OUT2;
418ab4382d2SGreg Kroah-Hartman 	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
419ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&up->port.lock, flags);
420ab4382d2SGreg Kroah-Hartman 
421ab4382d2SGreg Kroah-Hartman 	/*
422ab4382d2SGreg Kroah-Hartman 	 * Disable break condition and FIFOs
423ab4382d2SGreg Kroah-Hartman 	 */
424ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
425ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
426ab4382d2SGreg Kroah-Hartman 				  UART_FCR_CLEAR_RCVR |
427ab4382d2SGreg Kroah-Hartman 				  UART_FCR_CLEAR_XMIT);
428ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, 0);
429ab4382d2SGreg Kroah-Hartman }
430ab4382d2SGreg Kroah-Hartman 
431ab4382d2SGreg Kroah-Hartman static void
432ab4382d2SGreg Kroah-Hartman serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios,
433ab4382d2SGreg Kroah-Hartman 		       struct ktermios *old)
434ab4382d2SGreg Kroah-Hartman {
435ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
436ab4382d2SGreg Kroah-Hartman 	unsigned char cval, fcr = 0;
437ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
438ab4382d2SGreg Kroah-Hartman 	unsigned int baud, quot;
439ab4382d2SGreg Kroah-Hartman 	unsigned int dll;
440ab4382d2SGreg Kroah-Hartman 
441ab4382d2SGreg Kroah-Hartman 	switch (termios->c_cflag & CSIZE) {
442ab4382d2SGreg Kroah-Hartman 	case CS5:
443ab4382d2SGreg Kroah-Hartman 		cval = UART_LCR_WLEN5;
444ab4382d2SGreg Kroah-Hartman 		break;
445ab4382d2SGreg Kroah-Hartman 	case CS6:
446ab4382d2SGreg Kroah-Hartman 		cval = UART_LCR_WLEN6;
447ab4382d2SGreg Kroah-Hartman 		break;
448ab4382d2SGreg Kroah-Hartman 	case CS7:
449ab4382d2SGreg Kroah-Hartman 		cval = UART_LCR_WLEN7;
450ab4382d2SGreg Kroah-Hartman 		break;
451ab4382d2SGreg Kroah-Hartman 	default:
452ab4382d2SGreg Kroah-Hartman 	case CS8:
453ab4382d2SGreg Kroah-Hartman 		cval = UART_LCR_WLEN8;
454ab4382d2SGreg Kroah-Hartman 		break;
455ab4382d2SGreg Kroah-Hartman 	}
456ab4382d2SGreg Kroah-Hartman 
457ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CSTOPB)
458ab4382d2SGreg Kroah-Hartman 		cval |= UART_LCR_STOP;
459ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & PARENB)
460ab4382d2SGreg Kroah-Hartman 		cval |= UART_LCR_PARITY;
461ab4382d2SGreg Kroah-Hartman 	if (!(termios->c_cflag & PARODD))
462ab4382d2SGreg Kroah-Hartman 		cval |= UART_LCR_EPAR;
463ab4382d2SGreg Kroah-Hartman 
464ab4382d2SGreg Kroah-Hartman 	/*
465ab4382d2SGreg Kroah-Hartman 	 * Ask the core to calculate the divisor for us.
466ab4382d2SGreg Kroah-Hartman 	 */
467ab4382d2SGreg Kroah-Hartman 	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
468ab4382d2SGreg Kroah-Hartman 	quot = uart_get_divisor(port, baud);
469ab4382d2SGreg Kroah-Hartman 
470ab4382d2SGreg Kroah-Hartman 	if ((up->port.uartclk / quot) < (2400 * 16))
471ab4382d2SGreg Kroah-Hartman 		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR1;
472ab4382d2SGreg Kroah-Hartman 	else if ((up->port.uartclk / quot) < (230400 * 16))
473ab4382d2SGreg Kroah-Hartman 		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR8;
474ab4382d2SGreg Kroah-Hartman 	else
475ab4382d2SGreg Kroah-Hartman 		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_PXAR32;
476ab4382d2SGreg Kroah-Hartman 
477ab4382d2SGreg Kroah-Hartman 	/*
478ab4382d2SGreg Kroah-Hartman 	 * Ok, we're now changing the port state.  Do it with
479ab4382d2SGreg Kroah-Hartman 	 * interrupts disabled.
480ab4382d2SGreg Kroah-Hartman 	 */
481ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&up->port.lock, flags);
482ab4382d2SGreg Kroah-Hartman 
483ab4382d2SGreg Kroah-Hartman 	/*
484ab4382d2SGreg Kroah-Hartman 	 * Ensure the port will be enabled.
485ab4382d2SGreg Kroah-Hartman 	 * This is required especially for serial console.
486ab4382d2SGreg Kroah-Hartman 	 */
487ab4382d2SGreg Kroah-Hartman 	up->ier |= UART_IER_UUE;
488ab4382d2SGreg Kroah-Hartman 
489ab4382d2SGreg Kroah-Hartman 	/*
490ab4382d2SGreg Kroah-Hartman 	 * Update the per-port timeout.
491ab4382d2SGreg Kroah-Hartman 	 */
492ab4382d2SGreg Kroah-Hartman 	uart_update_timeout(port, termios->c_cflag, baud);
493ab4382d2SGreg Kroah-Hartman 
494ab4382d2SGreg Kroah-Hartman 	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
495ab4382d2SGreg Kroah-Hartman 	if (termios->c_iflag & INPCK)
496ab4382d2SGreg Kroah-Hartman 		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
497ef8b9ddcSPeter Hurley 	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
498ab4382d2SGreg Kroah-Hartman 		up->port.read_status_mask |= UART_LSR_BI;
499ab4382d2SGreg Kroah-Hartman 
500ab4382d2SGreg Kroah-Hartman 	/*
501ab4382d2SGreg Kroah-Hartman 	 * Characters to ignore
502ab4382d2SGreg Kroah-Hartman 	 */
503ab4382d2SGreg Kroah-Hartman 	up->port.ignore_status_mask = 0;
504ab4382d2SGreg Kroah-Hartman 	if (termios->c_iflag & IGNPAR)
505ab4382d2SGreg Kroah-Hartman 		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
506ab4382d2SGreg Kroah-Hartman 	if (termios->c_iflag & IGNBRK) {
507ab4382d2SGreg Kroah-Hartman 		up->port.ignore_status_mask |= UART_LSR_BI;
508ab4382d2SGreg Kroah-Hartman 		/*
509ab4382d2SGreg Kroah-Hartman 		 * If we're ignoring parity and break indicators,
510ab4382d2SGreg Kroah-Hartman 		 * ignore overruns too (for real raw support).
511ab4382d2SGreg Kroah-Hartman 		 */
512ab4382d2SGreg Kroah-Hartman 		if (termios->c_iflag & IGNPAR)
513ab4382d2SGreg Kroah-Hartman 			up->port.ignore_status_mask |= UART_LSR_OE;
514ab4382d2SGreg Kroah-Hartman 	}
515ab4382d2SGreg Kroah-Hartman 
516ab4382d2SGreg Kroah-Hartman 	/*
517ab4382d2SGreg Kroah-Hartman 	 * ignore all characters if CREAD is not set
518ab4382d2SGreg Kroah-Hartman 	 */
519ab4382d2SGreg Kroah-Hartman 	if ((termios->c_cflag & CREAD) == 0)
520ab4382d2SGreg Kroah-Hartman 		up->port.ignore_status_mask |= UART_LSR_DR;
521ab4382d2SGreg Kroah-Hartman 
522ab4382d2SGreg Kroah-Hartman 	/*
523ab4382d2SGreg Kroah-Hartman 	 * CTS flow control flag and modem status interrupts
524ab4382d2SGreg Kroah-Hartman 	 */
525ab4382d2SGreg Kroah-Hartman 	up->ier &= ~UART_IER_MSI;
526ab4382d2SGreg Kroah-Hartman 	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
527ab4382d2SGreg Kroah-Hartman 		up->ier |= UART_IER_MSI;
528ab4382d2SGreg Kroah-Hartman 
529ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, up->ier);
530ab4382d2SGreg Kroah-Hartman 
531ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CRTSCTS)
532ab4382d2SGreg Kroah-Hartman 		up->mcr |= UART_MCR_AFE;
533ab4382d2SGreg Kroah-Hartman 	else
534ab4382d2SGreg Kroah-Hartman 		up->mcr &= ~UART_MCR_AFE;
535ab4382d2SGreg Kroah-Hartman 
536ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
537ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */
538ab4382d2SGreg Kroah-Hartman 
539ab4382d2SGreg Kroah-Hartman 	/*
540ab4382d2SGreg Kroah-Hartman 	 * work around Errata #75 according to Intel(R) PXA27x Processor Family
541ab4382d2SGreg Kroah-Hartman 	 * Specification Update (Nov 2005)
542ab4382d2SGreg Kroah-Hartman 	 */
543ab4382d2SGreg Kroah-Hartman 	dll = serial_in(up, UART_DLL);
544ab4382d2SGreg Kroah-Hartman 	WARN_ON(dll != (quot & 0xff));
545ab4382d2SGreg Kroah-Hartman 
546ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */
547ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_LCR, cval);			/* reset DLAB */
548ab4382d2SGreg Kroah-Hartman 	up->lcr = cval;					/* Save LCR */
549ab4382d2SGreg Kroah-Hartman 	serial_pxa_set_mctrl(&up->port, up->port.mctrl);
550ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_FCR, fcr);
551ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&up->port.lock, flags);
552ab4382d2SGreg Kroah-Hartman }
553ab4382d2SGreg Kroah-Hartman 
554ab4382d2SGreg Kroah-Hartman static void
555ab4382d2SGreg Kroah-Hartman serial_pxa_pm(struct uart_port *port, unsigned int state,
556ab4382d2SGreg Kroah-Hartman 	      unsigned int oldstate)
557ab4382d2SGreg Kroah-Hartman {
558ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
559ab4382d2SGreg Kroah-Hartman 
560ab4382d2SGreg Kroah-Hartman 	if (!state)
561fb8ebec0SPhilipp Zabel 		clk_prepare_enable(up->clk);
562ab4382d2SGreg Kroah-Hartman 	else
563fb8ebec0SPhilipp Zabel 		clk_disable_unprepare(up->clk);
564ab4382d2SGreg Kroah-Hartman }
565ab4382d2SGreg Kroah-Hartman 
566ab4382d2SGreg Kroah-Hartman static void serial_pxa_release_port(struct uart_port *port)
567ab4382d2SGreg Kroah-Hartman {
568ab4382d2SGreg Kroah-Hartman }
569ab4382d2SGreg Kroah-Hartman 
570ab4382d2SGreg Kroah-Hartman static int serial_pxa_request_port(struct uart_port *port)
571ab4382d2SGreg Kroah-Hartman {
572ab4382d2SGreg Kroah-Hartman 	return 0;
573ab4382d2SGreg Kroah-Hartman }
574ab4382d2SGreg Kroah-Hartman 
575ab4382d2SGreg Kroah-Hartman static void serial_pxa_config_port(struct uart_port *port, int flags)
576ab4382d2SGreg Kroah-Hartman {
577ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
578ab4382d2SGreg Kroah-Hartman 	up->port.type = PORT_PXA;
579ab4382d2SGreg Kroah-Hartman }
580ab4382d2SGreg Kroah-Hartman 
581ab4382d2SGreg Kroah-Hartman static int
582ab4382d2SGreg Kroah-Hartman serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
583ab4382d2SGreg Kroah-Hartman {
584ab4382d2SGreg Kroah-Hartman 	/* we don't want the core code to modify any port params */
585ab4382d2SGreg Kroah-Hartman 	return -EINVAL;
586ab4382d2SGreg Kroah-Hartman }
587ab4382d2SGreg Kroah-Hartman 
588ab4382d2SGreg Kroah-Hartman static const char *
589ab4382d2SGreg Kroah-Hartman serial_pxa_type(struct uart_port *port)
590ab4382d2SGreg Kroah-Hartman {
591ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
592ab4382d2SGreg Kroah-Hartman 	return up->name;
593ab4382d2SGreg Kroah-Hartman }
594ab4382d2SGreg Kroah-Hartman 
595ab4382d2SGreg Kroah-Hartman static struct uart_pxa_port *serial_pxa_ports[4];
596ab4382d2SGreg Kroah-Hartman static struct uart_driver serial_pxa_reg;
597ab4382d2SGreg Kroah-Hartman 
598ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_SERIAL_PXA_CONSOLE
599ab4382d2SGreg Kroah-Hartman 
600ab4382d2SGreg Kroah-Hartman #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
601ab4382d2SGreg Kroah-Hartman 
602ab4382d2SGreg Kroah-Hartman /*
603ab4382d2SGreg Kroah-Hartman  *	Wait for transmitter & holding register to empty
604ab4382d2SGreg Kroah-Hartman  */
605be9ae5d9SDenys Vlasenko static void wait_for_xmitr(struct uart_pxa_port *up)
606ab4382d2SGreg Kroah-Hartman {
607ab4382d2SGreg Kroah-Hartman 	unsigned int status, tmout = 10000;
608ab4382d2SGreg Kroah-Hartman 
609ab4382d2SGreg Kroah-Hartman 	/* Wait up to 10ms for the character(s) to be sent. */
610ab4382d2SGreg Kroah-Hartman 	do {
611ab4382d2SGreg Kroah-Hartman 		status = serial_in(up, UART_LSR);
612ab4382d2SGreg Kroah-Hartman 
613ab4382d2SGreg Kroah-Hartman 		if (status & UART_LSR_BI)
614ab4382d2SGreg Kroah-Hartman 			up->lsr_break_flag = UART_LSR_BI;
615ab4382d2SGreg Kroah-Hartman 
616ab4382d2SGreg Kroah-Hartman 		if (--tmout == 0)
617ab4382d2SGreg Kroah-Hartman 			break;
618ab4382d2SGreg Kroah-Hartman 		udelay(1);
619ab4382d2SGreg Kroah-Hartman 	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
620ab4382d2SGreg Kroah-Hartman 
621ab4382d2SGreg Kroah-Hartman 	/* Wait up to 1s for flow control if necessary */
622ab4382d2SGreg Kroah-Hartman 	if (up->port.flags & UPF_CONS_FLOW) {
623ab4382d2SGreg Kroah-Hartman 		tmout = 1000000;
624ab4382d2SGreg Kroah-Hartman 		while (--tmout &&
625ab4382d2SGreg Kroah-Hartman 		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
626ab4382d2SGreg Kroah-Hartman 			udelay(1);
627ab4382d2SGreg Kroah-Hartman 	}
628ab4382d2SGreg Kroah-Hartman }
629ab4382d2SGreg Kroah-Hartman 
630ab4382d2SGreg Kroah-Hartman static void serial_pxa_console_putchar(struct uart_port *port, int ch)
631ab4382d2SGreg Kroah-Hartman {
632ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
633ab4382d2SGreg Kroah-Hartman 
634ab4382d2SGreg Kroah-Hartman 	wait_for_xmitr(up);
635ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_TX, ch);
636ab4382d2SGreg Kroah-Hartman }
637ab4382d2SGreg Kroah-Hartman 
638ab4382d2SGreg Kroah-Hartman /*
639ab4382d2SGreg Kroah-Hartman  * Print a string to the serial port trying not to disturb
640ab4382d2SGreg Kroah-Hartman  * any possible real use of the port...
641ab4382d2SGreg Kroah-Hartman  *
642ab4382d2SGreg Kroah-Hartman  *	The console_lock must be held when we get here.
643ab4382d2SGreg Kroah-Hartman  */
644ab4382d2SGreg Kroah-Hartman static void
645ab4382d2SGreg Kroah-Hartman serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
646ab4382d2SGreg Kroah-Hartman {
647ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up = serial_pxa_ports[co->index];
648ab4382d2SGreg Kroah-Hartman 	unsigned int ier;
649cfe275c2SChao Xie 	unsigned long flags;
650cfe275c2SChao Xie 	int locked = 1;
651ab4382d2SGreg Kroah-Hartman 
6529429ccbfSYi Zhang 	clk_enable(up->clk);
653cfe275c2SChao Xie 	local_irq_save(flags);
654cfe275c2SChao Xie 	if (up->port.sysrq)
655cfe275c2SChao Xie 		locked = 0;
656cfe275c2SChao Xie 	else if (oops_in_progress)
657cfe275c2SChao Xie 		locked = spin_trylock(&up->port.lock);
658cfe275c2SChao Xie 	else
659cfe275c2SChao Xie 		spin_lock(&up->port.lock);
660cfe275c2SChao Xie 
661ab4382d2SGreg Kroah-Hartman 	/*
662ab4382d2SGreg Kroah-Hartman 	 *	First save the IER then disable the interrupts
663ab4382d2SGreg Kroah-Hartman 	 */
664ab4382d2SGreg Kroah-Hartman 	ier = serial_in(up, UART_IER);
665ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, UART_IER_UUE);
666ab4382d2SGreg Kroah-Hartman 
667ab4382d2SGreg Kroah-Hartman 	uart_console_write(&up->port, s, count, serial_pxa_console_putchar);
668ab4382d2SGreg Kroah-Hartman 
669ab4382d2SGreg Kroah-Hartman 	/*
670ab4382d2SGreg Kroah-Hartman 	 *	Finally, wait for transmitter to become empty
671ab4382d2SGreg Kroah-Hartman 	 *	and restore the IER
672ab4382d2SGreg Kroah-Hartman 	 */
673ab4382d2SGreg Kroah-Hartman 	wait_for_xmitr(up);
674ab4382d2SGreg Kroah-Hartman 	serial_out(up, UART_IER, ier);
675ab4382d2SGreg Kroah-Hartman 
676cfe275c2SChao Xie 	if (locked)
677cfe275c2SChao Xie 		spin_unlock(&up->port.lock);
678cfe275c2SChao Xie 	local_irq_restore(flags);
6799429ccbfSYi Zhang 	clk_disable(up->clk);
680cfe275c2SChao Xie 
681ab4382d2SGreg Kroah-Hartman }
682ab4382d2SGreg Kroah-Hartman 
683e1a9c179SDenis V. Lunev #ifdef CONFIG_CONSOLE_POLL
684e1a9c179SDenis V. Lunev /*
685e1a9c179SDenis V. Lunev  * Console polling routines for writing and reading from the uart while
686e1a9c179SDenis V. Lunev  * in an interrupt or debug context.
687e1a9c179SDenis V. Lunev  */
688e1a9c179SDenis V. Lunev 
689e1a9c179SDenis V. Lunev static int serial_pxa_get_poll_char(struct uart_port *port)
690e1a9c179SDenis V. Lunev {
691e1a9c179SDenis V. Lunev 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
692e1a9c179SDenis V. Lunev 	unsigned char lsr = serial_in(up, UART_LSR);
693e1a9c179SDenis V. Lunev 
694e1a9c179SDenis V. Lunev 	while (!(lsr & UART_LSR_DR))
695e1a9c179SDenis V. Lunev 		lsr = serial_in(up, UART_LSR);
696e1a9c179SDenis V. Lunev 
697e1a9c179SDenis V. Lunev 	return serial_in(up, UART_RX);
698e1a9c179SDenis V. Lunev }
699e1a9c179SDenis V. Lunev 
700e1a9c179SDenis V. Lunev 
701e1a9c179SDenis V. Lunev static void serial_pxa_put_poll_char(struct uart_port *port,
702e1a9c179SDenis V. Lunev 			 unsigned char c)
703e1a9c179SDenis V. Lunev {
704e1a9c179SDenis V. Lunev 	unsigned int ier;
705e1a9c179SDenis V. Lunev 	struct uart_pxa_port *up = (struct uart_pxa_port *)port;
706e1a9c179SDenis V. Lunev 
707e1a9c179SDenis V. Lunev 	/*
708e1a9c179SDenis V. Lunev 	 *	First save the IER then disable the interrupts
709e1a9c179SDenis V. Lunev 	 */
710e1a9c179SDenis V. Lunev 	ier = serial_in(up, UART_IER);
711e1a9c179SDenis V. Lunev 	serial_out(up, UART_IER, UART_IER_UUE);
712e1a9c179SDenis V. Lunev 
713e1a9c179SDenis V. Lunev 	wait_for_xmitr(up);
714e1a9c179SDenis V. Lunev 	/*
715e1a9c179SDenis V. Lunev 	 *	Send the character out.
716e1a9c179SDenis V. Lunev 	 */
717e1a9c179SDenis V. Lunev 	serial_out(up, UART_TX, c);
718e1a9c179SDenis V. Lunev 
719e1a9c179SDenis V. Lunev 	/*
720e1a9c179SDenis V. Lunev 	 *	Finally, wait for transmitter to become empty
721e1a9c179SDenis V. Lunev 	 *	and restore the IER
722e1a9c179SDenis V. Lunev 	 */
723e1a9c179SDenis V. Lunev 	wait_for_xmitr(up);
724e1a9c179SDenis V. Lunev 	serial_out(up, UART_IER, ier);
725e1a9c179SDenis V. Lunev }
726e1a9c179SDenis V. Lunev 
727e1a9c179SDenis V. Lunev #endif /* CONFIG_CONSOLE_POLL */
728e1a9c179SDenis V. Lunev 
729ab4382d2SGreg Kroah-Hartman static int __init
730ab4382d2SGreg Kroah-Hartman serial_pxa_console_setup(struct console *co, char *options)
731ab4382d2SGreg Kroah-Hartman {
732ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *up;
733ab4382d2SGreg Kroah-Hartman 	int baud = 9600;
734ab4382d2SGreg Kroah-Hartman 	int bits = 8;
735ab4382d2SGreg Kroah-Hartman 	int parity = 'n';
736ab4382d2SGreg Kroah-Hartman 	int flow = 'n';
737ab4382d2SGreg Kroah-Hartman 
738ab4382d2SGreg Kroah-Hartman 	if (co->index == -1 || co->index >= serial_pxa_reg.nr)
739ab4382d2SGreg Kroah-Hartman 		co->index = 0;
740ab4382d2SGreg Kroah-Hartman 	up = serial_pxa_ports[co->index];
741ab4382d2SGreg Kroah-Hartman 	if (!up)
742ab4382d2SGreg Kroah-Hartman 		return -ENODEV;
743ab4382d2SGreg Kroah-Hartman 
744ab4382d2SGreg Kroah-Hartman 	if (options)
745ab4382d2SGreg Kroah-Hartman 		uart_parse_options(options, &baud, &parity, &bits, &flow);
746ab4382d2SGreg Kroah-Hartman 
747ab4382d2SGreg Kroah-Hartman 	return uart_set_options(&up->port, co, baud, parity, bits, flow);
748ab4382d2SGreg Kroah-Hartman }
749ab4382d2SGreg Kroah-Hartman 
750ab4382d2SGreg Kroah-Hartman static struct console serial_pxa_console = {
751ab4382d2SGreg Kroah-Hartman 	.name		= "ttyS",
752ab4382d2SGreg Kroah-Hartman 	.write		= serial_pxa_console_write,
753ab4382d2SGreg Kroah-Hartman 	.device		= uart_console_device,
754ab4382d2SGreg Kroah-Hartman 	.setup		= serial_pxa_console_setup,
755ab4382d2SGreg Kroah-Hartman 	.flags		= CON_PRINTBUFFER,
756ab4382d2SGreg Kroah-Hartman 	.index		= -1,
757ab4382d2SGreg Kroah-Hartman 	.data		= &serial_pxa_reg,
758ab4382d2SGreg Kroah-Hartman };
759ab4382d2SGreg Kroah-Hartman 
760ab4382d2SGreg Kroah-Hartman #define PXA_CONSOLE	&serial_pxa_console
761ab4382d2SGreg Kroah-Hartman #else
762ab4382d2SGreg Kroah-Hartman #define PXA_CONSOLE	NULL
763ab4382d2SGreg Kroah-Hartman #endif
764ab4382d2SGreg Kroah-Hartman 
7656c62cc0dSJingoo Han static struct uart_ops serial_pxa_pops = {
766ab4382d2SGreg Kroah-Hartman 	.tx_empty	= serial_pxa_tx_empty,
767ab4382d2SGreg Kroah-Hartman 	.set_mctrl	= serial_pxa_set_mctrl,
768ab4382d2SGreg Kroah-Hartman 	.get_mctrl	= serial_pxa_get_mctrl,
769ab4382d2SGreg Kroah-Hartman 	.stop_tx	= serial_pxa_stop_tx,
770ab4382d2SGreg Kroah-Hartman 	.start_tx	= serial_pxa_start_tx,
771ab4382d2SGreg Kroah-Hartman 	.stop_rx	= serial_pxa_stop_rx,
772ab4382d2SGreg Kroah-Hartman 	.enable_ms	= serial_pxa_enable_ms,
773ab4382d2SGreg Kroah-Hartman 	.break_ctl	= serial_pxa_break_ctl,
774ab4382d2SGreg Kroah-Hartman 	.startup	= serial_pxa_startup,
775ab4382d2SGreg Kroah-Hartman 	.shutdown	= serial_pxa_shutdown,
776ab4382d2SGreg Kroah-Hartman 	.set_termios	= serial_pxa_set_termios,
777ab4382d2SGreg Kroah-Hartman 	.pm		= serial_pxa_pm,
778ab4382d2SGreg Kroah-Hartman 	.type		= serial_pxa_type,
779ab4382d2SGreg Kroah-Hartman 	.release_port	= serial_pxa_release_port,
780ab4382d2SGreg Kroah-Hartman 	.request_port	= serial_pxa_request_port,
781ab4382d2SGreg Kroah-Hartman 	.config_port	= serial_pxa_config_port,
782ab4382d2SGreg Kroah-Hartman 	.verify_port	= serial_pxa_verify_port,
7832ee881b7SArnd Bergmann #if defined(CONFIG_CONSOLE_POLL) && defined(CONFIG_SERIAL_PXA_CONSOLE)
784e1a9c179SDenis V. Lunev 	.poll_get_char = serial_pxa_get_poll_char,
785e1a9c179SDenis V. Lunev 	.poll_put_char = serial_pxa_put_poll_char,
786e1a9c179SDenis V. Lunev #endif
787ab4382d2SGreg Kroah-Hartman };
788ab4382d2SGreg Kroah-Hartman 
789ab4382d2SGreg Kroah-Hartman static struct uart_driver serial_pxa_reg = {
790ab4382d2SGreg Kroah-Hartman 	.owner		= THIS_MODULE,
791ab4382d2SGreg Kroah-Hartman 	.driver_name	= "PXA serial",
792ab4382d2SGreg Kroah-Hartman 	.dev_name	= "ttyS",
793ab4382d2SGreg Kroah-Hartman 	.major		= TTY_MAJOR,
794ab4382d2SGreg Kroah-Hartman 	.minor		= 64,
795ab4382d2SGreg Kroah-Hartman 	.nr		= 4,
796ab4382d2SGreg Kroah-Hartman 	.cons		= PXA_CONSOLE,
797ab4382d2SGreg Kroah-Hartman };
798ab4382d2SGreg Kroah-Hartman 
799ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM
800ab4382d2SGreg Kroah-Hartman static int serial_pxa_suspend(struct device *dev)
801ab4382d2SGreg Kroah-Hartman {
802ab4382d2SGreg Kroah-Hartman         struct uart_pxa_port *sport = dev_get_drvdata(dev);
803ab4382d2SGreg Kroah-Hartman 
804ab4382d2SGreg Kroah-Hartman         if (sport)
805ab4382d2SGreg Kroah-Hartman                 uart_suspend_port(&serial_pxa_reg, &sport->port);
806ab4382d2SGreg Kroah-Hartman 
807ab4382d2SGreg Kroah-Hartman         return 0;
808ab4382d2SGreg Kroah-Hartman }
809ab4382d2SGreg Kroah-Hartman 
810ab4382d2SGreg Kroah-Hartman static int serial_pxa_resume(struct device *dev)
811ab4382d2SGreg Kroah-Hartman {
812ab4382d2SGreg Kroah-Hartman         struct uart_pxa_port *sport = dev_get_drvdata(dev);
813ab4382d2SGreg Kroah-Hartman 
814ab4382d2SGreg Kroah-Hartman         if (sport)
815ab4382d2SGreg Kroah-Hartman                 uart_resume_port(&serial_pxa_reg, &sport->port);
816ab4382d2SGreg Kroah-Hartman 
817ab4382d2SGreg Kroah-Hartman         return 0;
818ab4382d2SGreg Kroah-Hartman }
819ab4382d2SGreg Kroah-Hartman 
820ab4382d2SGreg Kroah-Hartman static const struct dev_pm_ops serial_pxa_pm_ops = {
821ab4382d2SGreg Kroah-Hartman 	.suspend	= serial_pxa_suspend,
822ab4382d2SGreg Kroah-Hartman 	.resume		= serial_pxa_resume,
823ab4382d2SGreg Kroah-Hartman };
824ab4382d2SGreg Kroah-Hartman #endif
825ab4382d2SGreg Kroah-Hartman 
826ed0bb232SFabian Frederick static const struct of_device_id serial_pxa_dt_ids[] = {
827699c20f3SHaojian Zhuang 	{ .compatible = "mrvl,pxa-uart", },
828699c20f3SHaojian Zhuang 	{ .compatible = "mrvl,mmp-uart", },
829699c20f3SHaojian Zhuang 	{}
830699c20f3SHaojian Zhuang };
831699c20f3SHaojian Zhuang 
832699c20f3SHaojian Zhuang static int serial_pxa_probe_dt(struct platform_device *pdev,
833699c20f3SHaojian Zhuang 			       struct uart_pxa_port *sport)
834699c20f3SHaojian Zhuang {
835699c20f3SHaojian Zhuang 	struct device_node *np = pdev->dev.of_node;
836699c20f3SHaojian Zhuang 	int ret;
837699c20f3SHaojian Zhuang 
838699c20f3SHaojian Zhuang 	if (!np)
839699c20f3SHaojian Zhuang 		return 1;
840699c20f3SHaojian Zhuang 
841699c20f3SHaojian Zhuang 	ret = of_alias_get_id(np, "serial");
842699c20f3SHaojian Zhuang 	if (ret < 0) {
843699c20f3SHaojian Zhuang 		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
844699c20f3SHaojian Zhuang 		return ret;
845699c20f3SHaojian Zhuang 	}
846699c20f3SHaojian Zhuang 	sport->port.line = ret;
847699c20f3SHaojian Zhuang 	return 0;
848699c20f3SHaojian Zhuang }
849699c20f3SHaojian Zhuang 
850ab4382d2SGreg Kroah-Hartman static int serial_pxa_probe(struct platform_device *dev)
851ab4382d2SGreg Kroah-Hartman {
852ab4382d2SGreg Kroah-Hartman 	struct uart_pxa_port *sport;
853ab4382d2SGreg Kroah-Hartman 	struct resource *mmres, *irqres;
854ab4382d2SGreg Kroah-Hartman 	int ret;
855ab4382d2SGreg Kroah-Hartman 
856ab4382d2SGreg Kroah-Hartman 	mmres = platform_get_resource(dev, IORESOURCE_MEM, 0);
857ab4382d2SGreg Kroah-Hartman 	irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0);
858ab4382d2SGreg Kroah-Hartman 	if (!mmres || !irqres)
859ab4382d2SGreg Kroah-Hartman 		return -ENODEV;
860ab4382d2SGreg Kroah-Hartman 
861ab4382d2SGreg Kroah-Hartman 	sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL);
862ab4382d2SGreg Kroah-Hartman 	if (!sport)
863ab4382d2SGreg Kroah-Hartman 		return -ENOMEM;
864ab4382d2SGreg Kroah-Hartman 
865ab4382d2SGreg Kroah-Hartman 	sport->clk = clk_get(&dev->dev, NULL);
866ab4382d2SGreg Kroah-Hartman 	if (IS_ERR(sport->clk)) {
867ab4382d2SGreg Kroah-Hartman 		ret = PTR_ERR(sport->clk);
868ab4382d2SGreg Kroah-Hartman 		goto err_free;
869ab4382d2SGreg Kroah-Hartman 	}
870ab4382d2SGreg Kroah-Hartman 
8719429ccbfSYi Zhang 	ret = clk_prepare(sport->clk);
8729429ccbfSYi Zhang 	if (ret) {
8739429ccbfSYi Zhang 		clk_put(sport->clk);
8749429ccbfSYi Zhang 		goto err_free;
8759429ccbfSYi Zhang 	}
8769429ccbfSYi Zhang 
877ab4382d2SGreg Kroah-Hartman 	sport->port.type = PORT_PXA;
878ab4382d2SGreg Kroah-Hartman 	sport->port.iotype = UPIO_MEM;
879ab4382d2SGreg Kroah-Hartman 	sport->port.mapbase = mmres->start;
880ab4382d2SGreg Kroah-Hartman 	sport->port.irq = irqres->start;
881ab4382d2SGreg Kroah-Hartman 	sport->port.fifosize = 64;
882ab4382d2SGreg Kroah-Hartman 	sport->port.ops = &serial_pxa_pops;
883ab4382d2SGreg Kroah-Hartman 	sport->port.dev = &dev->dev;
884ab4382d2SGreg Kroah-Hartman 	sport->port.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
885ab4382d2SGreg Kroah-Hartman 	sport->port.uartclk = clk_get_rate(sport->clk);
886ab4382d2SGreg Kroah-Hartman 
887699c20f3SHaojian Zhuang 	ret = serial_pxa_probe_dt(dev, sport);
888699c20f3SHaojian Zhuang 	if (ret > 0)
889699c20f3SHaojian Zhuang 		sport->port.line = dev->id;
890699c20f3SHaojian Zhuang 	else if (ret < 0)
891699c20f3SHaojian Zhuang 		goto err_clk;
892699c20f3SHaojian Zhuang 	snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
893ab4382d2SGreg Kroah-Hartman 
89428f65c11SJoe Perches 	sport->port.membase = ioremap(mmres->start, resource_size(mmres));
895ab4382d2SGreg Kroah-Hartman 	if (!sport->port.membase) {
896ab4382d2SGreg Kroah-Hartman 		ret = -ENOMEM;
897ab4382d2SGreg Kroah-Hartman 		goto err_clk;
898ab4382d2SGreg Kroah-Hartman 	}
899ab4382d2SGreg Kroah-Hartman 
900699c20f3SHaojian Zhuang 	serial_pxa_ports[sport->port.line] = sport;
901ab4382d2SGreg Kroah-Hartman 
902ab4382d2SGreg Kroah-Hartman 	uart_add_one_port(&serial_pxa_reg, &sport->port);
903ab4382d2SGreg Kroah-Hartman 	platform_set_drvdata(dev, sport);
904ab4382d2SGreg Kroah-Hartman 
905ab4382d2SGreg Kroah-Hartman 	return 0;
906ab4382d2SGreg Kroah-Hartman 
907ab4382d2SGreg Kroah-Hartman  err_clk:
9089429ccbfSYi Zhang 	clk_unprepare(sport->clk);
909ab4382d2SGreg Kroah-Hartman 	clk_put(sport->clk);
910ab4382d2SGreg Kroah-Hartman  err_free:
911ab4382d2SGreg Kroah-Hartman 	kfree(sport);
912ab4382d2SGreg Kroah-Hartman 	return ret;
913ab4382d2SGreg Kroah-Hartman }
914ab4382d2SGreg Kroah-Hartman 
915ab4382d2SGreg Kroah-Hartman static struct platform_driver serial_pxa_driver = {
916ab4382d2SGreg Kroah-Hartman         .probe          = serial_pxa_probe,
917ab4382d2SGreg Kroah-Hartman 
918ab4382d2SGreg Kroah-Hartman 	.driver		= {
919ab4382d2SGreg Kroah-Hartman 	        .name	= "pxa2xx-uart",
920ab4382d2SGreg Kroah-Hartman #ifdef CONFIG_PM
921ab4382d2SGreg Kroah-Hartman 		.pm	= &serial_pxa_pm_ops,
922ab4382d2SGreg Kroah-Hartman #endif
923*ca16c5a3SPaul Gortmaker 		.suppress_bind_attrs = true,
924699c20f3SHaojian Zhuang 		.of_match_table = serial_pxa_dt_ids,
925ab4382d2SGreg Kroah-Hartman 	},
926ab4382d2SGreg Kroah-Hartman };
927ab4382d2SGreg Kroah-Hartman 
9286c62cc0dSJingoo Han static int __init serial_pxa_init(void)
929ab4382d2SGreg Kroah-Hartman {
930ab4382d2SGreg Kroah-Hartman 	int ret;
931ab4382d2SGreg Kroah-Hartman 
932ab4382d2SGreg Kroah-Hartman 	ret = uart_register_driver(&serial_pxa_reg);
933ab4382d2SGreg Kroah-Hartman 	if (ret != 0)
934ab4382d2SGreg Kroah-Hartman 		return ret;
935ab4382d2SGreg Kroah-Hartman 
936ab4382d2SGreg Kroah-Hartman 	ret = platform_driver_register(&serial_pxa_driver);
937ab4382d2SGreg Kroah-Hartman 	if (ret != 0)
938ab4382d2SGreg Kroah-Hartman 		uart_unregister_driver(&serial_pxa_reg);
939ab4382d2SGreg Kroah-Hartman 
940ab4382d2SGreg Kroah-Hartman 	return ret;
941ab4382d2SGreg Kroah-Hartman }
942*ca16c5a3SPaul Gortmaker device_initcall(serial_pxa_init);
943