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>
26496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen#include <linux/uaccess.h>
27574de559c1797618fd8ed03576837eb3113c5d26Jingoo Han#include <linux/platform_device.h>
2849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/coldfire.h>
2949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/mcfsim.h>
3049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/mcfuart.h>
3149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#include <asm/nettel.h>
3249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
3349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
3449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
3549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
3649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Some boards implement the DTR/DCD lines using GPIO lines, most
3749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	don't. Dummy out the access macros for those that don't. Those
3849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	that do should define these macros somewhere in there board
3949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	specific inlude files.
4049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
4149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_getppdcd)
4249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_getppdcd(p)		(1)
4349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
4449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_getppdtr)
4549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_getppdtr(p)		(1)
4649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
4749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if !defined(mcf_setppdtr)
4849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	mcf_setppdtr(p, v)	do { } while (0)
4949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif
5049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
5149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
5249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
5349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
5449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Local per-uart structure.
5549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
5649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstruct mcf_uart {
5749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port	port;
5849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int		sigs;		/* Local copy of line sigs */
5949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char		imr;		/* Local IMR mirror */
60496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	struct serial_rs485	rs485;		/* RS485 settings */
6149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
6249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
6449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic unsigned int mcf_tx_empty(struct uart_port *port)
6649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
6749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ?
6849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		TIOCSER_TEMT : 0;
6949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
7049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
7149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
7249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
7349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic unsigned int mcf_get_mctrl(struct uart_port *port)
7449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
759f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
7649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int sigs;
7749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
7849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ?
7949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		0 : TIOCM_CTS;
8049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (pp->sigs & TIOCM_RTS);
8149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0);
8249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0);
830ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy
8449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return sigs;
8549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
8649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
8749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
8849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
8949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_set_mctrl(struct uart_port *port, unsigned int sigs)
9049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
919f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
9249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
9349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->sigs = sigs;
9449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mcf_setppdtr(port->line, (sigs & TIOCM_DTR));
9549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (sigs & TIOCM_RTS)
9649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
9749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
9849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0);
9949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
10049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
10149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
10249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
10349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_start_tx(struct uart_port *port)
10449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1059f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
10649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
107496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	if (pp->rs485.flags & SER_RS485_ENABLED) {
108496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		/* Enable Transmitter */
109496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
110496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		/* Manually assert RTS */
111496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
112496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
11349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr |= MCFUART_UIR_TXREADY;
11449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
11549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
11649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
11749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
11849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
11949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_stop_tx(struct uart_port *port)
12049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1219f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
12249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
12349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr &= ~MCFUART_UIR_TXREADY;
12449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
12549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
12649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
12749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
12849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
12949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_stop_rx(struct uart_port *port)
13049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1319f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
13249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
13349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr &= ~MCFUART_UIR_RXREADY;
13449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
13549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
13649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
13749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
13849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
13949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_break_ctl(struct uart_port *port, int break_state)
14049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
14149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
14249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
14349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
14449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (break_state == -1)
14549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR);
14649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
14749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR);
14849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
14949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
15049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
15149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
15249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
15349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_startup(struct uart_port *port)
15449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1559f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
15649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
15749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
15849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
15949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Reset UART, get it into known state... */
16149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
16249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
16349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Enable the UART transmitter and receiver */
16549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
16649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCR);
16749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
16849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Enable RX interrupts now */
16949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr = MCFUART_UIR_RXREADY;
17049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
17149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
17349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
17549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
17649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
17849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
17949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_shutdown(struct uart_port *port)
18049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
1819f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
18249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
18349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
18449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
18549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
18649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Disable all interrupts now */
18749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	pp->imr = 0;
18849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(pp->imr, port->membase + MCFUART_UIMR);
18949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Disable UART transmitter and receiver */
19149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
19249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
19349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
19549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
19649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
19849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
19949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
20049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct ktermios *old)
20149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
202496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
20349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned long flags;
20449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int baud, baudclk;
20526a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#if defined(CONFIG_M5272)
20626a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson	unsigned int baudfr;
20726a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#endif
20849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char mr1, mr2;
20949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
21049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	baud = uart_get_baud_rate(port, termios, old, 0, 230400);
21126a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#if defined(CONFIG_M5272)
21226a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson	baudclk = (MCF_BUSCLK / baud) / 32;
21326a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson	baudfr = (((MCF_BUSCLK / baud) + 1) / 2) % 16;
21426a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#else
21549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	baudclk = ((MCF_BUSCLK / baud) + 16) / 32;
21626a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#endif
21749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
21849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
21949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	mr2 = 0;
22049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
22149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	switch (termios->c_cflag & CSIZE) {
22249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS5: mr1 |= MCFUART_MR1_CS5; break;
22349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS6: mr1 |= MCFUART_MR1_CS6; break;
22449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS7: mr1 |= MCFUART_MR1_CS7; break;
22549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	case CS8:
22649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	default:  mr1 |= MCFUART_MR1_CS8; break;
22749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
22849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
22949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & PARENB) {
23049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (termios->c_cflag & CMSPAR) {
23149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (termios->c_cflag & PARODD)
23249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYMARK;
23349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else
23449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYSPACE;
23549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		} else {
23649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (termios->c_cflag & PARODD)
23749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYODD;
23849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else
23949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				mr1 |= MCFUART_MR1_PARITYEVEN;
24049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		}
24149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	} else {
24249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr1 |= MCFUART_MR1_PARITYNONE;
24349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
24449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
245ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley	/*
246ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley	 * FIXME: port->read_status_mask and port->ignore_status_mask
247ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley	 * need to be initialized based on termios settings for
248ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley	 * INPCK, IGNBRK, IGNPAR, PARMRK, BRKINT
249ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley	 */
250ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley
25149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & CSTOPB)
25249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_STOP2;
25349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	else
25449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_STOP1;
25549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
25649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (termios->c_cflag & CRTSCTS) {
25749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr1 |= MCFUART_MR1_RXRTS;
25849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mr2 |= MCFUART_MR2_TXCTS;
25949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
26049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
261496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	if (pp->rs485.flags & SER_RS485_ENABLED) {
262496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		dev_dbg(port->dev, "Setting UART to RS485\n");
263496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		mr2 |= MCFUART_MR2_TXRTS;
264496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
265496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen
26649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_lock_irqsave(&port->lock, flags);
2673732b68f22857201fa09cb82b128f295096a2375Philippe De Muyter	uart_update_timeout(port, termios->c_cflag, baud);
26849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
26949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR);
27049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR);
27149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(mr1, port->membase + MCFUART_UMR);
27249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(mr2, port->membase + MCFUART_UMR);
27349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1);
27449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb((baudclk & 0xff), port->membase + MCFUART_UBG2);
27526a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#if defined(CONFIG_M5272)
27626a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson	writeb((baudfr & 0x0f), port->membase + MCFUART_UFPD);
27726a4bc66a6f57299027e04d90b14fe56a44c6d2bJohn Adamson#endif
27849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER,
27949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCSR);
28049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE,
28149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase + MCFUART_UCR);
28249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	spin_unlock_irqrestore(&port->lock, flags);
28349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
28449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
28549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
28649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
28749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_rx_chars(struct mcf_uart *pp)
28849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
2899f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct uart_port *port = &pp->port;
29049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned char status, ch, flag;
29149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
29249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) {
29349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		ch = readb(port->membase + MCFUART_URB);
29449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		flag = TTY_NORMAL;
29549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.rx++;
29649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
29749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (status & MCFUART_USR_RXERR) {
29849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			writeb(MCFUART_UCR_CMDRESETERR,
29949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->membase + MCFUART_UCR);
30049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
30149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (status & MCFUART_USR_RXBREAK) {
30249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.brk++;
30349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				if (uart_handle_break(port))
30449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer					continue;
30549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXPARITY) {
30649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.parity++;
30749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXOVERRUN) {
30849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.overrun++;
30949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			} else if (status & MCFUART_USR_RXFRAMING) {
31049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				port->icount.frame++;
31149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			}
31249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
31349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			status &= port->read_status_mask;
31449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
31549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			if (status & MCFUART_USR_RXBREAK)
31649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_BREAK;
31749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else if (status & MCFUART_USR_RXPARITY)
31849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_PARITY;
31949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			else if (status & MCFUART_USR_RXFRAMING)
32049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer				flag = TTY_FRAME;
32149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		}
32249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
32349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (uart_handle_sysrq_char(port, ch))
32449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			continue;
32549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
32649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
32749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
3285275ad70fed320f6264d98f0b6f32c06941ccf26Viresh Kumar	spin_unlock(&port->lock);
3292e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby	tty_flip_buffer_push(&port->state->port);
3305275ad70fed320f6264d98f0b6f32c06941ccf26Viresh Kumar	spin_lock(&port->lock);
33149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
33249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
33349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
33449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
33549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_tx_chars(struct mcf_uart *pp)
33649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
3379f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct uart_port *port = &pp->port;
338ebd2c8f6d2ec4012c267ecb95e72a57b8355a705Alan Cox	struct circ_buf *xmit = &port->state->xmit;
33949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
34049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (port->x_char) {
34149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		/* Send special char - probably flow control */
34249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(port->x_char, port->membase + MCFUART_UTB);
34349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->x_char = 0;
34449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.tx++;
34549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return;
34649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
34749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
34849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
34949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (xmit->head == xmit->tail)
35049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
35149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
35249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
35349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->icount.tx++;
35449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
35549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
35649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
35749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_write_wakeup(port);
35849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
35949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (xmit->head == xmit->tail) {
36049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		pp->imr &= ~MCFUART_UIR_TXREADY;
36149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		writeb(pp->imr, port->membase + MCFUART_UIMR);
362496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		/* Disable TX to negate RTS automatically */
363496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		if (pp->rs485.flags & SER_RS485_ENABLED)
364496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen			writeb(MCFUART_UCR_TXDISABLE,
365496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen				port->membase + MCFUART_UCR);
36649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
36749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
36849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
36949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
37049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
37149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic irqreturn_t mcf_interrupt(int irq, void *data)
37249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
37349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port = data;
3749f69ba86d66297189916ceae401fe0944a207714Greg Ungerer	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
37549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	unsigned int isr;
3760ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	irqreturn_t ret = IRQ_NONE;
37749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
37849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	isr = readb(port->membase + MCFUART_UISR) & pp->imr;
3790ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy
3800ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	spin_lock(&port->lock);
3810ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	if (isr & MCFUART_UIR_RXREADY) {
38249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_rx_chars(pp);
3830ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy		ret = IRQ_HANDLED;
3840ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	}
3850ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	if (isr & MCFUART_UIR_TXREADY) {
38649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_tx_chars(pp);
3870ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy		ret = IRQ_HANDLED;
3880ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	}
3890ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	spin_unlock(&port->lock);
3900ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy
3910ac8382e9cfdd723445692fc97aaa4643929750dYury Georgievskiy	return ret;
39249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
39349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
39449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
39549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
39649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_config_port(struct uart_port *port, int flags)
39749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
39849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	port->type = PORT_MCF;
3993732b68f22857201fa09cb82b128f295096a2375Philippe De Muyter	port->fifosize = MCFUART_TXFIFOSIZE;
40049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
40149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Clear mask, so no surprise interrupts. */
40249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(0, port->membase + MCFUART_UIMR);
40349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
4049cfb5c05fee914cc65d4706801f6bc424082b5f5Yong Zhang	if (request_irq(port->irq, mcf_interrupt, 0, "UART", port))
40549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		printk(KERN_ERR "MCF: unable to attach ColdFire UART %d "
40649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			"interrupt vector=%d\n", port->line, port->irq);
40749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
40849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
40949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
41049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
41149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic const char *mcf_type(struct uart_port *port)
41249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
41349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return (port->type == PORT_MCF) ? "ColdFire UART" : NULL;
41449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
41549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
41649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
41749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
41849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_request_port(struct uart_port *port)
41949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
42049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* UARTs always present */
42149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
42249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
42349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
42449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
42549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
42649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_release_port(struct uart_port *port)
42749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
42849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	/* Nothing to release... */
42949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
43049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
43149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
43249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
43349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
43449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
43549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_MCF))
43649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return -EINVAL;
43749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
43849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
43949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
44049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
44149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
442496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen/* Enable or disable the RS485 support */
443496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyenstatic void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
444496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen{
445496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
446496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	unsigned long flags;
447496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	unsigned char mr1, mr2;
448496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen
449496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	spin_lock_irqsave(&port->lock, flags);
450496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	/* Get mode registers */
451496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	mr1 = readb(port->membase + MCFUART_UMR);
452496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	mr2 = readb(port->membase + MCFUART_UMR);
453496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	if (rs485->flags & SER_RS485_ENABLED) {
454496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		dev_dbg(port->dev, "Setting UART to RS485\n");
455496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		/* Automatically negate RTS after TX completes */
456496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		mr2 |= MCFUART_MR2_TXRTS;
457496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	} else {
458496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		dev_dbg(port->dev, "Setting UART to RS232\n");
459496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		mr2 &= ~MCFUART_MR2_TXRTS;
460496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
461496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	writeb(mr1, port->membase + MCFUART_UMR);
462496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	writeb(mr2, port->membase + MCFUART_UMR);
463496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	pp->rs485 = *rs485;
464496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	spin_unlock_irqrestore(&port->lock, flags);
465496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen}
466496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen
467496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyenstatic int mcf_ioctl(struct uart_port *port, unsigned int cmd,
468496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		unsigned long arg)
469496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen{
470496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	switch (cmd) {
471496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	case TIOCSRS485: {
472496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		struct serial_rs485 rs485;
473496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		if (copy_from_user(&rs485, (struct serial_rs485 *)arg,
474496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen				sizeof(struct serial_rs485)))
475496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen			return -EFAULT;
476496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		mcf_config_rs485(port, &rs485);
477496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		break;
478496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
479496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	case TIOCGRS485: {
480496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
481496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485,
482496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen				sizeof(struct serial_rs485)))
483496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen			return -EFAULT;
484496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		break;
485496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
486496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	default:
487496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen		return -ENOIOCTLCMD;
488496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	}
489496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	return 0;
490496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen}
491496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen
492496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen/****************************************************************************/
493496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen
49449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
49549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Define the basic serial functions we support.
49649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
4973732b68f22857201fa09cb82b128f295096a2375Philippe De Muyterstatic const struct uart_ops mcf_uart_ops = {
49849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.tx_empty	= mcf_tx_empty,
49949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.get_mctrl	= mcf_get_mctrl,
50049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.set_mctrl	= mcf_set_mctrl,
50149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.start_tx	= mcf_start_tx,
50249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.stop_tx	= mcf_stop_tx,
50349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.stop_rx	= mcf_stop_rx,
50449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.break_ctl	= mcf_break_ctl,
50549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.startup	= mcf_startup,
50649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.shutdown	= mcf_shutdown,
50749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.set_termios	= mcf_set_termios,
50849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.type		= mcf_type,
50949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.request_port	= mcf_request_port,
51049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.release_port	= mcf_release_port,
51149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.config_port	= mcf_config_port,
51249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.verify_port	= mcf_verify_port,
513496c907740ff083499f5449d2907af442e79ceb0Quoc-Viet Nguyen	.ioctl		= mcf_ioctl,
51449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
51549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
5162545cf6e94b4eb5a2c48dd55751aa9a70ff1ff9dPhilippe De Muyterstatic struct mcf_uart mcf_ports[4];
51749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
51816791963ff7dd6a108251f5fa4b273cf1ffe531fGreg Ungerer#define	MCF_MAXPORTS	ARRAY_SIZE(mcf_ports)
51949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
52049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
52149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#if defined(CONFIG_SERIAL_MCF_CONSOLE)
52249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
52349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
52449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererint __init early_mcf_setup(struct mcf_platform_uart *platp)
52549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
52649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
52749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
52849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
52949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
53049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
53149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
53249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->line = i;
53349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->type = PORT_MCF;
53449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->mapbase = platp[i].mapbase;
53549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase = (platp[i].membase) ? platp[i].membase :
53649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			(unsigned char __iomem *) port->mapbase;
53749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->iotype = SERIAL_IO_MEM;
53849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->irq = platp[i].irq;
53949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->uartclk = MCF_BUSCLK;
5405fda7a0e715c32c6dd9a39ebce8429eeafb64b7dPeter Hurley		port->flags = UPF_BOOT_AUTOCONF;
54149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->ops = &mcf_uart_ops;
54249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
54349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
54549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
54649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
54849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
54949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_console_putc(struct console *co, const char c)
55049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
55149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port = &(mcf_ports + co->index)->port;
55249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
55349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
55449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < 0x10000); i++) {
55549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
55649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
55749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
55849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	writeb(c, port->membase + MCFUART_UTB);
55949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < 0x10000); i++) {
56049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY)
56149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			break;
56249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
56349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
56449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
56549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
56649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
56749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void mcf_console_write(struct console *co, const char *s, unsigned int count)
56849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
56949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (; (count); count--, s++) {
57049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		mcf_console_putc(co, *s);
57149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (*s == '\n')
57249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			mcf_console_putc(co, '\r');
57349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
57449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
57549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
57649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
57749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
57849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_console_setup(struct console *co, char *options)
57949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
58049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
58149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int baud = CONFIG_SERIAL_MCF_BAUDRATE;
58249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int bits = 8;
58349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int parity = 'n';
58449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int flow = 'n';
58549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
5864330e179a96bc9310d36e9b858bc8f275f329312Len Sorensen	if ((co->index < 0) || (co->index >= MCF_MAXPORTS))
58749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		co->index = 0;
58849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	port = &mcf_ports[co->index].port;
58949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (port->membase == 0)
59049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return -ENODEV;
59149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (options)
59349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_parse_options(options, &baud, &parity, &bits, &flow);
59449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return uart_set_options(port, co, baud, parity, bits, flow);
59649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
59749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
59849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
59949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
60049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct uart_driver mcf_driver;
60149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
60249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct console mcf_console = {
60349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.name		= "ttyS",
60449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.write		= mcf_console_write,
60549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.device		= uart_console_device,
60649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.setup		= mcf_console_setup,
60749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.flags		= CON_PRINTBUFFER,
60849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.index		= -1,
60949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.data		= &mcf_driver,
61049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
61149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
61249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_console_init(void)
61349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
61449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	register_console(&mcf_console);
61549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
61649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
61749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
61849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererconsole_initcall(mcf_console_init);
61949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	MCF_CONSOLE	&mcf_console
62149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
62349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#else
62449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
62549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#define	MCF_CONSOLE	NULL
62749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
62849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
62949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer#endif /* CONFIG_MCF_CONSOLE */
63049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
63149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
63249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/*
63349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer *	Define the mcf UART driver structure.
63449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer */
63549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct uart_driver mcf_driver = {
63649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.owner		= THIS_MODULE,
63749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.driver_name	= "mcf",
63849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.dev_name	= "ttyS",
63949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.major		= TTY_MAJOR,
64049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.minor		= 64,
64149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.nr		= MCF_MAXPORTS,
64249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.cons		= MCF_CONSOLE,
64349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
64449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
64549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
64649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
6479671f09921d93e722a28ae9610d478e092ac5466Bill Pembertonstatic int mcf_probe(struct platform_device *pdev)
64849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
649574de559c1797618fd8ed03576837eb3113c5d26Jingoo Han	struct mcf_platform_uart *platp = dev_get_platdata(&pdev->dev);
65049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
65149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
65249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
65349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; ((i < MCF_MAXPORTS) && (platp[i].mapbase)); i++) {
65449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
65549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
65649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->line = i;
65749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->type = PORT_MCF;
65849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->mapbase = platp[i].mapbase;
65949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->membase = (platp[i].membase) ? platp[i].membase :
66049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			(unsigned char __iomem *) platp[i].mapbase;
66149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->iotype = SERIAL_IO_MEM;
66249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->irq = platp[i].irq;
66349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->uartclk = MCF_BUSCLK;
66449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port->ops = &mcf_uart_ops;
6655fda7a0e715c32c6dd9a39ebce8429eeafb64b7dPeter Hurley		port->flags = UPF_BOOT_AUTOCONF;
66649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
66749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		uart_add_one_port(&mcf_driver, port);
66849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
66949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
67049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
67149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
67249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
67349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
67449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
675ae8d8a146725a966bd7c59c94f4d0016dcf7a04fBill Pembertonstatic int mcf_remove(struct platform_device *pdev)
67649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
67749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	struct uart_port *port;
67849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int i;
67949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
68049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	for (i = 0; (i < MCF_MAXPORTS); i++) {
68149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		port = &mcf_ports[i].port;
68249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		if (port)
68349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer			uart_remove_one_port(&mcf_driver, port);
68449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	}
68549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
68649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
68749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
68849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
68949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
69049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
69149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic struct platform_driver mcf_platform_driver = {
69249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.probe		= mcf_probe,
6932d47b7160243b1422006b91debf438484a4fde58Bill Pemberton	.remove		= mcf_remove,
69449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	.driver		= {
69549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		.name	= "mcfuart",
69649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		.owner	= THIS_MODULE,
69749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	},
69849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer};
69949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
70049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
70149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
70249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic int __init mcf_init(void)
70349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
70449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	int rc;
70549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
70649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	printk("ColdFire internal UART serial driver\n");
70749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
70849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	rc = uart_register_driver(&mcf_driver);
70949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	if (rc)
71049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return rc;
71149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	rc = platform_driver_register(&mcf_platform_driver);
7122b359172e013c6b1b7e424e5be92a70fc7cceaafWei Yongjun	if (rc) {
7132b359172e013c6b1b7e424e5be92a70fc7cceaafWei Yongjun		uart_unregister_driver(&mcf_driver);
71449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer		return rc;
7152b359172e013c6b1b7e424e5be92a70fc7cceaafWei Yongjun	}
71649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	return 0;
71749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
71849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
71949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
72049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
72149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungererstatic void __exit mcf_exit(void)
72249aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer{
72349aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	platform_driver_unregister(&mcf_platform_driver);
72449aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer	uart_unregister_driver(&mcf_driver);
72549aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer}
72649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
72749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
72849aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
72949aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerermodule_init(mcf_init);
73049aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerermodule_exit(mcf_exit);
73149aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
73249aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
73349aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_DESCRIPTION("Freescale ColdFire UART driver");
73449aa49bfd40d718095669c1c70c9d167b814e29bGreg UngererMODULE_LICENSE("GPL");
735e169c139642fb4c682ec12a409725508dbefa520Kay SieversMODULE_ALIAS("platform:mcfuart");
73649aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer
73749aa49bfd40d718095669c1c70c9d167b814e29bGreg Ungerer/****************************************************************************/
738