mcf.c revision e169c139642fb4c682ec12a409725508dbefa520
149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	mcf.c -- Freescale ColdFire UART driver
549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *
649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	(C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *
849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer * This program is free software; you can redistribute it and/or modify
949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer * it under the terms of the GNU General Public License as published by
1049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer * the Free Software Foundation; either version 2 of the License, or
1149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer * (at your option) any later version.
1249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
1349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
1449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
1549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
1649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/kernel.h>
1749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/init.h>
1849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/interrupt.h>
1949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/module.h>
2049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/console.h>
2149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/tty.h>
2249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/tty_flip.h>
2349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/serial.h>
2449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/serial_core.h>
2549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <linux/io.h>
2649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/coldfire.h>
2749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/mcfsim.h>
2849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/mcfuart.h>
2949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/nettel.h>
3049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
3149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
3249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
3349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
3449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Some boards implement the DTR/DCD lines using GPIO lines, most
3549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	don't. Dummy out the access macros for those that don't. Those
3649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	that do should define these macros somewhere in there board
3749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	specific inlude files.
3849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
3949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_getppdcd)
4049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_getppdcd(p)		(1)
4149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
4249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_getppdtr)
4349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_getppdtr(p)		(1)
4449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
4549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_setppdtr)
4649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_setppdtr(p, v)	do { } while (0)
4749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
4849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
4949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
5049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
5149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
5249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Local per-uart structure.
5349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
5449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstruct mcf_uart {
5549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port	port;
5649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int		sigs;		/* Local copy of line sigs */
5749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char		imr;		/* Local IMR mirror */
5849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
5949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
6149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic unsigned int mcf_tx_empty(struct uart_port *port)
6349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
6449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
6549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		TIOCSER_TEMT : 0;
6649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
6749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
6949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
7049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic unsigned int mcf_get_mctrl(struct uart_port *port)
7149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
729f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
7349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
7449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int sigs;
7549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
7649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
7749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
7849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		0 : TIOCM_CTS;
7949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (pp->sigs & TIOCM_RTS);
8049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
8149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
8249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
8349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return sigs;
8449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
8549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
8649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
8749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
8849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
8949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
909f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
9149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
9249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
9349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
9449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->sigs = sigs;
9549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
9649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (sigs & TIOCM_RTS)
9749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
9849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
9949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
10049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
10149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
10249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
10349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
10449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
10549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_start_tx(struct uart_port *port)
10649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1079f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
10849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
10949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
11049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
11149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr |= MCFUART_UIR_TXREADY;
11249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
11349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
11449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
11549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
11649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
11749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
11849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_stop_tx(struct uart_port *port)
11949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1209f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
12149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
12249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
12349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
12449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr &= ~MCFUART_UIR_TXREADY;
12549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
12649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
12749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
12849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
12949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
13049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
13149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_stop_rx(struct uart_port *port)
13249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1339f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
13449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
13549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
13649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
13749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr &= ~MCFUART_UIR_RXREADY;
13849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
13949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
14049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
14149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
14249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
14349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
14449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_break_ctl(struct uart_port *port, int break_state)
14549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
14649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
14749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
14849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
14949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (break_state == -1)
15049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
15149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
15249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
15349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
15449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
15549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
15649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
15749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
15849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_enable_ms(struct uart_port *port)
15949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
16049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
16149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
16349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_startup(struct uart_port *port)
16549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1669f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
16749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
16849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
17049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Reset UART, get it into known state... */
17249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
17349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
17449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Enable the UART transmitter and receiver */
17649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
17749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCR);
17849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Enable RX interrupts now */
18049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr = MCFUART_UIR_RXREADY;
18149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
18249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
18349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
18449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
18549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
18649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
18749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
18849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
18949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_shutdown(struct uart_port *port)
19149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1929f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
19349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
19449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
19649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Disable all interrupts now */
19849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr = 0;
19949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
20049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
20149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Disable UART transmitter and receiver */
20249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
20349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
20449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
20549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
20649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
20749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
20849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
20949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
21049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
21149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct ktermios *old)
21249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
21349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
21449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int baud, baudclk;
21549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char mr1, mr2;
21649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
21749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
21849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
21949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
22049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
22149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mr2 = 0;
22249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
22349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	switch (termios->c_cflag & CSIZE) {
22449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS5: mr1 |= MCFUART_MR1_CS5; break;
22549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS6: mr1 |= MCFUART_MR1_CS6; break;
22649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS7: mr1 |= MCFUART_MR1_CS7; break;
22749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS8:
22849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	default:  mr1 |= MCFUART_MR1_CS8; break;
22949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
23049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
23149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & PARENB) {
23249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (termios->c_cflag & CMSPAR) {
23349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (termios->c_cflag & PARODD)
23449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYMARK;
23549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else
23649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYSPACE;
23749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		} else {
23849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (termios->c_cflag & PARODD)
23949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYODD;
24049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else
24149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYEVEN;
24249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		}
24349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	} else {
24449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr1 |= MCFUART_MR1_PARITYNONE;
24549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
24649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
24749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & CSTOPB)
24849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_STOP2;
24949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
25049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_STOP1;
25149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
25249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & CRTSCTS) {
25349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr1 |= MCFUART_MR1_RXRTS;
25449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_TXCTS;
25549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
25649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
25749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
25849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
25949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
26049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
26149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(mr1, port->membase + MCFUART_UMR);
26249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(mr2, port->membase + MCFUART_UMR);
26349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
26449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
26549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
26649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCSR);
26749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
26849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCR);
26949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
27049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
27149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
27249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
27349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
27449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_rx_chars(struct mcf_uart *pp)
27549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
2769f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct uart_port *port = &pp->port;
27749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char status, ch, flag;
27849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
27949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
28049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		ch = readb(port->membase + MCFUART_URB);
28149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		flag = TTY_NORMAL;
28249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.rx++;
28349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
28449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (status & MCFUART_USR_RXERR) {
28549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			writeb(MCFUART_UCR_CMDRESETERR,
28649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->membase + MCFUART_UCR);
28749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
28849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (status & MCFUART_USR_RXBREAK) {
28949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.brk++;
29049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				if (uart_handle_break(port))
29149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer					continue;
29249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXPARITY) {
29349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.parity++;
29449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXOVERRUN) {
29549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.overrun++;
29649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXFRAMING) {
29749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.frame++;
29849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			}
29949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
30049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			status &= port->read_status_mask;
30149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
30249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (status & MCFUART_USR_RXBREAK)
30349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_BREAK;
30449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else if (status & MCFUART_USR_RXPARITY)
30549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_PARITY;
30649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else if (status & MCFUART_USR_RXFRAMING)
30749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_FRAME;
30849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		}
30949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
31049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (uart_handle_sysrq_char(port, ch))
31149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			continue;
31249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
31349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
31449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
31549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	tty_flip_buffer_push(port->info->tty);
31649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
31749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
31849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
31949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
32049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_tx_chars(struct mcf_uart *pp)
32149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
3229f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct uart_port *port = &pp->port;
32349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct circ_buf *xmit = &port->info->xmit;
32449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
32549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (port->x_char) {
32649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		/* Send special char - probably flow control */
32749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(port->x_char, port->membase + MCFUART_UTB);
32849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->x_char = 0;
32949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.tx++;
33049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return;
33149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
33249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
33349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
33449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (xmit->head == xmit->tail)
33549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
33649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
33749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
33849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.tx++;
33949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
34049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
34149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
34249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_write_wakeup(port);
34349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
34449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (xmit->head == xmit->tail) {
34549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		pp->imr &= ~MCFUART_UIR_TXREADY;
34649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(pp->imr, port->membase + MCFUART_UIMR);
34749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
34849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
34949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
35049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
35149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
35249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic irqreturn_t mcf_interrupt(int irq, void *data)
35349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
35449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port = data;
3559f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
35649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int isr;
35749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
35849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	isr = readb(port->membase + MCFUART_UISR) & pp->imr;
35949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (isr & MCFUART_UIR_RXREADY)
36049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_rx_chars(pp);
36149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (isr & MCFUART_UIR_TXREADY)
36249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_tx_chars(pp);
36349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return IRQ_HANDLED;
36449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
36549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
36649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
36749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
36849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_config_port(struct uart_port *port, int flags)
36949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
37049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	port->type = PORT_MCF;
37149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
37249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Clear mask, so no surprise interrupts. */
37349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(0, port->membase + MCFUART_UIMR);
37449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
37549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (request_irq(port->irq, mcf_interrupt, IRQF_DISABLED, "UART", port))
37649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
37749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			"interrupt vector=%d\n", port->line, port->irq);
37849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
37949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
38049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
38149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
38249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic const char *mcf_type(struct uart_port *port)
38349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
38449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
38549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
38649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
38749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
38849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
38949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_request_port(struct uart_port *port)
39049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
39149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* UARTs always present */
39249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
39349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
39449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
39549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
39649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
39749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_release_port(struct uart_port *port)
39849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
39949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Nothing to release... */
40049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
40149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
40249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
40349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
40449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
40549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
40649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
40749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return -EINVAL;
40849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
40949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
41049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
41149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
41249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
41349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
41449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Define the basic serial functions we support.
41549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
41649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct uart_ops mcf_uart_ops = {
41749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.tx_empty	= mcf_tx_empty,
41849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.get_mctrl	= mcf_get_mctrl,
41949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.set_mctrl	= mcf_set_mctrl,
42049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.start_tx	= mcf_start_tx,
42149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.stop_tx	= mcf_stop_tx,
42249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.stop_rx	= mcf_stop_rx,
42349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.enable_ms	= mcf_enable_ms,
42449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.break_ctl	= mcf_break_ctl,
42549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.startup	= mcf_startup,
42649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.shutdown	= mcf_shutdown,
42749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.set_termios	= mcf_set_termios,
42849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.type		= mcf_type,
42949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.request_port	= mcf_request_port,
43049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.release_port	= mcf_release_port,
43149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.config_port	= mcf_config_port,
43249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.verify_port	= mcf_verify_port,
43349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
43449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
43549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct mcf_uart mcf_ports[3];
43649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
43716791963ff7dd6a108251f5fa4b273cf1ffe531fGreg Ungerer#define	MCF_MAXPORTS	ARRAY_SIZE(mcf_ports)
43849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
43949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
44049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if defined(CONFIG_SERIAL_MCF_CONSOLE)
44149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
44249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
44349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererint __init early_mcf_setup(struct mcf_platform_uart *platp)
44449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
44549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
44649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
44749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
44849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
44949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
45049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
45149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->line = i;
45249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->type = PORT_MCF;
45349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->mapbase = platp[i].mapbase;
45449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase = (platp[i].membase) ? platp[i].membase :
45549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			(unsigned char __iomem *) port->mapbase;
45649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->iotype = SERIAL_IO_MEM;
45749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->irq = platp[i].irq;
45849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->uartclk = MCF_BUSCLK;
45949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->flags = ASYNC_BOOT_AUTOCONF;
46049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->ops = &mcf_uart_ops;
46149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
46249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
46349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
46449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
46549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
46649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
46749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
46849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_console_putc(struct console *co, const char c)
46949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
47049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port = &(mcf_ports + co->index)->port;
47149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
47249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
47349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < 0x10000); i++) {
47449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
47549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
47649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
47749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(c, port->membase + MCFUART_UTB);
47849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < 0x10000); i++) {
47949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
48049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
48149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
48249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
48349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
48449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
48549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
48649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_console_write(struct console *co, const char *s, unsigned int count)
48749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
48849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (; (count); count--, s++) {
48949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_console_putc(co, *s);
49049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (*s == '\n')
49149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			mcf_console_putc(co, '\r');
49249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
49349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
49449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
49549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
49649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
49749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_console_setup(struct console *co, char *options)
49849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
49949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
50049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int baud = CONFIG_SERIAL_MCF_BAUDRATE;
50149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int bits = 8;
50249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int parity = 'n';
50349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int flow = 'n';
50449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
50549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if ((co->index >= 0) && (co->index <= MCF_MAXPORTS))
50649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		co->index = 0;
50749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	port = &mcf_ports[co->index].port;
50849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (port->membase == 0)
50949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return -ENODEV;
51049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
51149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (options)
51249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_parse_options(options, &baud, &parity, &bits, &flow);
51349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
51449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return uart_set_options(port, co, baud, parity, bits, flow);
51549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
51649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
51749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
51849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
51949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct uart_driver mcf_driver;
52049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
52149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct console mcf_console = {
52249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.name		= "ttyS",
52349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.write		= mcf_console_write,
52449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.device		= uart_console_device,
52549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.setup		= mcf_console_setup,
52649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.flags		= CON_PRINTBUFFER,
52749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.index		= -1,
52849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.data		= &mcf_driver,
52949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
53049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
53149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_console_init(void)
53249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
53349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	register_console(&mcf_console);
53449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
53549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
53649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
53749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererconsole_initcall(mcf_console_init);
53849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
53949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	MCF_CONSOLE	&mcf_console
54049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
54249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#else
54349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
54449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	MCF_CONSOLE	NULL
54649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
54849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif /* CONFIG_MCF_CONSOLE */
54949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
55049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
55149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
55249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Define the mcf UART driver structure.
55349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
55449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct uart_driver mcf_driver = {
55549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.owner		= THIS_MODULE,
55649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.driver_name	= "mcf",
55749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.dev_name	= "ttyS",
55849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.major		= TTY_MAJOR,
55949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.minor		= 64,
56049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.nr		= MCF_MAXPORTS,
56149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.cons		= MCF_CONSOLE,
56249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
56349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
56449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
56549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
56649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __devinit mcf_probe(struct platform_device *pdev)
56749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
56849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct mcf_platform_uart *platp = pdev->dev.platform_data;
56949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
57049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
57149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
57249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
57349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
57449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
57549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->line = i;
57649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->type = PORT_MCF;
57749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->mapbase = platp[i].mapbase;
57849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase = (platp[i].membase) ? platp[i].membase :
57949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			(unsigned char __iomem *) platp[i].mapbase;
58049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->iotype = SERIAL_IO_MEM;
58149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->irq = platp[i].irq;
58249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->uartclk = MCF_BUSCLK;
58349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->ops = &mcf_uart_ops;
58449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->flags = ASYNC_BOOT_AUTOCONF;
58549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
58649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_add_one_port(&mcf_driver, port);
58749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
58849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
58949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
59049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
59149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
59349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_remove(struct platform_device *pdev)
59549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
59649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
59749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
59849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < MCF_MAXPORTS); i++) {
60049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
60149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (port)
60249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			uart_remove_one_port(&mcf_driver, port);
60349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
60449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
60549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
60649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
60749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
60849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
60949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
61049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct platform_driver mcf_platform_driver = {
61149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.probe		= mcf_probe,
61249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.remove		= __devexit_p(mcf_remove),
61349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.driver		= {
61449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		.name	= "mcfuart",
61549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		.owner	= THIS_MODULE,
61649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	},
61749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
61849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
61949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
62049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_init(void)
62249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
62349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int rc;
62449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	printk("ColdFire internal UART serial driver\n");
62649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	rc = uart_register_driver(&mcf_driver);
62849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (rc)
62949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return rc;
63049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	rc = platform_driver_register(&mcf_platform_driver);
63149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (rc)
63249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return rc;
63349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
63449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
63549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
63649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
63749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
63849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void __exit mcf_exit(void)
63949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
64049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	platform_driver_unregister(&mcf_platform_driver);
64149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	uart_unregister_driver(&mcf_driver);
64249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
64349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
64449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
64549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
64649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerermodule_init(mcf_init);
64749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerermodule_exit(mcf_exit);
64849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
64949aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
65049aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_DESCRIPTION("Freescale ColdFire UART driver");
65149aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_LICENSE("GPL");
652e169c139642fb4c682ec12a409725508dbefa520Kay SieversMODULE_ALIAS("platform:mcfuart");
65349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
65449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
655