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