xref: /OK3568_Linux_fs/kernel/drivers/tty/serial/lpc32xx_hs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * High Speed Serial Ports on NXP LPC32xx SoC
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Authors: Kevin Wells <kevin.wells@nxp.com>
6*4882a593Smuzhiyun  *          Roland Stigge <stigge@antcom.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Copyright (C) 2010 NXP Semiconductors
9*4882a593Smuzhiyun  * Copyright (C) 2012 Roland Stigge
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/ioport.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/console.h>
16*4882a593Smuzhiyun #include <linux/sysrq.h>
17*4882a593Smuzhiyun #include <linux/tty.h>
18*4882a593Smuzhiyun #include <linux/tty_flip.h>
19*4882a593Smuzhiyun #include <linux/serial_core.h>
20*4882a593Smuzhiyun #include <linux/serial.h>
21*4882a593Smuzhiyun #include <linux/platform_device.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/nmi.h>
24*4882a593Smuzhiyun #include <linux/io.h>
25*4882a593Smuzhiyun #include <linux/irq.h>
26*4882a593Smuzhiyun #include <linux/of.h>
27*4882a593Smuzhiyun #include <linux/sizes.h>
28*4882a593Smuzhiyun #include <linux/soc/nxp/lpc32xx-misc.h>
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /*
31*4882a593Smuzhiyun  * High Speed UART register offsets
32*4882a593Smuzhiyun  */
33*4882a593Smuzhiyun #define LPC32XX_HSUART_FIFO(x)			((x) + 0x00)
34*4882a593Smuzhiyun #define LPC32XX_HSUART_LEVEL(x)			((x) + 0x04)
35*4882a593Smuzhiyun #define LPC32XX_HSUART_IIR(x)			((x) + 0x08)
36*4882a593Smuzhiyun #define LPC32XX_HSUART_CTRL(x)			((x) + 0x0C)
37*4882a593Smuzhiyun #define LPC32XX_HSUART_RATE(x)			((x) + 0x10)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define LPC32XX_HSU_BREAK_DATA			(1 << 10)
40*4882a593Smuzhiyun #define LPC32XX_HSU_ERROR_DATA			(1 << 9)
41*4882a593Smuzhiyun #define LPC32XX_HSU_RX_EMPTY			(1 << 8)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define LPC32XX_HSU_TX_LEV(n)			(((n) >> 8) & 0xFF)
44*4882a593Smuzhiyun #define LPC32XX_HSU_RX_LEV(n)			((n) & 0xFF)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define LPC32XX_HSU_TX_INT_SET			(1 << 6)
47*4882a593Smuzhiyun #define LPC32XX_HSU_RX_OE_INT			(1 << 5)
48*4882a593Smuzhiyun #define LPC32XX_HSU_BRK_INT			(1 << 4)
49*4882a593Smuzhiyun #define LPC32XX_HSU_FE_INT			(1 << 3)
50*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TIMEOUT_INT		(1 << 2)
51*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TRIG_INT			(1 << 1)
52*4882a593Smuzhiyun #define LPC32XX_HSU_TX_INT			(1 << 0)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_INV			(1 << 21)
55*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_TRIG_8B		(0x0 << 19)
56*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_TRIG_16B		(0x1 << 19)
57*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_TRIG_32B		(0x2 << 19)
58*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_TRIG_48B		(0x3 << 19)
59*4882a593Smuzhiyun #define LPC32XX_HSU_HRTS_EN			(1 << 18)
60*4882a593Smuzhiyun #define LPC32XX_HSU_TMO_DISABLED		(0x0 << 16)
61*4882a593Smuzhiyun #define LPC32XX_HSU_TMO_INACT_4B		(0x1 << 16)
62*4882a593Smuzhiyun #define LPC32XX_HSU_TMO_INACT_8B		(0x2 << 16)
63*4882a593Smuzhiyun #define LPC32XX_HSU_TMO_INACT_16B		(0x3 << 16)
64*4882a593Smuzhiyun #define LPC32XX_HSU_HCTS_INV			(1 << 15)
65*4882a593Smuzhiyun #define LPC32XX_HSU_HCTS_EN			(1 << 14)
66*4882a593Smuzhiyun #define LPC32XX_HSU_OFFSET(n)			((n) << 9)
67*4882a593Smuzhiyun #define LPC32XX_HSU_BREAK			(1 << 8)
68*4882a593Smuzhiyun #define LPC32XX_HSU_ERR_INT_EN			(1 << 7)
69*4882a593Smuzhiyun #define LPC32XX_HSU_RX_INT_EN			(1 << 6)
70*4882a593Smuzhiyun #define LPC32XX_HSU_TX_INT_EN			(1 << 5)
71*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL1B			(0x0 << 2)
72*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL4B			(0x1 << 2)
73*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL8B			(0x2 << 2)
74*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL16B			(0x3 << 2)
75*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL32B			(0x4 << 2)
76*4882a593Smuzhiyun #define LPC32XX_HSU_RX_TL48B			(0x5 << 2)
77*4882a593Smuzhiyun #define LPC32XX_HSU_TX_TLEMPTY			(0x0 << 0)
78*4882a593Smuzhiyun #define LPC32XX_HSU_TX_TL0B			(0x0 << 0)
79*4882a593Smuzhiyun #define LPC32XX_HSU_TX_TL4B			(0x1 << 0)
80*4882a593Smuzhiyun #define LPC32XX_HSU_TX_TL8B			(0x2 << 0)
81*4882a593Smuzhiyun #define LPC32XX_HSU_TX_TL16B			(0x3 << 0)
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define LPC32XX_MAIN_OSC_FREQ			13000000
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun #define MODNAME "lpc32xx_hsuart"
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun struct lpc32xx_hsuart_port {
88*4882a593Smuzhiyun 	struct uart_port port;
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun #define FIFO_READ_LIMIT 128
92*4882a593Smuzhiyun #define MAX_PORTS 3
93*4882a593Smuzhiyun #define LPC32XX_TTY_NAME "ttyTX"
94*4882a593Smuzhiyun static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
wait_for_xmit_empty(struct uart_port * port)97*4882a593Smuzhiyun static void wait_for_xmit_empty(struct uart_port *port)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun 	unsigned int timeout = 10000;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	do {
102*4882a593Smuzhiyun 		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
103*4882a593Smuzhiyun 							port->membase))) == 0)
104*4882a593Smuzhiyun 			break;
105*4882a593Smuzhiyun 		if (--timeout == 0)
106*4882a593Smuzhiyun 			break;
107*4882a593Smuzhiyun 		udelay(1);
108*4882a593Smuzhiyun 	} while (1);
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
wait_for_xmit_ready(struct uart_port * port)111*4882a593Smuzhiyun static void wait_for_xmit_ready(struct uart_port *port)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	unsigned int timeout = 10000;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	while (1) {
116*4882a593Smuzhiyun 		if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
117*4882a593Smuzhiyun 							port->membase))) < 32)
118*4882a593Smuzhiyun 			break;
119*4882a593Smuzhiyun 		if (--timeout == 0)
120*4882a593Smuzhiyun 			break;
121*4882a593Smuzhiyun 		udelay(1);
122*4882a593Smuzhiyun 	}
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
lpc32xx_hsuart_console_putchar(struct uart_port * port,int ch)125*4882a593Smuzhiyun static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	wait_for_xmit_ready(port);
128*4882a593Smuzhiyun 	writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
lpc32xx_hsuart_console_write(struct console * co,const char * s,unsigned int count)131*4882a593Smuzhiyun static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
132*4882a593Smuzhiyun 					 unsigned int count)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
135*4882a593Smuzhiyun 	unsigned long flags;
136*4882a593Smuzhiyun 	int locked = 1;
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	touch_nmi_watchdog();
139*4882a593Smuzhiyun 	local_irq_save(flags);
140*4882a593Smuzhiyun 	if (up->port.sysrq)
141*4882a593Smuzhiyun 		locked = 0;
142*4882a593Smuzhiyun 	else if (oops_in_progress)
143*4882a593Smuzhiyun 		locked = spin_trylock(&up->port.lock);
144*4882a593Smuzhiyun 	else
145*4882a593Smuzhiyun 		spin_lock(&up->port.lock);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
148*4882a593Smuzhiyun 	wait_for_xmit_empty(&up->port);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (locked)
151*4882a593Smuzhiyun 		spin_unlock(&up->port.lock);
152*4882a593Smuzhiyun 	local_irq_restore(flags);
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
lpc32xx_hsuart_console_setup(struct console * co,char * options)155*4882a593Smuzhiyun static int __init lpc32xx_hsuart_console_setup(struct console *co,
156*4882a593Smuzhiyun 					       char *options)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct uart_port *port;
159*4882a593Smuzhiyun 	int baud = 115200;
160*4882a593Smuzhiyun 	int bits = 8;
161*4882a593Smuzhiyun 	int parity = 'n';
162*4882a593Smuzhiyun 	int flow = 'n';
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (co->index >= MAX_PORTS)
165*4882a593Smuzhiyun 		co->index = 0;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	port = &lpc32xx_hs_ports[co->index].port;
168*4882a593Smuzhiyun 	if (!port->membase)
169*4882a593Smuzhiyun 		return -ENODEV;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (options)
172*4882a593Smuzhiyun 		uart_parse_options(options, &baud, &parity, &bits, &flow);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return uart_set_options(port, co, baud, parity, bits, flow);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun static struct uart_driver lpc32xx_hsuart_reg;
180*4882a593Smuzhiyun static struct console lpc32xx_hsuart_console = {
181*4882a593Smuzhiyun 	.name		= LPC32XX_TTY_NAME,
182*4882a593Smuzhiyun 	.write		= lpc32xx_hsuart_console_write,
183*4882a593Smuzhiyun 	.device		= uart_console_device,
184*4882a593Smuzhiyun 	.setup		= lpc32xx_hsuart_console_setup,
185*4882a593Smuzhiyun 	.flags		= CON_PRINTBUFFER,
186*4882a593Smuzhiyun 	.index		= -1,
187*4882a593Smuzhiyun 	.data		= &lpc32xx_hsuart_reg,
188*4882a593Smuzhiyun };
189*4882a593Smuzhiyun 
lpc32xx_hsuart_console_init(void)190*4882a593Smuzhiyun static int __init lpc32xx_hsuart_console_init(void)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	register_console(&lpc32xx_hsuart_console);
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun console_initcall(lpc32xx_hsuart_console_init);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun #define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
198*4882a593Smuzhiyun #else
199*4882a593Smuzhiyun #define LPC32XX_HSUART_CONSOLE NULL
200*4882a593Smuzhiyun #endif
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun static struct uart_driver lpc32xx_hs_reg = {
203*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
204*4882a593Smuzhiyun 	.driver_name	= MODNAME,
205*4882a593Smuzhiyun 	.dev_name	= LPC32XX_TTY_NAME,
206*4882a593Smuzhiyun 	.nr		= MAX_PORTS,
207*4882a593Smuzhiyun 	.cons		= LPC32XX_HSUART_CONSOLE,
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun static int uarts_registered;
210*4882a593Smuzhiyun 
__serial_get_clock_div(unsigned long uartclk,unsigned long rate)211*4882a593Smuzhiyun static unsigned int __serial_get_clock_div(unsigned long uartclk,
212*4882a593Smuzhiyun 					   unsigned long rate)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
215*4882a593Smuzhiyun 	u32 rate_diff;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	/* Find the closest divider to get the desired clock rate */
218*4882a593Smuzhiyun 	div = uartclk / rate;
219*4882a593Smuzhiyun 	goodrate = hsu_rate = (div / 14) - 1;
220*4882a593Smuzhiyun 	if (hsu_rate != 0)
221*4882a593Smuzhiyun 		hsu_rate--;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/* Tweak divider */
224*4882a593Smuzhiyun 	l_hsu_rate = hsu_rate + 3;
225*4882a593Smuzhiyun 	rate_diff = 0xFFFFFFFF;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	while (hsu_rate < l_hsu_rate) {
228*4882a593Smuzhiyun 		comprate = uartclk / ((hsu_rate + 1) * 14);
229*4882a593Smuzhiyun 		if (abs(comprate - rate) < rate_diff) {
230*4882a593Smuzhiyun 			goodrate = hsu_rate;
231*4882a593Smuzhiyun 			rate_diff = abs(comprate - rate);
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 		hsu_rate++;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 	if (hsu_rate > 0xFF)
237*4882a593Smuzhiyun 		hsu_rate = 0xFF;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return goodrate;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
__serial_uart_flush(struct uart_port * port)242*4882a593Smuzhiyun static void __serial_uart_flush(struct uart_port *port)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	u32 tmp;
245*4882a593Smuzhiyun 	int cnt = 0;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
248*4882a593Smuzhiyun 	       (cnt++ < FIFO_READ_LIMIT))
249*4882a593Smuzhiyun 		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
__serial_lpc32xx_rx(struct uart_port * port)252*4882a593Smuzhiyun static void __serial_lpc32xx_rx(struct uart_port *port)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	struct tty_port *tport = &port->state->port;
255*4882a593Smuzhiyun 	unsigned int tmp, flag;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* Read data from FIFO and push into terminal */
258*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
259*4882a593Smuzhiyun 	while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
260*4882a593Smuzhiyun 		flag = TTY_NORMAL;
261*4882a593Smuzhiyun 		port->icount.rx++;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 		if (tmp & LPC32XX_HSU_ERROR_DATA) {
264*4882a593Smuzhiyun 			/* Framing error */
265*4882a593Smuzhiyun 			writel(LPC32XX_HSU_FE_INT,
266*4882a593Smuzhiyun 			       LPC32XX_HSUART_IIR(port->membase));
267*4882a593Smuzhiyun 			port->icount.frame++;
268*4882a593Smuzhiyun 			flag = TTY_FRAME;
269*4882a593Smuzhiyun 			tty_insert_flip_char(tport, 0, TTY_FRAME);
270*4882a593Smuzhiyun 		}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		tty_insert_flip_char(tport, (tmp & 0xFF), flag);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 		tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	spin_unlock(&port->lock);
278*4882a593Smuzhiyun 	tty_flip_buffer_push(tport);
279*4882a593Smuzhiyun 	spin_lock(&port->lock);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
__serial_lpc32xx_tx(struct uart_port * port)282*4882a593Smuzhiyun static void __serial_lpc32xx_tx(struct uart_port *port)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun 	struct circ_buf *xmit = &port->state->xmit;
285*4882a593Smuzhiyun 	unsigned int tmp;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	if (port->x_char) {
288*4882a593Smuzhiyun 		writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
289*4882a593Smuzhiyun 		port->icount.tx++;
290*4882a593Smuzhiyun 		port->x_char = 0;
291*4882a593Smuzhiyun 		return;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	if (uart_circ_empty(xmit) || uart_tx_stopped(port))
295*4882a593Smuzhiyun 		goto exit_tx;
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	/* Transfer data */
298*4882a593Smuzhiyun 	while (LPC32XX_HSU_TX_LEV(readl(
299*4882a593Smuzhiyun 		LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
300*4882a593Smuzhiyun 		writel((u32) xmit->buf[xmit->tail],
301*4882a593Smuzhiyun 		       LPC32XX_HSUART_FIFO(port->membase));
302*4882a593Smuzhiyun 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
303*4882a593Smuzhiyun 		port->icount.tx++;
304*4882a593Smuzhiyun 		if (uart_circ_empty(xmit))
305*4882a593Smuzhiyun 			break;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
309*4882a593Smuzhiyun 		uart_write_wakeup(port);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun exit_tx:
312*4882a593Smuzhiyun 	if (uart_circ_empty(xmit)) {
313*4882a593Smuzhiyun 		tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
314*4882a593Smuzhiyun 		tmp &= ~LPC32XX_HSU_TX_INT_EN;
315*4882a593Smuzhiyun 		writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
serial_lpc32xx_interrupt(int irq,void * dev_id)319*4882a593Smuzhiyun static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct uart_port *port = dev_id;
322*4882a593Smuzhiyun 	struct tty_port *tport = &port->state->port;
323*4882a593Smuzhiyun 	u32 status;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	spin_lock(&port->lock);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	/* Read UART status and clear latched interrupts */
328*4882a593Smuzhiyun 	status = readl(LPC32XX_HSUART_IIR(port->membase));
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	if (status & LPC32XX_HSU_BRK_INT) {
331*4882a593Smuzhiyun 		/* Break received */
332*4882a593Smuzhiyun 		writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
333*4882a593Smuzhiyun 		port->icount.brk++;
334*4882a593Smuzhiyun 		uart_handle_break(port);
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	/* Framing error */
338*4882a593Smuzhiyun 	if (status & LPC32XX_HSU_FE_INT)
339*4882a593Smuzhiyun 		writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	if (status & LPC32XX_HSU_RX_OE_INT) {
342*4882a593Smuzhiyun 		/* Receive FIFO overrun */
343*4882a593Smuzhiyun 		writel(LPC32XX_HSU_RX_OE_INT,
344*4882a593Smuzhiyun 		       LPC32XX_HSUART_IIR(port->membase));
345*4882a593Smuzhiyun 		port->icount.overrun++;
346*4882a593Smuzhiyun 		tty_insert_flip_char(tport, 0, TTY_OVERRUN);
347*4882a593Smuzhiyun 		tty_flip_buffer_push(tport);
348*4882a593Smuzhiyun 	}
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	/* Data received? */
351*4882a593Smuzhiyun 	if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT))
352*4882a593Smuzhiyun 		__serial_lpc32xx_rx(port);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	/* Transmit data request? */
355*4882a593Smuzhiyun 	if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
356*4882a593Smuzhiyun 		writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
357*4882a593Smuzhiyun 		__serial_lpc32xx_tx(port);
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	spin_unlock(&port->lock);
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	return IRQ_HANDLED;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun /* port->lock is not held.  */
serial_lpc32xx_tx_empty(struct uart_port * port)366*4882a593Smuzhiyun static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	unsigned int ret = 0;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
371*4882a593Smuzhiyun 		ret = TIOCSER_TEMT;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	return ret;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun /* port->lock held by caller.  */
serial_lpc32xx_set_mctrl(struct uart_port * port,unsigned int mctrl)377*4882a593Smuzhiyun static void serial_lpc32xx_set_mctrl(struct uart_port *port,
378*4882a593Smuzhiyun 				     unsigned int mctrl)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun 	/* No signals are supported on HS UARTs */
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* port->lock is held by caller and interrupts are disabled.  */
serial_lpc32xx_get_mctrl(struct uart_port * port)384*4882a593Smuzhiyun static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	/* No signals are supported on HS UARTs */
387*4882a593Smuzhiyun 	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun /* port->lock held by caller.  */
serial_lpc32xx_stop_tx(struct uart_port * port)391*4882a593Smuzhiyun static void serial_lpc32xx_stop_tx(struct uart_port *port)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	u32 tmp;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
396*4882a593Smuzhiyun 	tmp &= ~LPC32XX_HSU_TX_INT_EN;
397*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun /* port->lock held by caller.  */
serial_lpc32xx_start_tx(struct uart_port * port)401*4882a593Smuzhiyun static void serial_lpc32xx_start_tx(struct uart_port *port)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	u32 tmp;
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	__serial_lpc32xx_tx(port);
406*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
407*4882a593Smuzhiyun 	tmp |= LPC32XX_HSU_TX_INT_EN;
408*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun /* port->lock held by caller.  */
serial_lpc32xx_stop_rx(struct uart_port * port)412*4882a593Smuzhiyun static void serial_lpc32xx_stop_rx(struct uart_port *port)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	u32 tmp;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
417*4882a593Smuzhiyun 	tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
418*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
421*4882a593Smuzhiyun 		LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /* port->lock is not held.  */
serial_lpc32xx_break_ctl(struct uart_port * port,int break_state)425*4882a593Smuzhiyun static void serial_lpc32xx_break_ctl(struct uart_port *port,
426*4882a593Smuzhiyun 				     int break_state)
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	unsigned long flags;
429*4882a593Smuzhiyun 	u32 tmp;
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
432*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
433*4882a593Smuzhiyun 	if (break_state != 0)
434*4882a593Smuzhiyun 		tmp |= LPC32XX_HSU_BREAK;
435*4882a593Smuzhiyun 	else
436*4882a593Smuzhiyun 		tmp &= ~LPC32XX_HSU_BREAK;
437*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
438*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun /* port->lock is not held.  */
serial_lpc32xx_startup(struct uart_port * port)442*4882a593Smuzhiyun static int serial_lpc32xx_startup(struct uart_port *port)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun 	int retval;
445*4882a593Smuzhiyun 	unsigned long flags;
446*4882a593Smuzhiyun 	u32 tmp;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	__serial_uart_flush(port);
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
453*4882a593Smuzhiyun 		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
454*4882a593Smuzhiyun 	       LPC32XX_HSUART_IIR(port->membase));
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	/*
459*4882a593Smuzhiyun 	 * Set receiver timeout, HSU offset of 20, no break, no interrupts,
460*4882a593Smuzhiyun 	 * and default FIFO trigger levels
461*4882a593Smuzhiyun 	 */
462*4882a593Smuzhiyun 	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
463*4882a593Smuzhiyun 		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
464*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	retval = request_irq(port->irq, serial_lpc32xx_interrupt,
471*4882a593Smuzhiyun 			     0, MODNAME, port);
472*4882a593Smuzhiyun 	if (!retval)
473*4882a593Smuzhiyun 		writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
474*4882a593Smuzhiyun 		       LPC32XX_HSUART_CTRL(port->membase));
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	return retval;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun /* port->lock is not held.  */
serial_lpc32xx_shutdown(struct uart_port * port)480*4882a593Smuzhiyun static void serial_lpc32xx_shutdown(struct uart_port *port)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	u32 tmp;
483*4882a593Smuzhiyun 	unsigned long flags;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
488*4882a593Smuzhiyun 		LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
489*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	free_irq(port->irq, port);
496*4882a593Smuzhiyun }
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun /* port->lock is not held.  */
serial_lpc32xx_set_termios(struct uart_port * port,struct ktermios * termios,struct ktermios * old)499*4882a593Smuzhiyun static void serial_lpc32xx_set_termios(struct uart_port *port,
500*4882a593Smuzhiyun 				       struct ktermios *termios,
501*4882a593Smuzhiyun 				       struct ktermios *old)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun 	unsigned long flags;
504*4882a593Smuzhiyun 	unsigned int baud, quot;
505*4882a593Smuzhiyun 	u32 tmp;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	/* Always 8-bit, no parity, 1 stop bit */
508*4882a593Smuzhiyun 	termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
509*4882a593Smuzhiyun 	termios->c_cflag |= CS8;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	baud = uart_get_baud_rate(port, termios, old, 0,
514*4882a593Smuzhiyun 				  port->uartclk / 14);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	quot = __serial_get_clock_div(port->uartclk, baud);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	spin_lock_irqsave(&port->lock, flags);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 	/* Ignore characters? */
521*4882a593Smuzhiyun 	tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
522*4882a593Smuzhiyun 	if ((termios->c_cflag & CREAD) == 0)
523*4882a593Smuzhiyun 		tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
524*4882a593Smuzhiyun 	else
525*4882a593Smuzhiyun 		tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
526*4882a593Smuzhiyun 	writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	writel(quot, LPC32XX_HSUART_RATE(port->membase));
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	uart_update_timeout(port, termios->c_cflag, baud);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	spin_unlock_irqrestore(&port->lock, flags);
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	/* Don't rewrite B0 */
535*4882a593Smuzhiyun 	if (tty_termios_baud_rate(termios))
536*4882a593Smuzhiyun 		tty_termios_encode_baud_rate(termios, baud, baud);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun 
serial_lpc32xx_type(struct uart_port * port)539*4882a593Smuzhiyun static const char *serial_lpc32xx_type(struct uart_port *port)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun 	return MODNAME;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
serial_lpc32xx_release_port(struct uart_port * port)544*4882a593Smuzhiyun static void serial_lpc32xx_release_port(struct uart_port *port)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun 	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
547*4882a593Smuzhiyun 		if (port->flags & UPF_IOREMAP) {
548*4882a593Smuzhiyun 			iounmap(port->membase);
549*4882a593Smuzhiyun 			port->membase = NULL;
550*4882a593Smuzhiyun 		}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 		release_mem_region(port->mapbase, SZ_4K);
553*4882a593Smuzhiyun 	}
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun 
serial_lpc32xx_request_port(struct uart_port * port)556*4882a593Smuzhiyun static int serial_lpc32xx_request_port(struct uart_port *port)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun 	int ret = -ENODEV;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
561*4882a593Smuzhiyun 		ret = 0;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
564*4882a593Smuzhiyun 			ret = -EBUSY;
565*4882a593Smuzhiyun 		else if (port->flags & UPF_IOREMAP) {
566*4882a593Smuzhiyun 			port->membase = ioremap(port->mapbase, SZ_4K);
567*4882a593Smuzhiyun 			if (!port->membase) {
568*4882a593Smuzhiyun 				release_mem_region(port->mapbase, SZ_4K);
569*4882a593Smuzhiyun 				ret = -ENOMEM;
570*4882a593Smuzhiyun 			}
571*4882a593Smuzhiyun 		}
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	return ret;
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun 
serial_lpc32xx_config_port(struct uart_port * port,int uflags)577*4882a593Smuzhiyun static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
578*4882a593Smuzhiyun {
579*4882a593Smuzhiyun 	int ret;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	ret = serial_lpc32xx_request_port(port);
582*4882a593Smuzhiyun 	if (ret < 0)
583*4882a593Smuzhiyun 		return;
584*4882a593Smuzhiyun 	port->type = PORT_UART00;
585*4882a593Smuzhiyun 	port->fifosize = 64;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	__serial_uart_flush(port);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
590*4882a593Smuzhiyun 		LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
591*4882a593Smuzhiyun 	       LPC32XX_HSUART_IIR(port->membase));
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	/* Set receiver timeout, HSU offset of 20, no break, no interrupts,
596*4882a593Smuzhiyun 	   and default FIFO trigger levels */
597*4882a593Smuzhiyun 	writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
598*4882a593Smuzhiyun 	       LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
599*4882a593Smuzhiyun 	       LPC32XX_HSUART_CTRL(port->membase));
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
serial_lpc32xx_verify_port(struct uart_port * port,struct serial_struct * ser)602*4882a593Smuzhiyun static int serial_lpc32xx_verify_port(struct uart_port *port,
603*4882a593Smuzhiyun 				      struct serial_struct *ser)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	int ret = 0;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	if (ser->type != PORT_UART00)
608*4882a593Smuzhiyun 		ret = -EINVAL;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	return ret;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun static const struct uart_ops serial_lpc32xx_pops = {
614*4882a593Smuzhiyun 	.tx_empty	= serial_lpc32xx_tx_empty,
615*4882a593Smuzhiyun 	.set_mctrl	= serial_lpc32xx_set_mctrl,
616*4882a593Smuzhiyun 	.get_mctrl	= serial_lpc32xx_get_mctrl,
617*4882a593Smuzhiyun 	.stop_tx	= serial_lpc32xx_stop_tx,
618*4882a593Smuzhiyun 	.start_tx	= serial_lpc32xx_start_tx,
619*4882a593Smuzhiyun 	.stop_rx	= serial_lpc32xx_stop_rx,
620*4882a593Smuzhiyun 	.break_ctl	= serial_lpc32xx_break_ctl,
621*4882a593Smuzhiyun 	.startup	= serial_lpc32xx_startup,
622*4882a593Smuzhiyun 	.shutdown	= serial_lpc32xx_shutdown,
623*4882a593Smuzhiyun 	.set_termios	= serial_lpc32xx_set_termios,
624*4882a593Smuzhiyun 	.type		= serial_lpc32xx_type,
625*4882a593Smuzhiyun 	.release_port	= serial_lpc32xx_release_port,
626*4882a593Smuzhiyun 	.request_port	= serial_lpc32xx_request_port,
627*4882a593Smuzhiyun 	.config_port	= serial_lpc32xx_config_port,
628*4882a593Smuzhiyun 	.verify_port	= serial_lpc32xx_verify_port,
629*4882a593Smuzhiyun };
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun /*
632*4882a593Smuzhiyun  * Register a set of serial devices attached to a platform device
633*4882a593Smuzhiyun  */
serial_hs_lpc32xx_probe(struct platform_device * pdev)634*4882a593Smuzhiyun static int serial_hs_lpc32xx_probe(struct platform_device *pdev)
635*4882a593Smuzhiyun {
636*4882a593Smuzhiyun 	struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
637*4882a593Smuzhiyun 	int ret = 0;
638*4882a593Smuzhiyun 	struct resource *res;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (uarts_registered >= MAX_PORTS) {
641*4882a593Smuzhiyun 		dev_err(&pdev->dev,
642*4882a593Smuzhiyun 			"Error: Number of possible ports exceeded (%d)!\n",
643*4882a593Smuzhiyun 			uarts_registered + 1);
644*4882a593Smuzhiyun 		return -ENXIO;
645*4882a593Smuzhiyun 	}
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	memset(p, 0, sizeof(*p));
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
650*4882a593Smuzhiyun 	if (!res) {
651*4882a593Smuzhiyun 		dev_err(&pdev->dev,
652*4882a593Smuzhiyun 			"Error getting mem resource for HS UART port %d\n",
653*4882a593Smuzhiyun 			uarts_registered);
654*4882a593Smuzhiyun 		return -ENXIO;
655*4882a593Smuzhiyun 	}
656*4882a593Smuzhiyun 	p->port.mapbase = res->start;
657*4882a593Smuzhiyun 	p->port.membase = NULL;
658*4882a593Smuzhiyun 
659*4882a593Smuzhiyun 	ret = platform_get_irq(pdev, 0);
660*4882a593Smuzhiyun 	if (ret < 0)
661*4882a593Smuzhiyun 		return ret;
662*4882a593Smuzhiyun 	p->port.irq = ret;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 	p->port.iotype = UPIO_MEM32;
665*4882a593Smuzhiyun 	p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
666*4882a593Smuzhiyun 	p->port.regshift = 2;
667*4882a593Smuzhiyun 	p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
668*4882a593Smuzhiyun 	p->port.dev = &pdev->dev;
669*4882a593Smuzhiyun 	p->port.ops = &serial_lpc32xx_pops;
670*4882a593Smuzhiyun 	p->port.line = uarts_registered++;
671*4882a593Smuzhiyun 	spin_lock_init(&p->port.lock);
672*4882a593Smuzhiyun 
673*4882a593Smuzhiyun 	/* send port to loopback mode by default */
674*4882a593Smuzhiyun 	lpc32xx_loopback_set(p->port.mapbase, 1);
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 	ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	platform_set_drvdata(pdev, p);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	return ret;
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun /*
684*4882a593Smuzhiyun  * Remove serial ports registered against a platform device.
685*4882a593Smuzhiyun  */
serial_hs_lpc32xx_remove(struct platform_device * pdev)686*4882a593Smuzhiyun static int serial_hs_lpc32xx_remove(struct platform_device *pdev)
687*4882a593Smuzhiyun {
688*4882a593Smuzhiyun 	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	return 0;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun #ifdef CONFIG_PM
serial_hs_lpc32xx_suspend(struct platform_device * pdev,pm_message_t state)697*4882a593Smuzhiyun static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
698*4882a593Smuzhiyun 				     pm_message_t state)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun 	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	uart_suspend_port(&lpc32xx_hs_reg, &p->port);
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	return 0;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun 
serial_hs_lpc32xx_resume(struct platform_device * pdev)707*4882a593Smuzhiyun static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
708*4882a593Smuzhiyun {
709*4882a593Smuzhiyun 	struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	uart_resume_port(&lpc32xx_hs_reg, &p->port);
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	return 0;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun #else
716*4882a593Smuzhiyun #define serial_hs_lpc32xx_suspend	NULL
717*4882a593Smuzhiyun #define serial_hs_lpc32xx_resume	NULL
718*4882a593Smuzhiyun #endif
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
721*4882a593Smuzhiyun 	{ .compatible = "nxp,lpc3220-hsuart" },
722*4882a593Smuzhiyun 	{ /* sentinel */ }
723*4882a593Smuzhiyun };
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun static struct platform_driver serial_hs_lpc32xx_driver = {
728*4882a593Smuzhiyun 	.probe		= serial_hs_lpc32xx_probe,
729*4882a593Smuzhiyun 	.remove		= serial_hs_lpc32xx_remove,
730*4882a593Smuzhiyun 	.suspend	= serial_hs_lpc32xx_suspend,
731*4882a593Smuzhiyun 	.resume		= serial_hs_lpc32xx_resume,
732*4882a593Smuzhiyun 	.driver		= {
733*4882a593Smuzhiyun 		.name	= MODNAME,
734*4882a593Smuzhiyun 		.of_match_table	= serial_hs_lpc32xx_dt_ids,
735*4882a593Smuzhiyun 	},
736*4882a593Smuzhiyun };
737*4882a593Smuzhiyun 
lpc32xx_hsuart_init(void)738*4882a593Smuzhiyun static int __init lpc32xx_hsuart_init(void)
739*4882a593Smuzhiyun {
740*4882a593Smuzhiyun 	int ret;
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	ret = uart_register_driver(&lpc32xx_hs_reg);
743*4882a593Smuzhiyun 	if (ret)
744*4882a593Smuzhiyun 		return ret;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	ret = platform_driver_register(&serial_hs_lpc32xx_driver);
747*4882a593Smuzhiyun 	if (ret)
748*4882a593Smuzhiyun 		uart_unregister_driver(&lpc32xx_hs_reg);
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	return ret;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
lpc32xx_hsuart_exit(void)753*4882a593Smuzhiyun static void __exit lpc32xx_hsuart_exit(void)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	platform_driver_unregister(&serial_hs_lpc32xx_driver);
756*4882a593Smuzhiyun 	uart_unregister_driver(&lpc32xx_hs_reg);
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun module_init(lpc32xx_hsuart_init);
760*4882a593Smuzhiyun module_exit(lpc32xx_hsuart_exit);
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
763*4882a593Smuzhiyun MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
764*4882a593Smuzhiyun MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
765*4882a593Smuzhiyun MODULE_LICENSE("GPL");
766