diff options
Diffstat (limited to 'drivers/serial/serial_lh7a40x.c')
| -rw-r--r-- | drivers/serial/serial_lh7a40x.c | 682 | 
1 files changed, 0 insertions, 682 deletions
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c deleted file mode 100644 index ea744707c4d..00000000000 --- a/drivers/serial/serial_lh7a40x.c +++ /dev/null @@ -1,682 +0,0 @@ -/* drivers/serial/serial_lh7a40x.c - * - *  Copyright (C) 2004 Coastal Environmental Systems - * - *  This program is free software; you can redistribute it and/or - *  modify it under the terms of the GNU General Public License - *  version 2 as published by the Free Software Foundation. - * - */ - -/* Driver for Sharp LH7A40X embedded serial ports - * - *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - *  Based on drivers/serial/amba.c, by Deep Blue Solutions Ltd. - * - *  --- - * - * This driver supports the embedded UARTs of the Sharp LH7A40X series - * CPUs.  While similar to the 16550 and other UART chips, there is - * nothing close to register compatibility.  Moreover, some of the - * modem control lines are not available, either in the chip or they - * are lacking in the board-level implementation. - * - * - Use of SIRDIS - *   For simplicity, we disable the IR functions of any UART whenever - *   we enable it. - * - */ - - -#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - -#include <linux/module.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/console.h> -#include <linux/sysrq.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/io.h> - -#include <asm/irq.h> -#include <mach/hardware.h> - -#define DEV_MAJOR	204 -#define DEV_MINOR	16 -#define DEV_NR		3 - -#define ISR_LOOP_LIMIT	256 - -#define UR(p,o)	_UR ((p)->membase, o) -#define _UR(b,o) (*((volatile unsigned int*)(((unsigned char*) b) + (o)))) -#define BIT_CLR(p,o,m)	UR(p,o) = UR(p,o) & (~(unsigned int)m) -#define BIT_SET(p,o,m)	UR(p,o) = UR(p,o) | ( (unsigned int)m) - -#define UART_REG_SIZE	32 - -#define UART_R_DATA	(0x00) -#define UART_R_FCON	(0x04) -#define UART_R_BRCON	(0x08) -#define UART_R_CON	(0x0c) -#define UART_R_STATUS	(0x10) -#define UART_R_RAWISR	(0x14) -#define UART_R_INTEN	(0x18) -#define UART_R_ISR	(0x1c) - -#define UARTEN		(0x01)		/* UART enable */ -#define SIRDIS		(0x02)		/* Serial IR disable (UART1 only) */ - -#define RxEmpty		(0x10) -#define TxEmpty		(0x80) -#define TxFull		(0x20) -#define nRxRdy		RxEmpty -#define nTxRdy		TxFull -#define TxBusy		(0x08) - -#define RxBreak		(0x0800) -#define RxOverrunError	(0x0400) -#define RxParityError	(0x0200) -#define RxFramingError	(0x0100) -#define RxError     (RxBreak | RxOverrunError | RxParityError | RxFramingError) - -#define DCD		(0x04) -#define DSR		(0x02) -#define CTS		(0x01) - -#define RxInt		(0x01) -#define TxInt		(0x02) -#define ModemInt	(0x04) -#define RxTimeoutInt	(0x08) - -#define MSEOI		(0x10) - -#define WLEN_8		(0x60) -#define WLEN_7		(0x40) -#define WLEN_6		(0x20) -#define WLEN_5		(0x00) -#define WLEN		(0x60)	/* Mask for all word-length bits */ -#define STP2		(0x08) -#define PEN		(0x02)	/* Parity Enable */ -#define EPS		(0x04)	/* Even Parity Set */ -#define FEN		(0x10)	/* FIFO Enable */ -#define BRK		(0x01)	/* Send Break */ - - -struct uart_port_lh7a40x { -	struct uart_port port; -	unsigned int statusPrev; /* Most recently read modem status */ -}; - -static void lh7a40xuart_stop_tx (struct uart_port* port) -{ -	BIT_CLR (port, UART_R_INTEN, TxInt); -} - -static void lh7a40xuart_start_tx (struct uart_port* port) -{ -	BIT_SET (port, UART_R_INTEN, TxInt); - -	/* *** FIXME: do I need to check for startup of the -		      transmitter?  The old driver did, but AMBA -		      doesn't . */ -} - -static void lh7a40xuart_stop_rx (struct uart_port* port) -{ -	BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); -} - -static void lh7a40xuart_enable_ms (struct uart_port* port) -{ -	BIT_SET (port, UART_R_INTEN, ModemInt); -} - -static void lh7a40xuart_rx_chars (struct uart_port* port) -{ -	struct tty_struct* tty = port->state->port.tty; -	int cbRxMax = 256;	/* (Gross) limit on receive */ -	unsigned int data;	/* Received data and status */ -	unsigned int flag; - -	while (!(UR (port, UART_R_STATUS) & nRxRdy) && --cbRxMax) { -		data = UR (port, UART_R_DATA); -		flag = TTY_NORMAL; -		++port->icount.rx; - -		if (unlikely(data & RxError)) { -			if (data & RxBreak) { -				data &= ~(RxFramingError | RxParityError); -				++port->icount.brk; -				if (uart_handle_break (port)) -					continue; -			} -			else if (data & RxParityError) -				++port->icount.parity; -			else if (data & RxFramingError) -				++port->icount.frame; -			if (data & RxOverrunError) -				++port->icount.overrun; - -				/* Mask by termios, leave Rx'd byte */ -			data &= port->read_status_mask | 0xff; - -			if (data & RxBreak) -				flag = TTY_BREAK; -			else if (data & RxParityError) -				flag = TTY_PARITY; -			else if (data & RxFramingError) -				flag = TTY_FRAME; -		} - -		if (uart_handle_sysrq_char (port, (unsigned char) data)) -			continue; - -		uart_insert_char(port, data, RxOverrunError, data, flag); -	} -	tty_flip_buffer_push (tty); -	return; -} - -static void lh7a40xuart_tx_chars (struct uart_port* port) -{ -	struct circ_buf* xmit = &port->state->xmit; -	int cbTxMax = port->fifosize; - -	if (port->x_char) { -		UR (port, UART_R_DATA) = port->x_char; -		++port->icount.tx; -		port->x_char = 0; -		return; -	} -	if (uart_circ_empty (xmit) || uart_tx_stopped (port)) { -		lh7a40xuart_stop_tx (port); -		return; -	} - -	/* Unlike the AMBA UART, the lh7a40x UART does not guarantee -	   that at least half of the FIFO is empty.  Instead, we check -	   status for every character.  Using the AMBA method causes -	   the transmitter to drop characters. */ - -	do { -		UR (port, UART_R_DATA) = xmit->buf[xmit->tail]; -		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); -		++port->icount.tx; -		if (uart_circ_empty(xmit)) -			break; -	} while (!(UR (port, UART_R_STATUS) & nTxRdy) -		 && cbTxMax--); - -	if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS) -		uart_write_wakeup (port); - -	if (uart_circ_empty (xmit)) -		lh7a40xuart_stop_tx (port); -} - -static void lh7a40xuart_modem_status (struct uart_port* port) -{ -	unsigned int status = UR (port, UART_R_STATUS); -	unsigned int delta -		= status ^ ((struct uart_port_lh7a40x*) port)->statusPrev; - -	BIT_SET (port, UART_R_RAWISR, MSEOI); /* Clear modem status intr */ - -	if (!delta)		/* Only happens if we missed 2 transitions */ -		return; - -	((struct uart_port_lh7a40x*) port)->statusPrev = status; - -	if (delta & DCD) -		uart_handle_dcd_change (port, status & DCD); - -	if (delta & DSR) -		++port->icount.dsr; - -	if (delta & CTS) -		uart_handle_cts_change (port, status & CTS); - -	wake_up_interruptible (&port->state->port.delta_msr_wait); -} - -static irqreturn_t lh7a40xuart_int (int irq, void* dev_id) -{ -	struct uart_port* port = dev_id; -	unsigned int cLoopLimit = ISR_LOOP_LIMIT; -	unsigned int isr = UR (port, UART_R_ISR); - - -	do { -		if (isr & (RxInt | RxTimeoutInt)) -			lh7a40xuart_rx_chars(port); -		if (isr & ModemInt) -			lh7a40xuart_modem_status (port); -		if (isr & TxInt) -			lh7a40xuart_tx_chars (port); - -		if (--cLoopLimit == 0) -			break; - -		isr = UR (port, UART_R_ISR); -	} while (isr & (RxInt | TxInt | RxTimeoutInt)); - -	return IRQ_HANDLED; -} - -static unsigned int lh7a40xuart_tx_empty (struct uart_port* port) -{ -	return (UR (port, UART_R_STATUS) & TxEmpty) ? TIOCSER_TEMT : 0; -} - -static unsigned int lh7a40xuart_get_mctrl (struct uart_port* port) -{ -	unsigned int result = 0; -	unsigned int status = UR (port, UART_R_STATUS); - -	if (status & DCD) -		result |= TIOCM_CAR; -	if (status & DSR) -		result |= TIOCM_DSR; -	if (status & CTS) -		result |= TIOCM_CTS; - -	return result; -} - -static void lh7a40xuart_set_mctrl (struct uart_port* port, unsigned int mctrl) -{ -	/* None of the ports supports DTR. UART1 supports RTS through GPIO. */ -	/* Note, kernel appears to be setting DTR and RTS on console. */ - -	/* *** FIXME: this deserves more work.  There's some work in -	       tracing all of the IO pins. */ -#if 0 -	if( port->mapbase == UART1_PHYS) { -		gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); - -		if (mctrl & TIOCM_RTS) -			gpio->pbdr &= ~GPIOB_UART1_RTS; -		else -			gpio->pbdr |= GPIOB_UART1_RTS; -	} -#endif -} - -static void lh7a40xuart_break_ctl (struct uart_port* port, int break_state) -{ -	unsigned long flags; - -	spin_lock_irqsave(&port->lock, flags); -	if (break_state == -1) -		BIT_SET (port, UART_R_FCON, BRK); /* Assert break */ -	else -		BIT_CLR (port, UART_R_FCON, BRK); /* Deassert break */ -	spin_unlock_irqrestore(&port->lock, flags); -} - -static int lh7a40xuart_startup (struct uart_port* port) -{ -	int retval; - -	retval = request_irq (port->irq, lh7a40xuart_int, 0, -			      "serial_lh7a40x", port); -	if (retval) -		return retval; - -				/* Initial modem control-line settings */ -	((struct uart_port_lh7a40x*) port)->statusPrev -		= UR (port, UART_R_STATUS); - -	/* There is presently no configuration option to enable IR. -	   Thus, we always disable it. */ - -	BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); -	BIT_SET (port, UART_R_INTEN, RxTimeoutInt | RxInt); - -	return 0; -} - -static void lh7a40xuart_shutdown (struct uart_port* port) -{ -	free_irq (port->irq, port); -	BIT_CLR (port, UART_R_FCON, BRK | FEN); -	BIT_CLR (port, UART_R_CON, UARTEN); -} - -static void lh7a40xuart_set_termios (struct uart_port* port, -				     struct ktermios* termios, -				     struct ktermios* old) -{ -	unsigned int con; -	unsigned int inten; -	unsigned int fcon; -	unsigned long flags; -	unsigned int baud; -	unsigned int quot; - -	baud = uart_get_baud_rate (port, termios, old, 8, port->uartclk/16); -	quot = uart_get_divisor (port, baud); /* -1 performed elsewhere */ - -	switch (termios->c_cflag & CSIZE) { -	case CS5: -		fcon = WLEN_5; -		break; -	case CS6: -		fcon = WLEN_6; -		break; -	case CS7: -		fcon = WLEN_7; -		break; -	case CS8: -	default: -		fcon = WLEN_8; -		break; -	} -	if (termios->c_cflag & CSTOPB) -		fcon |= STP2; -	if (termios->c_cflag & PARENB) { -		fcon |= PEN; -		if (!(termios->c_cflag & PARODD)) -			fcon |= EPS; -	} -	if (port->fifosize > 1) -		fcon |= FEN; - -	spin_lock_irqsave (&port->lock, flags); - -	uart_update_timeout (port, termios->c_cflag, baud); - -	port->read_status_mask = RxOverrunError; -	if (termios->c_iflag & INPCK) -		port->read_status_mask |= RxFramingError | RxParityError; -	if (termios->c_iflag & (BRKINT | PARMRK)) -		port->read_status_mask |= RxBreak; - -		/* Figure mask for status we ignore */ -	port->ignore_status_mask = 0; -	if (termios->c_iflag & IGNPAR) -		port->ignore_status_mask |= RxFramingError | RxParityError; -	if (termios->c_iflag & IGNBRK) { -		port->ignore_status_mask |= RxBreak; -		/* Ignore overrun when ignorning parity */ -		/* *** FIXME: is this in the right place? */ -		if (termios->c_iflag & IGNPAR) -			port->ignore_status_mask |= RxOverrunError; -	} - -		/* Ignore all receive errors when receive disabled */ -	if ((termios->c_cflag & CREAD) == 0) -		port->ignore_status_mask |= RxError; - -	con   = UR (port, UART_R_CON); -	inten = (UR (port, UART_R_INTEN) & ~ModemInt); - -	if (UART_ENABLE_MS (port, termios->c_cflag)) -		inten |= ModemInt; - -	BIT_CLR (port, UART_R_CON, UARTEN);	/* Disable UART */ -	UR (port, UART_R_INTEN) = 0;		/* Disable interrupts */ -	UR (port, UART_R_BRCON) = quot - 1;	/* Set baud rate divisor */ -	UR (port, UART_R_FCON)  = fcon;		/* Set FIFO and frame ctrl */ -	UR (port, UART_R_INTEN) = inten;	/* Enable interrupts */ -	UR (port, UART_R_CON)   = con;		/* Restore UART mode */ - -	spin_unlock_irqrestore(&port->lock, flags); -} - -static const char* lh7a40xuart_type (struct uart_port* port) -{ -	return port->type == PORT_LH7A40X ? "LH7A40X" : NULL; -} - -static void lh7a40xuart_release_port (struct uart_port* port) -{ -	release_mem_region (port->mapbase, UART_REG_SIZE); -} - -static int lh7a40xuart_request_port (struct uart_port* port) -{ -	return request_mem_region (port->mapbase, UART_REG_SIZE, -				   "serial_lh7a40x") != NULL -		? 0 : -EBUSY; -} - -static void lh7a40xuart_config_port (struct uart_port* port, int flags) -{ -	if (flags & UART_CONFIG_TYPE) { -		port->type = PORT_LH7A40X; -		lh7a40xuart_request_port (port); -	} -} - -static int lh7a40xuart_verify_port (struct uart_port* port, -				    struct serial_struct* ser) -{ -	int ret = 0; - -	if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A40X) -		ret = -EINVAL; -	if (ser->irq < 0 || ser->irq >= nr_irqs) -		ret = -EINVAL; -	if (ser->baud_base < 9600) /* *** FIXME: is this true? */ -		ret = -EINVAL; -	return ret; -} - -static struct uart_ops lh7a40x_uart_ops = { -	.tx_empty	= lh7a40xuart_tx_empty, -	.set_mctrl	= lh7a40xuart_set_mctrl, -	.get_mctrl	= lh7a40xuart_get_mctrl, -	.stop_tx	= lh7a40xuart_stop_tx, -	.start_tx	= lh7a40xuart_start_tx, -	.stop_rx	= lh7a40xuart_stop_rx, -	.enable_ms	= lh7a40xuart_enable_ms, -	.break_ctl	= lh7a40xuart_break_ctl, -	.startup	= lh7a40xuart_startup, -	.shutdown	= lh7a40xuart_shutdown, -	.set_termios	= lh7a40xuart_set_termios, -	.type		= lh7a40xuart_type, -	.release_port	= lh7a40xuart_release_port, -	.request_port	= lh7a40xuart_request_port, -	.config_port	= lh7a40xuart_config_port, -	.verify_port	= lh7a40xuart_verify_port, -}; - -static struct uart_port_lh7a40x lh7a40x_ports[DEV_NR] = { -	{ -		.port = { -			.membase	= (void*) io_p2v (UART1_PHYS), -			.mapbase	= UART1_PHYS, -			.iotype		= UPIO_MEM, -			.irq		= IRQ_UART1INTR, -			.uartclk	= 14745600/2, -			.fifosize	= 16, -			.ops		= &lh7a40x_uart_ops, -			.flags		= UPF_BOOT_AUTOCONF, -			.line		= 0, -		}, -	}, -	{ -		.port = { -			.membase	= (void*) io_p2v (UART2_PHYS), -			.mapbase	= UART2_PHYS, -			.iotype		= UPIO_MEM, -			.irq		= IRQ_UART2INTR, -			.uartclk	= 14745600/2, -			.fifosize	= 16, -			.ops		= &lh7a40x_uart_ops, -			.flags		= UPF_BOOT_AUTOCONF, -			.line		= 1, -		}, -	}, -	{ -		.port = { -			.membase	= (void*) io_p2v (UART3_PHYS), -			.mapbase	= UART3_PHYS, -			.iotype		= UPIO_MEM, -			.irq		= IRQ_UART3INTR, -			.uartclk	= 14745600/2, -			.fifosize	= 16, -			.ops		= &lh7a40x_uart_ops, -			.flags		= UPF_BOOT_AUTOCONF, -			.line		= 2, -		}, -	}, -}; - -#ifndef CONFIG_SERIAL_LH7A40X_CONSOLE -# define LH7A40X_CONSOLE NULL -#else -# define LH7A40X_CONSOLE &lh7a40x_console - -static void lh7a40xuart_console_putchar(struct uart_port *port, int ch) -{ -	while (UR(port, UART_R_STATUS) & nTxRdy) -		; -	UR(port, UART_R_DATA) = ch; -} - -static void lh7a40xuart_console_write (struct console* co, -				       const char* s, -				       unsigned int count) -{ -	struct uart_port* port = &lh7a40x_ports[co->index].port; -	unsigned int con = UR (port, UART_R_CON); -	unsigned int inten = UR (port, UART_R_INTEN); - - -	UR (port, UART_R_INTEN) = 0;		/* Disable all interrupts */ -	BIT_SET (port, UART_R_CON, UARTEN | SIRDIS); /* Enable UART */ - -	uart_console_write(port, s, count, lh7a40xuart_console_putchar); - -				/* Wait until all characters are sent */ -	while (UR (port, UART_R_STATUS) & TxBusy) -		; - -				/* Restore control and interrupt mask */ -	UR (port, UART_R_CON) = con; -	UR (port, UART_R_INTEN) = inten; -} - -static void __init lh7a40xuart_console_get_options (struct uart_port* port, -						    int* baud, -						    int* parity, -						    int* bits) -{ -	if (UR (port, UART_R_CON) & UARTEN) { -		unsigned int fcon = UR (port, UART_R_FCON); -		unsigned int quot = UR (port, UART_R_BRCON) + 1; - -		switch (fcon & (PEN | EPS)) { -		default:        *parity = 'n'; break; -		case PEN:       *parity = 'o'; break; -		case PEN | EPS: *parity = 'e'; break; -		} - -		switch (fcon & WLEN) { -		default: -		case WLEN_8: *bits = 8; break; -		case WLEN_7: *bits = 7; break; -		case WLEN_6: *bits = 6; break; -		case WLEN_5: *bits = 5; break; -		} - -		*baud = port->uartclk/(16*quot); -	} -} - -static int __init lh7a40xuart_console_setup (struct console* co, char* options) -{ -	struct uart_port* port; -	int baud = 38400; -	int bits = 8; -	int parity = 'n'; -	int flow = 'n'; - -	if (co->index >= DEV_NR) /* Bounds check on device number */ -		co->index = 0; -	port = &lh7a40x_ports[co->index].port; - -	if (options) -		uart_parse_options (options, &baud, &parity, &bits, &flow); -	else -		lh7a40xuart_console_get_options (port, &baud, &parity, &bits); - -	return uart_set_options (port, co, baud, parity, bits, flow); -} - -static struct uart_driver lh7a40x_reg; -static struct console lh7a40x_console = { -	.name		= "ttyAM", -	.write		= lh7a40xuart_console_write, -	.device		= uart_console_device, -	.setup		= lh7a40xuart_console_setup, -	.flags		= CON_PRINTBUFFER, -	.index		= -1, -	.data		= &lh7a40x_reg, -}; - -static int __init lh7a40xuart_console_init(void) -{ -	register_console (&lh7a40x_console); -	return 0; -} - -console_initcall (lh7a40xuart_console_init); - -#endif - -static struct uart_driver lh7a40x_reg = { -	.owner			= THIS_MODULE, -	.driver_name		= "ttyAM", -	.dev_name		= "ttyAM", -	.major			= DEV_MAJOR, -	.minor			= DEV_MINOR, -	.nr			= DEV_NR, -	.cons			= LH7A40X_CONSOLE, -}; - -static int __init lh7a40xuart_init(void) -{ -	int ret; - -	printk (KERN_INFO "serial: LH7A40X serial driver\n"); - -	ret = uart_register_driver (&lh7a40x_reg); - -	if (ret == 0) { -		int i; - -		for (i = 0; i < DEV_NR; i++) { -			/* UART3, when used, requires GPIO pin reallocation */ -			if (lh7a40x_ports[i].port.mapbase == UART3_PHYS) -				GPIO_PINMUX |= 1<<3; -			uart_add_one_port (&lh7a40x_reg, -					   &lh7a40x_ports[i].port); -		} -	} -	return ret; -} - -static void __exit lh7a40xuart_exit(void) -{ -	int i; - -	for (i = 0; i < DEV_NR; i++) -		uart_remove_one_port (&lh7a40x_reg, &lh7a40x_ports[i].port); - -	uart_unregister_driver (&lh7a40x_reg); -} - -module_init (lh7a40xuart_init); -module_exit (lh7a40xuart_exit); - -MODULE_AUTHOR ("Marc Singer"); -MODULE_DESCRIPTION ("Sharp LH7A40X serial port driver"); -MODULE_LICENSE ("GPL");  | 
