cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mcf.c (18883B)


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