⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpc52xx_uart.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * drivers/serial/mpc52xx_uart.c * * Driver for the PSC of the Freescale MPC52xx PSCs configured as UARTs. * * FIXME According to the usermanual the status bits in the status register * are only updated when the peripherals access the FIFO and not when the * CPU access them. So since we use this bits to know when we stop writing * and reading, they may not be updated in-time and a race condition may * exists. But I haven't be able to prove this and I don't care. But if * any problem arises, it might worth checking. The TX/RX FIFO Stats * registers should be used in addition. * Update: Actually, they seem updated ... At least the bits we use. * * * Maintainer : Sylvain Munaut <tnt@246tNt.com> *  * Some of the code has been inspired/copied from the 2.4 code written * by Dale Farnsworth <dfarnsworth@mvista.com>. *  * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> * Copyright (C) 2003 MontaVista, Software, Inc. *  * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ /* OCP Usage : * * This drivers uses the OCP model. To load the serial driver for one of the * PSCs, just add this to the core_ocp table : * * { * 	.vendor         = OCP_VENDOR_FREESCALE, * 	.function       = OCP_FUNC_PSC_UART, * 	.index          = 0, * 	.paddr          = MPC52xx_PSC1, * 	.irq            = MPC52xx_PSC1_IRQ, * 	.pm             = OCP_CPM_NA, * }, * * This is for PSC1, replace the paddr and irq according to the PSC you want to * use. The driver all necessary registers to place the PSC in uart mode without * DCD. However, the pin multiplexing aren't changed and should be set either * by the bootloader or in the platform init code. * The index field must be equal to the PSC index ( e.g. 0 for PSC1, 1 for PSC2, * and so on). So the PSC1 is mapped to /dev/ttyS0, PSC2 to /dev/ttyS1 and so * on. But be warned, it's an ABSOLUTE REQUIREMENT ! This is needed mainly for * the console code : without this 1:1 mapping, at early boot time, when we are * parsing the kernel args console=ttyS?, we wouldn't know wich PSC it will be * mapped to because OCP stuff is not yet initialized. */#include <linux/config.h>#include <linux/module.h>#include <linux/tty.h>#include <linux/serial.h>#include <linux/sysrq.h>#include <linux/console.h>#include <asm/delay.h>#include <asm/io.h>#include <asm/ocp.h>#include <asm/mpc52xx.h>#include <asm/mpc52xx_psc.h>#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)#define SUPPORT_SYSRQ#endif#include <linux/serial_core.h>#define ISR_PASS_LIMIT 256	/* Max number of iteration in the interrupt */static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];	/* Rem: - We use the read_status_mask as a shadow of	 *        psc->mpc52xx_psc_imr	 *      - It's important that is array is all zero on start as we	 *        use it to know if it's initialized or not ! If it's not sure	 *        it's cleared, then a memset(...,0,...) should be added to	 *        the console_init	 */#define PSC(port) ((struct mpc52xx_psc *)((port)->membase))/* Forward declaration of the interruption handling routine */static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs);/* Simple macro to test if a port is console or not. This one is taken * for serial_core.c and maybe should be moved to serial_core.h ? */#ifdef CONFIG_SERIAL_CORE_CONSOLE#define uart_console(port)	((port)->cons && (port)->cons->index == (port)->line)#else#define uart_console(port)	(0)#endif/* ======================================================================== *//* UART operations                                                          *//* ======================================================================== */static unsigned int mpc52xx_uart_tx_empty(struct uart_port *port){	int status = in_be16(&PSC(port)->mpc52xx_psc_status);	return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;}static void mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl){	/* Not implemented */}static unsigned int mpc52xx_uart_get_mctrl(struct uart_port *port){	/* Not implemented */	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;}static void mpc52xx_uart_stop_tx(struct uart_port *port, unsigned int tty_stop){	/* port->lock taken by caller */	port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);}static void mpc52xx_uart_start_tx(struct uart_port *port, unsigned int tty_start){	/* port->lock taken by caller */	port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);}static void mpc52xx_uart_send_xchar(struct uart_port *port, char ch){	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);		port->x_char = ch;	if (ch) {		/* Make sure tx interrupts are on */		/* Truly necessary ??? They should be anyway */		port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;		out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);	}		spin_unlock_irqrestore(&port->lock, flags);}static voidmpc52xx_uart_stop_rx(struct uart_port *port){	/* port->lock taken by caller */	port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;	out_be16(&PSC(port)->mpc52xx_psc_imr,port->read_status_mask);}static voidmpc52xx_uart_enable_ms(struct uart_port *port){	/* Not implemented */}static voidmpc52xx_uart_break_ctl(struct uart_port *port, int ctl){	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);	if ( ctl == -1 )		out_8(&PSC(port)->command,MPC52xx_PSC_START_BRK);	else		out_8(&PSC(port)->command,MPC52xx_PSC_STOP_BRK);		spin_unlock_irqrestore(&port->lock, flags);}static intmpc52xx_uart_startup(struct uart_port *port){	struct mpc52xx_psc *psc = PSC(port);	/* Reset/activate the port, clear and enable interrupts */	out_8(&psc->command,MPC52xx_PSC_RST_RX);	out_8(&psc->command,MPC52xx_PSC_RST_TX);		out_be32(&psc->sicr,0);	/* UART mode DCD ignored */	out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */		out_8(&psc->rfcntl, 0x00);	out_be16(&psc->rfalarm, 0x1ff);	out_8(&psc->tfcntl, 0x07);	out_be16(&psc->tfalarm, 0x80);	port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);		out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);	out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);			return 0;}static voidmpc52xx_uart_shutdown(struct uart_port *port){	struct mpc52xx_psc *psc = PSC(port);		/* Shut down the port, interrupt and all */	out_8(&psc->command,MPC52xx_PSC_RST_RX);	out_8(&psc->command,MPC52xx_PSC_RST_TX);		port->read_status_mask = 0; 	out_be16(&psc->mpc52xx_psc_imr,port->read_status_mask);}static void mpc52xx_uart_set_termios(struct uart_port *port, struct termios *new,                         struct termios *old){	struct mpc52xx_psc *psc = PSC(port);	unsigned long flags;	unsigned char mr1, mr2;	unsigned short ctr;	unsigned int j, baud, quot;		/* Prepare what we're gonna write */	mr1 = 0;		switch (new->c_cflag & CSIZE) {		case CS5:	mr1 |= MPC52xx_PSC_MODE_5_BITS;				break;		case CS6:	mr1 |= MPC52xx_PSC_MODE_6_BITS;				break;		case CS7:	mr1 |= MPC52xx_PSC_MODE_7_BITS;				break;		case CS8:		default:	mr1 |= MPC52xx_PSC_MODE_8_BITS;	}	if (new->c_cflag & PARENB) {		mr1 |= (new->c_cflag & PARODD) ?			MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;	} else		mr1 |= MPC52xx_PSC_MODE_PARNONE;			mr2 = 0;	if (new->c_cflag & CSTOPB)		mr2 |= MPC52xx_PSC_MODE_TWO_STOP;	else		mr2 |= ((new->c_cflag & CSIZE) == CS5) ?			MPC52xx_PSC_MODE_ONE_STOP_5_BITS :			MPC52xx_PSC_MODE_ONE_STOP;	baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);	quot = uart_get_divisor(port, baud);	ctr = quot & 0xffff;		/* Get the lock */	spin_lock_irqsave(&port->lock, flags);	/* Update the per-port timeout */	uart_update_timeout(port, new->c_cflag, baud);	/* Do our best to flush TX & RX, so we don't loose anything */	/* But we don't wait indefinitly ! */	j = 5000000;	/* Maximum wait */	/* FIXME Can't receive chars since set_termios might be called at early	 * boot for the console, all stuff is not yet ready to receive at that	 * time and that just makes the kernel oops */	/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */	while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) && 	       --j)		udelay(1);	if (!j)		printk(	KERN_ERR "mpc52xx_uart.c: "			"Unable to flush RX & TX fifos in-time in set_termios."			"Some chars may have been lost.\n" ); 	/* Reset the TX & RX */	out_8(&psc->command,MPC52xx_PSC_RST_RX);	out_8(&psc->command,MPC52xx_PSC_RST_TX);	/* Send new mode settings */	out_8(&psc->command,MPC52xx_PSC_SEL_MODE_REG_1);	out_8(&psc->mode,mr1);	out_8(&psc->mode,mr2);	out_8(&psc->ctur,ctr >> 8);	out_8(&psc->ctlr,ctr & 0xff);		/* Reenable TX & RX */	out_8(&psc->command,MPC52xx_PSC_TX_ENABLE);	out_8(&psc->command,MPC52xx_PSC_RX_ENABLE);	/* We're all set, release the lock */	spin_unlock_irqrestore(&port->lock, flags);}static const char *mpc52xx_uart_type(struct uart_port *port){	return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;}static voidmpc52xx_uart_release_port(struct uart_port *port){	if (port->flags & UPF_IOREMAP) { /* remapped by us ? */		iounmap(port->membase);		port->membase = NULL;	}}static intmpc52xx_uart_request_port(struct uart_port *port){	if (port->flags & UPF_IOREMAP) /* Need to remap ? */		port->membase = ioremap(port->mapbase, sizeof(struct mpc52xx_psc));		return port->membase != NULL ? 0 : -EBUSY;}static voidmpc52xx_uart_config_port(struct uart_port *port, int flags){	if ( (flags & UART_CONFIG_TYPE) &&	     (mpc52xx_uart_request_port(port) == 0) )	     	port->type = PORT_MPC52xx;}static intmpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser){	if ( ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx )		return -EINVAL;	if ( (ser->irq != port->irq) ||	     (ser->io_type != SERIAL_IO_MEM) ||	     (ser->baud_base != port->uartclk)  || 	     // FIXME Should check addresses/irq as well ?	     (ser->hub6 != 0 ) )		return -EINVAL;	return 0;}static struct uart_ops mpc52xx_uart_ops = {	.tx_empty	= mpc52xx_uart_tx_empty,	.set_mctrl	= mpc52xx_uart_set_mctrl,	.get_mctrl	= mpc52xx_uart_get_mctrl,	.stop_tx	= mpc52xx_uart_stop_tx,	.start_tx	= mpc52xx_uart_start_tx,	.send_xchar	= mpc52xx_uart_send_xchar,	.stop_rx	= mpc52xx_uart_stop_rx,	.enable_ms	= mpc52xx_uart_enable_ms,	.break_ctl	= mpc52xx_uart_break_ctl,	.startup	= mpc52xx_uart_startup,	.shutdown	= mpc52xx_uart_shutdown,	.set_termios	= mpc52xx_uart_set_termios,/*	.pm		= mpc52xx_uart_pm,		Not supported yet *//*	.set_wake	= mpc52xx_uart_set_wake,	Not supported yet */	.type		= mpc52xx_uart_type,	.release_port	= mpc52xx_uart_release_port,	.request_port	= mpc52xx_uart_request_port,	.config_port	= mpc52xx_uart_config_port,	.verify_port	= mpc52xx_uart_verify_port};	/* ======================================================================== *//* Interrupt handling                                                       *//* ======================================================================== */	static inline intmpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs){	struct tty_struct *tty = port->info->tty;	unsigned char ch;	unsigned short status;	/* While we can read, do so ! */	while ( (status = in_be16(&PSC(port)->mpc52xx_psc_status)) &	        MPC52xx_PSC_SR_RXRDY) {		/* If we are full, just stop reading */		if (tty->flip.count >= TTY_FLIPBUF_SIZE)			break;				/* Get the char */		ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);		/* Handle sysreq char */#ifdef SUPPORT_SYSRQ		if (uart_handle_sysrq_char(port, ch, regs)) {			port->sysrq = 0;			continue;		}#endif		/* Store it */		*tty->flip.char_buf_ptr = ch;		*tty->flip.flag_buf_ptr = 0;		port->icount.rx++;			if ( status & (MPC52xx_PSC_SR_PE |		               MPC52xx_PSC_SR_FE |		               MPC52xx_PSC_SR_RB |		               MPC52xx_PSC_SR_OE) ) {						if (status & MPC52xx_PSC_SR_RB) {				*tty->flip.flag_buf_ptr = TTY_BREAK;				uart_handle_break(port);			} else if (status & MPC52xx_PSC_SR_PE)				*tty->flip.flag_buf_ptr = TTY_PARITY;			else if (status & MPC52xx_PSC_SR_FE)				*tty->flip.flag_buf_ptr = TTY_FRAME;			if (status & MPC52xx_PSC_SR_OE) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -