xref: /openbmc/linux/drivers/tty/serial/mcf.c (revision f91ca89e924eb287915522664a31afc71a49c05b)
1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
2ab4382d2SGreg Kroah-Hartman /****************************************************************************/
3ab4382d2SGreg Kroah-Hartman 
4ab4382d2SGreg Kroah-Hartman /*
5ab4382d2SGreg Kroah-Hartman  *	mcf.c -- Freescale ColdFire UART driver
6ab4382d2SGreg Kroah-Hartman  *
76a1c34f4SGreg Ungerer  *	(C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.org>
8ab4382d2SGreg Kroah-Hartman  */
9ab4382d2SGreg Kroah-Hartman 
10ab4382d2SGreg Kroah-Hartman /****************************************************************************/
11ab4382d2SGreg Kroah-Hartman 
12ab4382d2SGreg Kroah-Hartman #include <linux/kernel.h>
13ab4382d2SGreg Kroah-Hartman #include <linux/init.h>
14ab4382d2SGreg Kroah-Hartman #include <linux/interrupt.h>
15ab4382d2SGreg Kroah-Hartman #include <linux/module.h>
16ab4382d2SGreg Kroah-Hartman #include <linux/console.h>
17ab4382d2SGreg Kroah-Hartman #include <linux/tty.h>
18ab4382d2SGreg Kroah-Hartman #include <linux/tty_flip.h>
19ab4382d2SGreg Kroah-Hartman #include <linux/serial.h>
20ab4382d2SGreg Kroah-Hartman #include <linux/serial_core.h>
21ab4382d2SGreg Kroah-Hartman #include <linux/io.h>
22496c9077SQuoc-Viet Nguyen #include <linux/uaccess.h>
23574de559SJingoo Han #include <linux/platform_device.h>
24ab4382d2SGreg Kroah-Hartman #include <asm/coldfire.h>
25ab4382d2SGreg Kroah-Hartman #include <asm/mcfsim.h>
26ab4382d2SGreg Kroah-Hartman #include <asm/mcfuart.h>
27ab4382d2SGreg Kroah-Hartman #include <asm/nettel.h>
28ab4382d2SGreg Kroah-Hartman 
29ab4382d2SGreg Kroah-Hartman /****************************************************************************/
30ab4382d2SGreg Kroah-Hartman 
31ab4382d2SGreg Kroah-Hartman /*
32ab4382d2SGreg Kroah-Hartman  *	Some boards implement the DTR/DCD lines using GPIO lines, most
33ab4382d2SGreg Kroah-Hartman  *	don't. Dummy out the access macros for those that don't. Those
34ab4382d2SGreg Kroah-Hartman  *	that do should define these macros somewhere in there board
35ab4382d2SGreg Kroah-Hartman  *	specific inlude files.
36ab4382d2SGreg Kroah-Hartman  */
37ab4382d2SGreg Kroah-Hartman #if !defined(mcf_getppdcd)
38ab4382d2SGreg Kroah-Hartman #define	mcf_getppdcd(p)		(1)
39ab4382d2SGreg Kroah-Hartman #endif
40ab4382d2SGreg Kroah-Hartman #if !defined(mcf_getppdtr)
41ab4382d2SGreg Kroah-Hartman #define	mcf_getppdtr(p)		(1)
42ab4382d2SGreg Kroah-Hartman #endif
43ab4382d2SGreg Kroah-Hartman #if !defined(mcf_setppdtr)
44ab4382d2SGreg Kroah-Hartman #define	mcf_setppdtr(p, v)	do { } while (0)
45ab4382d2SGreg Kroah-Hartman #endif
46ab4382d2SGreg Kroah-Hartman 
47ab4382d2SGreg Kroah-Hartman /****************************************************************************/
48ab4382d2SGreg Kroah-Hartman 
49ab4382d2SGreg Kroah-Hartman /*
50ab4382d2SGreg Kroah-Hartman  *	Local per-uart structure.
51ab4382d2SGreg Kroah-Hartman  */
52ab4382d2SGreg Kroah-Hartman struct mcf_uart {
53ab4382d2SGreg Kroah-Hartman 	struct uart_port	port;
54ab4382d2SGreg Kroah-Hartman 	unsigned int		sigs;		/* Local copy of line sigs */
55ab4382d2SGreg Kroah-Hartman 	unsigned char		imr;		/* Local IMR mirror */
56ab4382d2SGreg Kroah-Hartman };
57ab4382d2SGreg Kroah-Hartman 
58ab4382d2SGreg Kroah-Hartman /****************************************************************************/
59ab4382d2SGreg Kroah-Hartman 
mcf_tx_empty(struct uart_port * port)60ab4382d2SGreg Kroah-Hartman static unsigned int mcf_tx_empty(struct uart_port *port)
61ab4382d2SGreg Kroah-Hartman {
62ab4382d2SGreg Kroah-Hartman 	return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
63ab4382d2SGreg Kroah-Hartman 		TIOCSER_TEMT : 0;
64ab4382d2SGreg Kroah-Hartman }
65ab4382d2SGreg Kroah-Hartman 
66ab4382d2SGreg Kroah-Hartman /****************************************************************************/
67ab4382d2SGreg Kroah-Hartman 
mcf_get_mctrl(struct uart_port * port)68ab4382d2SGreg Kroah-Hartman static unsigned int mcf_get_mctrl(struct uart_port *port)
69ab4382d2SGreg Kroah-Hartman {
70ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
71ab4382d2SGreg Kroah-Hartman 	unsigned int sigs;
72ab4382d2SGreg Kroah-Hartman 
73ab4382d2SGreg Kroah-Hartman 	sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
74ab4382d2SGreg Kroah-Hartman 		0 : TIOCM_CTS;
75ab4382d2SGreg Kroah-Hartman 	sigs |= (pp->sigs & TIOCM_RTS);
76ab4382d2SGreg Kroah-Hartman 	sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
77ab4382d2SGreg Kroah-Hartman 	sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
78ab4382d2SGreg Kroah-Hartman 
79ab4382d2SGreg Kroah-Hartman 	return sigs;
80ab4382d2SGreg Kroah-Hartman }
81ab4382d2SGreg Kroah-Hartman 
82ab4382d2SGreg Kroah-Hartman /****************************************************************************/
83ab4382d2SGreg Kroah-Hartman 
mcf_set_mctrl(struct uart_port * port,unsigned int sigs)84ab4382d2SGreg Kroah-Hartman static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
85ab4382d2SGreg Kroah-Hartman {
86ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
87ab4382d2SGreg Kroah-Hartman 
88ab4382d2SGreg Kroah-Hartman 	pp->sigs = sigs;
89ab4382d2SGreg Kroah-Hartman 	mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
90ab4382d2SGreg Kroah-Hartman 	if (sigs & TIOCM_RTS)
91ab4382d2SGreg Kroah-Hartman 		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
92ab4382d2SGreg Kroah-Hartman 	else
93ab4382d2SGreg Kroah-Hartman 		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
94ab4382d2SGreg Kroah-Hartman }
95ab4382d2SGreg Kroah-Hartman 
96ab4382d2SGreg Kroah-Hartman /****************************************************************************/
97ab4382d2SGreg Kroah-Hartman 
mcf_start_tx(struct uart_port * port)98ab4382d2SGreg Kroah-Hartman static void mcf_start_tx(struct uart_port *port)
99ab4382d2SGreg Kroah-Hartman {
100ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
101ab4382d2SGreg Kroah-Hartman 
1022fc0184dSRicardo Ribalda Delgado 	if (port->rs485.flags & SER_RS485_ENABLED) {
103496c9077SQuoc-Viet Nguyen 		/* Enable Transmitter */
104496c9077SQuoc-Viet Nguyen 		writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
105496c9077SQuoc-Viet Nguyen 		/* Manually assert RTS */
106496c9077SQuoc-Viet Nguyen 		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
107496c9077SQuoc-Viet Nguyen 	}
108ab4382d2SGreg Kroah-Hartman 	pp->imr |= MCFUART_UIR_TXREADY;
109ab4382d2SGreg Kroah-Hartman 	writeb(pp->imr, port->membase + MCFUART_UIMR);
110ab4382d2SGreg Kroah-Hartman }
111ab4382d2SGreg Kroah-Hartman 
112ab4382d2SGreg Kroah-Hartman /****************************************************************************/
113ab4382d2SGreg Kroah-Hartman 
mcf_stop_tx(struct uart_port * port)114ab4382d2SGreg Kroah-Hartman static void mcf_stop_tx(struct uart_port *port)
115ab4382d2SGreg Kroah-Hartman {
116ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
117ab4382d2SGreg Kroah-Hartman 
118ab4382d2SGreg Kroah-Hartman 	pp->imr &= ~MCFUART_UIR_TXREADY;
119ab4382d2SGreg Kroah-Hartman 	writeb(pp->imr, port->membase + MCFUART_UIMR);
120ab4382d2SGreg Kroah-Hartman }
121ab4382d2SGreg Kroah-Hartman 
122ab4382d2SGreg Kroah-Hartman /****************************************************************************/
123ab4382d2SGreg Kroah-Hartman 
mcf_stop_rx(struct uart_port * port)124ab4382d2SGreg Kroah-Hartman static void mcf_stop_rx(struct uart_port *port)
125ab4382d2SGreg Kroah-Hartman {
126ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
127ab4382d2SGreg Kroah-Hartman 
128ab4382d2SGreg Kroah-Hartman 	pp->imr &= ~MCFUART_UIR_RXREADY;
129ab4382d2SGreg Kroah-Hartman 	writeb(pp->imr, port->membase + MCFUART_UIMR);
130ab4382d2SGreg Kroah-Hartman }
131ab4382d2SGreg Kroah-Hartman 
132ab4382d2SGreg Kroah-Hartman /****************************************************************************/
133ab4382d2SGreg Kroah-Hartman 
mcf_break_ctl(struct uart_port * port,int break_state)134ab4382d2SGreg Kroah-Hartman static void mcf_break_ctl(struct uart_port *port, int break_state)
135ab4382d2SGreg Kroah-Hartman {
136ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
137ab4382d2SGreg Kroah-Hartman 
138ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&port->lock, flags);
139ab4382d2SGreg Kroah-Hartman 	if (break_state == -1)
140ab4382d2SGreg Kroah-Hartman 		writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
141ab4382d2SGreg Kroah-Hartman 	else
142ab4382d2SGreg Kroah-Hartman 		writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
143ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&port->lock, flags);
144ab4382d2SGreg Kroah-Hartman }
145ab4382d2SGreg Kroah-Hartman 
146ab4382d2SGreg Kroah-Hartman /****************************************************************************/
147ab4382d2SGreg Kroah-Hartman 
mcf_startup(struct uart_port * port)148ab4382d2SGreg Kroah-Hartman static int mcf_startup(struct uart_port *port)
149ab4382d2SGreg Kroah-Hartman {
150ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
151ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
152ab4382d2SGreg Kroah-Hartman 
153ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&port->lock, flags);
154ab4382d2SGreg Kroah-Hartman 
155ab4382d2SGreg Kroah-Hartman 	/* Reset UART, get it into known state... */
156ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
157ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
158ab4382d2SGreg Kroah-Hartman 
159ab4382d2SGreg Kroah-Hartman 	/* Enable the UART transmitter and receiver */
160ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
161ab4382d2SGreg Kroah-Hartman 		port->membase + MCFUART_UCR);
162ab4382d2SGreg Kroah-Hartman 
163ab4382d2SGreg Kroah-Hartman 	/* Enable RX interrupts now */
164ab4382d2SGreg Kroah-Hartman 	pp->imr = MCFUART_UIR_RXREADY;
165ab4382d2SGreg Kroah-Hartman 	writeb(pp->imr, port->membase + MCFUART_UIMR);
166ab4382d2SGreg Kroah-Hartman 
167ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&port->lock, flags);
168ab4382d2SGreg Kroah-Hartman 
169ab4382d2SGreg Kroah-Hartman 	return 0;
170ab4382d2SGreg Kroah-Hartman }
171ab4382d2SGreg Kroah-Hartman 
172ab4382d2SGreg Kroah-Hartman /****************************************************************************/
173ab4382d2SGreg Kroah-Hartman 
mcf_shutdown(struct uart_port * port)174ab4382d2SGreg Kroah-Hartman static void mcf_shutdown(struct uart_port *port)
175ab4382d2SGreg Kroah-Hartman {
176ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
177ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
178ab4382d2SGreg Kroah-Hartman 
179ab4382d2SGreg Kroah-Hartman 	spin_lock_irqsave(&port->lock, flags);
180ab4382d2SGreg Kroah-Hartman 
181ab4382d2SGreg Kroah-Hartman 	/* Disable all interrupts now */
182ab4382d2SGreg Kroah-Hartman 	pp->imr = 0;
183ab4382d2SGreg Kroah-Hartman 	writeb(pp->imr, port->membase + MCFUART_UIMR);
184ab4382d2SGreg Kroah-Hartman 
185ab4382d2SGreg Kroah-Hartman 	/* Disable UART transmitter and receiver */
186ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
187ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
188ab4382d2SGreg Kroah-Hartman 
189ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&port->lock, flags);
190ab4382d2SGreg Kroah-Hartman }
191ab4382d2SGreg Kroah-Hartman 
192ab4382d2SGreg Kroah-Hartman /****************************************************************************/
193ab4382d2SGreg Kroah-Hartman 
mcf_set_termios(struct uart_port * port,struct ktermios * termios,const struct ktermios * old)194ab4382d2SGreg Kroah-Hartman static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
195bec5b814SIlpo Järvinen 			    const struct ktermios *old)
196ab4382d2SGreg Kroah-Hartman {
197ab4382d2SGreg Kroah-Hartman 	unsigned long flags;
198ab4382d2SGreg Kroah-Hartman 	unsigned int baud, baudclk;
199ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_M5272)
200ab4382d2SGreg Kroah-Hartman 	unsigned int baudfr;
201ab4382d2SGreg Kroah-Hartman #endif
202ab4382d2SGreg Kroah-Hartman 	unsigned char mr1, mr2;
203ab4382d2SGreg Kroah-Hartman 
204ab4382d2SGreg Kroah-Hartman 	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
205ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_M5272)
206ab4382d2SGreg Kroah-Hartman 	baudclk = (MCF_BUSCLK / baud) / 32;
207ab4382d2SGreg Kroah-Hartman 	baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
208ab4382d2SGreg Kroah-Hartman #else
209ab4382d2SGreg Kroah-Hartman 	baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
210ab4382d2SGreg Kroah-Hartman #endif
211ab4382d2SGreg Kroah-Hartman 
212ab4382d2SGreg Kroah-Hartman 	mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
213ab4382d2SGreg Kroah-Hartman 	mr2 = 0;
214ab4382d2SGreg Kroah-Hartman 
215ab4382d2SGreg Kroah-Hartman 	switch (termios->c_cflag & CSIZE) {
216ab4382d2SGreg Kroah-Hartman 	case CS5: mr1 |= MCFUART_MR1_CS5; break;
217ab4382d2SGreg Kroah-Hartman 	case CS6: mr1 |= MCFUART_MR1_CS6; break;
218ab4382d2SGreg Kroah-Hartman 	case CS7: mr1 |= MCFUART_MR1_CS7; break;
219ab4382d2SGreg Kroah-Hartman 	case CS8:
220ab4382d2SGreg Kroah-Hartman 	default:  mr1 |= MCFUART_MR1_CS8; break;
221ab4382d2SGreg Kroah-Hartman 	}
222ab4382d2SGreg Kroah-Hartman 
223ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & PARENB) {
224ab4382d2SGreg Kroah-Hartman 		if (termios->c_cflag & CMSPAR) {
225ab4382d2SGreg Kroah-Hartman 			if (termios->c_cflag & PARODD)
226ab4382d2SGreg Kroah-Hartman 				mr1 |= MCFUART_MR1_PARITYMARK;
227ab4382d2SGreg Kroah-Hartman 			else
228ab4382d2SGreg Kroah-Hartman 				mr1 |= MCFUART_MR1_PARITYSPACE;
229ab4382d2SGreg Kroah-Hartman 		} else {
230ab4382d2SGreg Kroah-Hartman 			if (termios->c_cflag & PARODD)
231ab4382d2SGreg Kroah-Hartman 				mr1 |= MCFUART_MR1_PARITYODD;
232ab4382d2SGreg Kroah-Hartman 			else
233ab4382d2SGreg Kroah-Hartman 				mr1 |= MCFUART_MR1_PARITYEVEN;
234ab4382d2SGreg Kroah-Hartman 		}
235ab4382d2SGreg Kroah-Hartman 	} else {
236ab4382d2SGreg Kroah-Hartman 		mr1 |= MCFUART_MR1_PARITYNONE;
237ab4382d2SGreg Kroah-Hartman 	}
238ab4382d2SGreg Kroah-Hartman 
239ef8b9ddcSPeter Hurley 	/*
240ef8b9ddcSPeter Hurley 	 * FIXME: port->read_status_mask and port->ignore_status_mask
241ef8b9ddcSPeter Hurley 	 * need to be initialized based on termios settings for
242ef8b9ddcSPeter Hurley 	 * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
243ef8b9ddcSPeter Hurley 	 */
244ef8b9ddcSPeter Hurley 
245ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CSTOPB)
246ab4382d2SGreg Kroah-Hartman 		mr2 |= MCFUART_MR2_STOP2;
247ab4382d2SGreg Kroah-Hartman 	else
248ab4382d2SGreg Kroah-Hartman 		mr2 |= MCFUART_MR2_STOP1;
249ab4382d2SGreg Kroah-Hartman 
250ab4382d2SGreg Kroah-Hartman 	if (termios->c_cflag & CRTSCTS) {
251ab4382d2SGreg Kroah-Hartman 		mr1 |= MCFUART_MR1_RXRTS;
252ab4382d2SGreg Kroah-Hartman 		mr2 |= MCFUART_MR2_TXCTS;
253ab4382d2SGreg Kroah-Hartman 	}
254ab4382d2SGreg Kroah-Hartman 
255bd737f87SRicardo Ribalda Delgado 	spin_lock_irqsave(&port->lock, flags);
2562fc0184dSRicardo Ribalda Delgado 	if (port->rs485.flags & SER_RS485_ENABLED) {
257496c9077SQuoc-Viet Nguyen 		dev_dbg(port->dev, "Setting UART to RS485\n");
258496c9077SQuoc-Viet Nguyen 		mr2 |= MCFUART_MR2_TXRTS;
259496c9077SQuoc-Viet Nguyen 	}
260496c9077SQuoc-Viet Nguyen 
261ab4382d2SGreg Kroah-Hartman 	uart_update_timeout(port, termios->c_cflag, baud);
262ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
263ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
264ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
265ab4382d2SGreg Kroah-Hartman 	writeb(mr1, port->membase + MCFUART_UMR);
266ab4382d2SGreg Kroah-Hartman 	writeb(mr2, port->membase + MCFUART_UMR);
267ab4382d2SGreg Kroah-Hartman 	writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
268ab4382d2SGreg Kroah-Hartman 	writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
269ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_M5272)
270ab4382d2SGreg Kroah-Hartman 	writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
271ab4382d2SGreg Kroah-Hartman #endif
272ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
273ab4382d2SGreg Kroah-Hartman 		port->membase + MCFUART_UCSR);
274ab4382d2SGreg Kroah-Hartman 	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
275ab4382d2SGreg Kroah-Hartman 		port->membase + MCFUART_UCR);
276ab4382d2SGreg Kroah-Hartman 	spin_unlock_irqrestore(&port->lock, flags);
277ab4382d2SGreg Kroah-Hartman }
278ab4382d2SGreg Kroah-Hartman 
279ab4382d2SGreg Kroah-Hartman /****************************************************************************/
280ab4382d2SGreg Kroah-Hartman 
mcf_rx_chars(struct mcf_uart * pp)281ab4382d2SGreg Kroah-Hartman static void mcf_rx_chars(struct mcf_uart *pp)
282ab4382d2SGreg Kroah-Hartman {
283ab4382d2SGreg Kroah-Hartman 	struct uart_port *port = &pp->port;
284fd2b55f8SJiri Slaby 	u8 status, ch, flag;
285ab4382d2SGreg Kroah-Hartman 
286ab4382d2SGreg Kroah-Hartman 	while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
287ab4382d2SGreg Kroah-Hartman 		ch = readb(port->membase + MCFUART_URB);
288ab4382d2SGreg Kroah-Hartman 		flag = TTY_NORMAL;
289ab4382d2SGreg Kroah-Hartman 		port->icount.rx++;
290ab4382d2SGreg Kroah-Hartman 
291ab4382d2SGreg Kroah-Hartman 		if (status & MCFUART_USR_RXERR) {
292ab4382d2SGreg Kroah-Hartman 			writeb(MCFUART_UCR_CMDRESETERR,
293ab4382d2SGreg Kroah-Hartman 				port->membase + MCFUART_UCR);
294ab4382d2SGreg Kroah-Hartman 
295ab4382d2SGreg Kroah-Hartman 			if (status & MCFUART_USR_RXBREAK) {
296ab4382d2SGreg Kroah-Hartman 				port->icount.brk++;
297ab4382d2SGreg Kroah-Hartman 				if (uart_handle_break(port))
298ab4382d2SGreg Kroah-Hartman 					continue;
299ab4382d2SGreg Kroah-Hartman 			} else if (status & MCFUART_USR_RXPARITY) {
300ab4382d2SGreg Kroah-Hartman 				port->icount.parity++;
301ab4382d2SGreg Kroah-Hartman 			} else if (status & MCFUART_USR_RXOVERRUN) {
302ab4382d2SGreg Kroah-Hartman 				port->icount.overrun++;
303ab4382d2SGreg Kroah-Hartman 			} else if (status & MCFUART_USR_RXFRAMING) {
304ab4382d2SGreg Kroah-Hartman 				port->icount.frame++;
305ab4382d2SGreg Kroah-Hartman 			}
306ab4382d2SGreg Kroah-Hartman 
307ab4382d2SGreg Kroah-Hartman 			status &= port->read_status_mask;
308ab4382d2SGreg Kroah-Hartman 
309ab4382d2SGreg Kroah-Hartman 			if (status & MCFUART_USR_RXBREAK)
310ab4382d2SGreg Kroah-Hartman 				flag = TTY_BREAK;
311ab4382d2SGreg Kroah-Hartman 			else if (status & MCFUART_USR_RXPARITY)
312ab4382d2SGreg Kroah-Hartman 				flag = TTY_PARITY;
313ab4382d2SGreg Kroah-Hartman 			else if (status & MCFUART_USR_RXFRAMING)
314ab4382d2SGreg Kroah-Hartman 				flag = TTY_FRAME;
315ab4382d2SGreg Kroah-Hartman 		}
316ab4382d2SGreg Kroah-Hartman 
317ab4382d2SGreg Kroah-Hartman 		if (uart_handle_sysrq_char(port, ch))
318ab4382d2SGreg Kroah-Hartman 			continue;
319ab4382d2SGreg Kroah-Hartman 		uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
320ab4382d2SGreg Kroah-Hartman 	}
321ab4382d2SGreg Kroah-Hartman 
3222e124b4aSJiri Slaby 	tty_flip_buffer_push(&port->state->port);
323ab4382d2SGreg Kroah-Hartman }
324ab4382d2SGreg Kroah-Hartman 
325ab4382d2SGreg Kroah-Hartman /****************************************************************************/
326ab4382d2SGreg Kroah-Hartman 
mcf_tx_chars(struct mcf_uart * pp)327ab4382d2SGreg Kroah-Hartman static void mcf_tx_chars(struct mcf_uart *pp)
328ab4382d2SGreg Kroah-Hartman {
329ab4382d2SGreg Kroah-Hartman 	struct uart_port *port = &pp->port;
3302d141e68SJiri Slaby (SUSE) 	bool pending;
3312d141e68SJiri Slaby (SUSE) 	u8 ch;
332ab4382d2SGreg Kroah-Hartman 
3332d141e68SJiri Slaby (SUSE) 	pending = uart_port_tx(port, ch,
3342d141e68SJiri Slaby (SUSE) 		readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY,
3352d141e68SJiri Slaby (SUSE) 		writeb(ch, port->membase + MCFUART_UTB));
336ab4382d2SGreg Kroah-Hartman 
337496c9077SQuoc-Viet Nguyen 	/* Disable TX to negate RTS automatically */
3382d141e68SJiri Slaby (SUSE) 	if (!pending && (port->rs485.flags & SER_RS485_ENABLED))
3392d141e68SJiri Slaby (SUSE) 		writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR);
340ab4382d2SGreg Kroah-Hartman }
341ab4382d2SGreg Kroah-Hartman 
342ab4382d2SGreg Kroah-Hartman /****************************************************************************/
343ab4382d2SGreg Kroah-Hartman 
mcf_interrupt(int irq,void * data)344ab4382d2SGreg Kroah-Hartman static irqreturn_t mcf_interrupt(int irq, void *data)
345ab4382d2SGreg Kroah-Hartman {
346ab4382d2SGreg Kroah-Hartman 	struct uart_port *port = data;
347ab4382d2SGreg Kroah-Hartman 	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
348ab4382d2SGreg Kroah-Hartman 	unsigned int isr;
349ab4382d2SGreg Kroah-Hartman 	irqreturn_t ret = IRQ_NONE;
350ab4382d2SGreg Kroah-Hartman 
351ab4382d2SGreg Kroah-Hartman 	isr = readb(port->membase + MCFUART_UISR) & pp->imr;
352ab4382d2SGreg Kroah-Hartman 
353ab4382d2SGreg Kroah-Hartman 	spin_lock(&port->lock);
354ab4382d2SGreg Kroah-Hartman 	if (isr & MCFUART_UIR_RXREADY) {
355ab4382d2SGreg Kroah-Hartman 		mcf_rx_chars(pp);
356ab4382d2SGreg Kroah-Hartman 		ret = IRQ_HANDLED;
357ab4382d2SGreg Kroah-Hartman 	}
358ab4382d2SGreg Kroah-Hartman 	if (isr & MCFUART_UIR_TXREADY) {
359ab4382d2SGreg Kroah-Hartman 		mcf_tx_chars(pp);
360ab4382d2SGreg Kroah-Hartman 		ret = IRQ_HANDLED;
361ab4382d2SGreg Kroah-Hartman 	}
362ab4382d2SGreg Kroah-Hartman 	spin_unlock(&port->lock);
363ab4382d2SGreg Kroah-Hartman 
364ab4382d2SGreg Kroah-Hartman 	return ret;
365ab4382d2SGreg Kroah-Hartman }
366ab4382d2SGreg Kroah-Hartman 
367ab4382d2SGreg Kroah-Hartman /****************************************************************************/
368ab4382d2SGreg Kroah-Hartman 
mcf_config_port(struct uart_port * port,int flags)369ab4382d2SGreg Kroah-Hartman static void mcf_config_port(struct uart_port *port, int flags)
370ab4382d2SGreg Kroah-Hartman {
371ab4382d2SGreg Kroah-Hartman 	port->type = PORT_MCF;
372ab4382d2SGreg Kroah-Hartman 	port->fifosize = MCFUART_TXFIFOSIZE;
373ab4382d2SGreg Kroah-Hartman 
374ab4382d2SGreg Kroah-Hartman 	/* Clear mask, so no surprise interrupts. */
375ab4382d2SGreg Kroah-Hartman 	writeb(0, port->membase + MCFUART_UIMR);
376ab4382d2SGreg Kroah-Hartman 
3779cfb5c05SYong Zhang 	if (request_irq(port->irq, mcf_interrupt, 0, "UART", port))
378ab4382d2SGreg Kroah-Hartman 		printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
379ab4382d2SGreg Kroah-Hartman 			"interrupt vector=%d\n", port->line, port->irq);
380ab4382d2SGreg Kroah-Hartman }
381ab4382d2SGreg Kroah-Hartman 
382ab4382d2SGreg Kroah-Hartman /****************************************************************************/
383ab4382d2SGreg Kroah-Hartman 
mcf_type(struct uart_port * port)384ab4382d2SGreg Kroah-Hartman static const char *mcf_type(struct uart_port *port)
385ab4382d2SGreg Kroah-Hartman {
386ab4382d2SGreg Kroah-Hartman 	return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
387ab4382d2SGreg Kroah-Hartman }
388ab4382d2SGreg Kroah-Hartman 
389ab4382d2SGreg Kroah-Hartman /****************************************************************************/
390ab4382d2SGreg Kroah-Hartman 
mcf_request_port(struct uart_port * port)391ab4382d2SGreg Kroah-Hartman static int mcf_request_port(struct uart_port *port)
392ab4382d2SGreg Kroah-Hartman {
393ab4382d2SGreg Kroah-Hartman 	/* UARTs always present */
394ab4382d2SGreg Kroah-Hartman 	return 0;
395ab4382d2SGreg Kroah-Hartman }
396ab4382d2SGreg Kroah-Hartman 
397ab4382d2SGreg Kroah-Hartman /****************************************************************************/
398ab4382d2SGreg Kroah-Hartman 
mcf_release_port(struct uart_port * port)399ab4382d2SGreg Kroah-Hartman static void mcf_release_port(struct uart_port *port)
400ab4382d2SGreg Kroah-Hartman {
401ab4382d2SGreg Kroah-Hartman 	/* Nothing to release... */
402ab4382d2SGreg Kroah-Hartman }
403ab4382d2SGreg Kroah-Hartman 
404ab4382d2SGreg Kroah-Hartman /****************************************************************************/
405ab4382d2SGreg Kroah-Hartman 
mcf_verify_port(struct uart_port * port,struct serial_struct * ser)406ab4382d2SGreg Kroah-Hartman static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
407ab4382d2SGreg Kroah-Hartman {
408ab4382d2SGreg Kroah-Hartman 	if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
409ab4382d2SGreg Kroah-Hartman 		return -EINVAL;
410ab4382d2SGreg Kroah-Hartman 	return 0;
411ab4382d2SGreg Kroah-Hartman }
412ab4382d2SGreg Kroah-Hartman 
413ab4382d2SGreg Kroah-Hartman /****************************************************************************/
414ab4382d2SGreg Kroah-Hartman 
415496c9077SQuoc-Viet Nguyen /* Enable or disable the RS485 support */
mcf_config_rs485(struct uart_port * port,struct ktermios * termios,struct serial_rs485 * rs485)416ae50bb27SIlpo Järvinen static int mcf_config_rs485(struct uart_port *port, struct ktermios *termios,
417ae50bb27SIlpo Järvinen 			    struct serial_rs485 *rs485)
418496c9077SQuoc-Viet Nguyen {
419496c9077SQuoc-Viet Nguyen 	unsigned char mr1, mr2;
420496c9077SQuoc-Viet Nguyen 
421496c9077SQuoc-Viet Nguyen 	/* Get mode registers */
422496c9077SQuoc-Viet Nguyen 	mr1 = readb(port->membase + MCFUART_UMR);
423496c9077SQuoc-Viet Nguyen 	mr2 = readb(port->membase + MCFUART_UMR);
424496c9077SQuoc-Viet Nguyen 	if (rs485->flags & SER_RS485_ENABLED) {
425496c9077SQuoc-Viet Nguyen 		dev_dbg(port->dev, "Setting UART to RS485\n");
426496c9077SQuoc-Viet Nguyen 		/* Automatically negate RTS after TX completes */
427496c9077SQuoc-Viet Nguyen 		mr2 |= MCFUART_MR2_TXRTS;
428496c9077SQuoc-Viet Nguyen 	} else {
429496c9077SQuoc-Viet Nguyen 		dev_dbg(port->dev, "Setting UART to RS232\n");
430496c9077SQuoc-Viet Nguyen 		mr2 &= ~MCFUART_MR2_TXRTS;
431496c9077SQuoc-Viet Nguyen 	}
432496c9077SQuoc-Viet Nguyen 	writeb(mr1, port->membase + MCFUART_UMR);
433496c9077SQuoc-Viet Nguyen 	writeb(mr2, port->membase + MCFUART_UMR);
434496c9077SQuoc-Viet Nguyen 
435496c9077SQuoc-Viet Nguyen 	return 0;
436496c9077SQuoc-Viet Nguyen }
437496c9077SQuoc-Viet Nguyen 
438949b4dbfSIlpo Järvinen static const struct serial_rs485 mcf_rs485_supported = {
439949b4dbfSIlpo Järvinen 	.flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
440949b4dbfSIlpo Järvinen };
441949b4dbfSIlpo Järvinen 
442496c9077SQuoc-Viet Nguyen /****************************************************************************/
443496c9077SQuoc-Viet Nguyen 
444ab4382d2SGreg Kroah-Hartman /*
445ab4382d2SGreg Kroah-Hartman  *	Define the basic serial functions we support.
446ab4382d2SGreg Kroah-Hartman  */
447ab4382d2SGreg Kroah-Hartman static const struct uart_ops mcf_uart_ops = {
448ab4382d2SGreg Kroah-Hartman 	.tx_empty	= mcf_tx_empty,
449ab4382d2SGreg Kroah-Hartman 	.get_mctrl	= mcf_get_mctrl,
450ab4382d2SGreg Kroah-Hartman 	.set_mctrl	= mcf_set_mctrl,
451ab4382d2SGreg Kroah-Hartman 	.start_tx	= mcf_start_tx,
452ab4382d2SGreg Kroah-Hartman 	.stop_tx	= mcf_stop_tx,
453ab4382d2SGreg Kroah-Hartman 	.stop_rx	= mcf_stop_rx,
454ab4382d2SGreg Kroah-Hartman 	.break_ctl	= mcf_break_ctl,
455ab4382d2SGreg Kroah-Hartman 	.startup	= mcf_startup,
456ab4382d2SGreg Kroah-Hartman 	.shutdown	= mcf_shutdown,
457ab4382d2SGreg Kroah-Hartman 	.set_termios	= mcf_set_termios,
458ab4382d2SGreg Kroah-Hartman 	.type		= mcf_type,
459ab4382d2SGreg Kroah-Hartman 	.request_port	= mcf_request_port,
460ab4382d2SGreg Kroah-Hartman 	.release_port	= mcf_release_port,
461ab4382d2SGreg Kroah-Hartman 	.config_port	= mcf_config_port,
462ab4382d2SGreg Kroah-Hartman 	.verify_port	= mcf_verify_port,
463ab4382d2SGreg Kroah-Hartman };
464ab4382d2SGreg Kroah-Hartman 
465*31020beaSJean-Michel Hautbois static struct mcf_uart mcf_ports[10];
466ab4382d2SGreg Kroah-Hartman 
467ab4382d2SGreg Kroah-Hartman #define	MCF_MAXPORTS	ARRAY_SIZE(mcf_ports)
468ab4382d2SGreg Kroah-Hartman 
469ab4382d2SGreg Kroah-Hartman /****************************************************************************/
470ab4382d2SGreg Kroah-Hartman #if defined(CONFIG_SERIAL_MCF_CONSOLE)
471ab4382d2SGreg Kroah-Hartman /****************************************************************************/
472ab4382d2SGreg Kroah-Hartman 
early_mcf_setup(struct mcf_platform_uart * platp)473ab4382d2SGreg Kroah-Hartman int __init early_mcf_setup(struct mcf_platform_uart *platp)
474ab4382d2SGreg Kroah-Hartman {
475ab4382d2SGreg Kroah-Hartman 	struct uart_port *port;
476ab4382d2SGreg Kroah-Hartman 	int i;
477ab4382d2SGreg Kroah-Hartman 
478ab4382d2SGreg Kroah-Hartman 	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
479ab4382d2SGreg Kroah-Hartman 		port = &mcf_ports[i].port;
480ab4382d2SGreg Kroah-Hartman 
481ab4382d2SGreg Kroah-Hartman 		port->line = i;
482ab4382d2SGreg Kroah-Hartman 		port->type = PORT_MCF;
483ab4382d2SGreg Kroah-Hartman 		port->mapbase = platp[i].mapbase;
484ab4382d2SGreg Kroah-Hartman 		port->membase = (platp[i].membase) ? platp[i].membase :
485ab4382d2SGreg Kroah-Hartman 			(unsigned char __iomem *) port->mapbase;
486ab4382d2SGreg Kroah-Hartman 		port->iotype = SERIAL_IO_MEM;
487ab4382d2SGreg Kroah-Hartman 		port->irq = platp[i].irq;
488ab4382d2SGreg Kroah-Hartman 		port->uartclk = MCF_BUSCLK;
4895fda7a0eSPeter Hurley 		port->flags = UPF_BOOT_AUTOCONF;
4902fc0184dSRicardo Ribalda Delgado 		port->rs485_config = mcf_config_rs485;
4910139da50SIlpo Järvinen 		port->rs485_supported = mcf_rs485_supported;
492ab4382d2SGreg Kroah-Hartman 		port->ops = &mcf_uart_ops;
493ab4382d2SGreg Kroah-Hartman 	}
494ab4382d2SGreg Kroah-Hartman 
495ab4382d2SGreg Kroah-Hartman 	return 0;
496ab4382d2SGreg Kroah-Hartman }
497ab4382d2SGreg Kroah-Hartman 
498ab4382d2SGreg Kroah-Hartman /****************************************************************************/
499ab4382d2SGreg Kroah-Hartman 
mcf_console_putc(struct console * co,const char c)500ab4382d2SGreg Kroah-Hartman static void mcf_console_putc(struct console *co, const char c)
501ab4382d2SGreg Kroah-Hartman {
502ab4382d2SGreg Kroah-Hartman 	struct uart_port *port = &(mcf_ports + co->index)->port;
503ab4382d2SGreg Kroah-Hartman 	int i;
504ab4382d2SGreg Kroah-Hartman 
505ab4382d2SGreg Kroah-Hartman 	for (i = 0; (i < 0x10000); i++) {
506ab4382d2SGreg Kroah-Hartman 		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
507ab4382d2SGreg Kroah-Hartman 			break;
508ab4382d2SGreg Kroah-Hartman 	}
509ab4382d2SGreg Kroah-Hartman 	writeb(c, port->membase + MCFUART_UTB);
510ab4382d2SGreg Kroah-Hartman 	for (i = 0; (i < 0x10000); i++) {
511ab4382d2SGreg Kroah-Hartman 		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
512ab4382d2SGreg Kroah-Hartman 			break;
513ab4382d2SGreg Kroah-Hartman 	}
514ab4382d2SGreg Kroah-Hartman }
515ab4382d2SGreg Kroah-Hartman 
516ab4382d2SGreg Kroah-Hartman /****************************************************************************/
517ab4382d2SGreg Kroah-Hartman 
mcf_console_write(struct console * co,const char * s,unsigned int count)518ab4382d2SGreg Kroah-Hartman static void mcf_console_write(struct console *co, const char *s, unsigned int count)
519ab4382d2SGreg Kroah-Hartman {
520ab4382d2SGreg Kroah-Hartman 	for (; (count); count--, s++) {
521ab4382d2SGreg Kroah-Hartman 		mcf_console_putc(co, *s);
522ab4382d2SGreg Kroah-Hartman 		if (*s == '\n')
523ab4382d2SGreg Kroah-Hartman 			mcf_console_putc(co, '\r');
524ab4382d2SGreg Kroah-Hartman 	}
525ab4382d2SGreg Kroah-Hartman }
526ab4382d2SGreg Kroah-Hartman 
527ab4382d2SGreg Kroah-Hartman /****************************************************************************/
528ab4382d2SGreg Kroah-Hartman 
mcf_console_setup(struct console * co,char * options)529ab4382d2SGreg Kroah-Hartman static int __init mcf_console_setup(struct console *co, char *options)
530ab4382d2SGreg Kroah-Hartman {
531ab4382d2SGreg Kroah-Hartman 	struct uart_port *port;
532ab4382d2SGreg Kroah-Hartman 	int baud = CONFIG_SERIAL_MCF_BAUDRATE;
533ab4382d2SGreg Kroah-Hartman 	int bits = 8;
534ab4382d2SGreg Kroah-Hartman 	int parity = 'n';
535ab4382d2SGreg Kroah-Hartman 	int flow = 'n';
536ab4382d2SGreg Kroah-Hartman 
537ab4382d2SGreg Kroah-Hartman 	if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
538ab4382d2SGreg Kroah-Hartman 		co->index = 0;
539ab4382d2SGreg Kroah-Hartman 	port = &mcf_ports[co->index].port;
540ab4382d2SGreg Kroah-Hartman 	if (port->membase == 0)
541ab4382d2SGreg Kroah-Hartman 		return -ENODEV;
542ab4382d2SGreg Kroah-Hartman 
543ab4382d2SGreg Kroah-Hartman 	if (options)
544ab4382d2SGreg Kroah-Hartman 		uart_parse_options(options, &baud, &parity, &bits, &flow);
545ab4382d2SGreg Kroah-Hartman 
546ab4382d2SGreg Kroah-Hartman 	return uart_set_options(port, co, baud, parity, bits, flow);
547ab4382d2SGreg Kroah-Hartman }
548ab4382d2SGreg Kroah-Hartman 
549ab4382d2SGreg Kroah-Hartman /****************************************************************************/
550ab4382d2SGreg Kroah-Hartman 
551ab4382d2SGreg Kroah-Hartman static struct uart_driver mcf_driver;
552ab4382d2SGreg Kroah-Hartman 
553ab4382d2SGreg Kroah-Hartman static struct console mcf_console = {
554ab4382d2SGreg Kroah-Hartman 	.name		= "ttyS",
555ab4382d2SGreg Kroah-Hartman 	.write		= mcf_console_write,
556ab4382d2SGreg Kroah-Hartman 	.device		= uart_console_device,
557ab4382d2SGreg Kroah-Hartman 	.setup		= mcf_console_setup,
558ab4382d2SGreg Kroah-Hartman 	.flags		= CON_PRINTBUFFER,
559ab4382d2SGreg Kroah-Hartman 	.index		= -1,
560ab4382d2SGreg Kroah-Hartman 	.data		= &mcf_driver,
561ab4382d2SGreg Kroah-Hartman };
562ab4382d2SGreg Kroah-Hartman 
mcf_console_init(void)563ab4382d2SGreg Kroah-Hartman static int __init mcf_console_init(void)
564ab4382d2SGreg Kroah-Hartman {
565ab4382d2SGreg Kroah-Hartman 	register_console(&mcf_console);
566ab4382d2SGreg Kroah-Hartman 	return 0;
567ab4382d2SGreg Kroah-Hartman }
568ab4382d2SGreg Kroah-Hartman 
569ab4382d2SGreg Kroah-Hartman console_initcall(mcf_console_init);
570ab4382d2SGreg Kroah-Hartman 
571ab4382d2SGreg Kroah-Hartman #define	MCF_CONSOLE	&mcf_console
572ab4382d2SGreg Kroah-Hartman 
573ab4382d2SGreg Kroah-Hartman /****************************************************************************/
574ab4382d2SGreg Kroah-Hartman #else
575ab4382d2SGreg Kroah-Hartman /****************************************************************************/
576ab4382d2SGreg Kroah-Hartman 
577ab4382d2SGreg Kroah-Hartman #define	MCF_CONSOLE	NULL
578ab4382d2SGreg Kroah-Hartman 
579ab4382d2SGreg Kroah-Hartman /****************************************************************************/
580bbdfe620SValentin Rothberg #endif /* CONFIG_SERIAL_MCF_CONSOLE */
581ab4382d2SGreg Kroah-Hartman /****************************************************************************/
582ab4382d2SGreg Kroah-Hartman 
583ab4382d2SGreg Kroah-Hartman /*
584ab4382d2SGreg Kroah-Hartman  *	Define the mcf UART driver structure.
585ab4382d2SGreg Kroah-Hartman  */
586ab4382d2SGreg Kroah-Hartman static struct uart_driver mcf_driver = {
587ab4382d2SGreg Kroah-Hartman 	.owner		= THIS_MODULE,
588ab4382d2SGreg Kroah-Hartman 	.driver_name	= "mcf",
589ab4382d2SGreg Kroah-Hartman 	.dev_name	= "ttyS",
590ab4382d2SGreg Kroah-Hartman 	.major		= TTY_MAJOR,
591ab4382d2SGreg Kroah-Hartman 	.minor		= 64,
592ab4382d2SGreg Kroah-Hartman 	.nr		= MCF_MAXPORTS,
593ab4382d2SGreg Kroah-Hartman 	.cons		= MCF_CONSOLE,
594ab4382d2SGreg Kroah-Hartman };
595ab4382d2SGreg Kroah-Hartman 
596ab4382d2SGreg Kroah-Hartman /****************************************************************************/
597ab4382d2SGreg Kroah-Hartman 
mcf_probe(struct platform_device * pdev)5989671f099SBill Pemberton static int mcf_probe(struct platform_device *pdev)
599ab4382d2SGreg Kroah-Hartman {
600574de559SJingoo Han 	struct mcf_platform_uart *platp = dev_get_platdata(&pdev->dev);
601ab4382d2SGreg Kroah-Hartman 	struct uart_port *port;
602ab4382d2SGreg Kroah-Hartman 	int i;
603ab4382d2SGreg Kroah-Hartman 
604ab4382d2SGreg Kroah-Hartman 	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
605ab4382d2SGreg Kroah-Hartman 		port = &mcf_ports[i].port;
606ab4382d2SGreg Kroah-Hartman 
607ab4382d2SGreg Kroah-Hartman 		port->line = i;
608ab4382d2SGreg Kroah-Hartman 		port->type = PORT_MCF;
609ab4382d2SGreg Kroah-Hartman 		port->mapbase = platp[i].mapbase;
610ab4382d2SGreg Kroah-Hartman 		port->membase = (platp[i].membase) ? platp[i].membase :
611ab4382d2SGreg Kroah-Hartman 			(unsigned char __iomem *) platp[i].mapbase;
612201d8975SGreg Ungerer 		port->dev = &pdev->dev;
613ab4382d2SGreg Kroah-Hartman 		port->iotype = SERIAL_IO_MEM;
614ab4382d2SGreg Kroah-Hartman 		port->irq = platp[i].irq;
615ab4382d2SGreg Kroah-Hartman 		port->uartclk = MCF_BUSCLK;
616ab4382d2SGreg Kroah-Hartman 		port->ops = &mcf_uart_ops;
6175fda7a0eSPeter Hurley 		port->flags = UPF_BOOT_AUTOCONF;
6182fc0184dSRicardo Ribalda Delgado 		port->rs485_config = mcf_config_rs485;
6190139da50SIlpo Järvinen 		port->rs485_supported = mcf_rs485_supported;
6204be87603SAngelo Dureghello 		port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE);
621ab4382d2SGreg Kroah-Hartman 
622ab4382d2SGreg Kroah-Hartman 		uart_add_one_port(&mcf_driver, port);
623ab4382d2SGreg Kroah-Hartman 	}
624ab4382d2SGreg Kroah-Hartman 
625ab4382d2SGreg Kroah-Hartman 	return 0;
626ab4382d2SGreg Kroah-Hartman }
627ab4382d2SGreg Kroah-Hartman 
628ab4382d2SGreg Kroah-Hartman /****************************************************************************/
629ab4382d2SGreg Kroah-Hartman 
mcf_remove(struct platform_device * pdev)630ae8d8a14SBill Pemberton static int mcf_remove(struct platform_device *pdev)
631ab4382d2SGreg Kroah-Hartman {
632ab4382d2SGreg Kroah-Hartman 	struct uart_port *port;
633ab4382d2SGreg Kroah-Hartman 	int i;
634ab4382d2SGreg Kroah-Hartman 
635ab4382d2SGreg Kroah-Hartman 	for (i = 0; (i < MCF_MAXPORTS); i++) {
636ab4382d2SGreg Kroah-Hartman 		port = &mcf_ports[i].port;
637ab4382d2SGreg Kroah-Hartman 		if (port)
638ab4382d2SGreg Kroah-Hartman 			uart_remove_one_port(&mcf_driver, port);
639ab4382d2SGreg Kroah-Hartman 	}
640ab4382d2SGreg Kroah-Hartman 
641ab4382d2SGreg Kroah-Hartman 	return 0;
642ab4382d2SGreg Kroah-Hartman }
643ab4382d2SGreg Kroah-Hartman 
644ab4382d2SGreg Kroah-Hartman /****************************************************************************/
645ab4382d2SGreg Kroah-Hartman 
646ab4382d2SGreg Kroah-Hartman static struct platform_driver mcf_platform_driver = {
647ab4382d2SGreg Kroah-Hartman 	.probe		= mcf_probe,
6482d47b716SBill Pemberton 	.remove		= mcf_remove,
649ab4382d2SGreg Kroah-Hartman 	.driver		= {
650ab4382d2SGreg Kroah-Hartman 		.name	= "mcfuart",
651ab4382d2SGreg Kroah-Hartman 	},
652ab4382d2SGreg Kroah-Hartman };
653ab4382d2SGreg Kroah-Hartman 
654ab4382d2SGreg Kroah-Hartman /****************************************************************************/
655ab4382d2SGreg Kroah-Hartman 
mcf_init(void)656ab4382d2SGreg Kroah-Hartman static int __init mcf_init(void)
657ab4382d2SGreg Kroah-Hartman {
658ab4382d2SGreg Kroah-Hartman 	int rc;
659ab4382d2SGreg Kroah-Hartman 
660ab4382d2SGreg Kroah-Hartman 	printk("ColdFire internal UART serial driver\n");
661ab4382d2SGreg Kroah-Hartman 
662ab4382d2SGreg Kroah-Hartman 	rc = uart_register_driver(&mcf_driver);
663ab4382d2SGreg Kroah-Hartman 	if (rc)
664ab4382d2SGreg Kroah-Hartman 		return rc;
665ab4382d2SGreg Kroah-Hartman 	rc = platform_driver_register(&mcf_platform_driver);
6662b359172SWei Yongjun 	if (rc) {
6672b359172SWei Yongjun 		uart_unregister_driver(&mcf_driver);
668ab4382d2SGreg Kroah-Hartman 		return rc;
6692b359172SWei Yongjun 	}
670ab4382d2SGreg Kroah-Hartman 	return 0;
671ab4382d2SGreg Kroah-Hartman }
672ab4382d2SGreg Kroah-Hartman 
673ab4382d2SGreg Kroah-Hartman /****************************************************************************/
674ab4382d2SGreg Kroah-Hartman 
mcf_exit(void)675ab4382d2SGreg Kroah-Hartman static void __exit mcf_exit(void)
676ab4382d2SGreg Kroah-Hartman {
677ab4382d2SGreg Kroah-Hartman 	platform_driver_unregister(&mcf_platform_driver);
678ab4382d2SGreg Kroah-Hartman 	uart_unregister_driver(&mcf_driver);
679ab4382d2SGreg Kroah-Hartman }
680ab4382d2SGreg Kroah-Hartman 
681ab4382d2SGreg Kroah-Hartman /****************************************************************************/
682ab4382d2SGreg Kroah-Hartman 
683ab4382d2SGreg Kroah-Hartman module_init(mcf_init);
684ab4382d2SGreg Kroah-Hartman module_exit(mcf_exit);
685ab4382d2SGreg Kroah-Hartman 
6866a1c34f4SGreg Ungerer MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
687ab4382d2SGreg Kroah-Hartman MODULE_DESCRIPTION("Freescale ColdFire UART driver");
688ab4382d2SGreg Kroah-Hartman MODULE_LICENSE("GPL");
689ab4382d2SGreg Kroah-Hartman MODULE_ALIAS("platform:mcfuart");
690ab4382d2SGreg Kroah-Hartman 
691ab4382d2SGreg Kroah-Hartman /****************************************************************************/
692