📄 mcf.c
字号:
/****************************************************************************//* * mcf.c -- Freescale ColdFire UART driver * * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//****************************************************************************/#include <linux/kernel.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/module.h>#include <linux/console.h>#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial.h>#include <linux/serial_core.h>#include <linux/io.h>#include <asm/coldfire.h>#include <asm/mcfsim.h>#include <asm/mcfuart.h>#include <asm/nettel.h>/****************************************************************************//* * Some boards implement the DTR/DCD lines using GPIO lines, most * don't. Dummy out the access macros for those that don't. Those * that do should define these macros somewhere in there board * specific inlude files. */#if !defined(mcf_getppdcd)#define mcf_getppdcd(p) (1)#endif#if !defined(mcf_getppdtr)#define mcf_getppdtr(p) (1)#endif#if !defined(mcf_setppdtr)#define mcf_setppdtr(p, v) do { } while (0)#endif/****************************************************************************//* * Local per-uart structure. */struct mcf_uart { struct uart_port port; unsigned int sigs; /* Local copy of line sigs */ unsigned char imr; /* Local IMR mirror */};/****************************************************************************/static unsigned int mcf_tx_empty(struct uart_port *port){ return (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;}/****************************************************************************/static unsigned int mcf_get_mctrl(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; unsigned int sigs; spin_lock_irqsave(&port->lock, flags); sigs = (readb(port->membase + MCFUART_UIPR) & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; sigs |= (pp->sigs & TIOCM_RTS); sigs |= (mcf_getppdcd(port->line) ? TIOCM_CD : 0); sigs |= (mcf_getppdtr(port->line) ? TIOCM_DTR : 0); spin_unlock_irqrestore(&port->lock, flags); return sigs;}/****************************************************************************/static void mcf_set_mctrl(struct uart_port *port, unsigned int sigs){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); pp->sigs = sigs; mcf_setppdtr(port->line, (sigs & TIOCM_DTR)); if (sigs & TIOCM_RTS) writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1); else writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP0); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_start_tx(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); pp->imr |= MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_stop_tx(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); pp->imr &= ~MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_stop_rx(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); pp->imr &= ~MCFUART_UIR_RXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_break_ctl(struct uart_port *port, int break_state){ unsigned long flags; spin_lock_irqsave(&port->lock, flags); if (break_state == -1) writeb(MCFUART_UCR_CMDBREAKSTART, port->membase + MCFUART_UCR); else writeb(MCFUART_UCR_CMDBREAKSTOP, port->membase + MCFUART_UCR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_enable_ms(struct uart_port *port){}/****************************************************************************/static int mcf_startup(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); /* Reset UART, get it into known state... */ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); /* Enable the UART transmitter and receiver */ writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); /* Enable RX interrupts now */ pp->imr = MCFUART_UIR_RXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); spin_unlock_irqrestore(&port->lock, flags); return 0;}/****************************************************************************/static void mcf_shutdown(struct uart_port *port){ struct mcf_uart *pp = (struct mcf_uart *) port; unsigned long flags; spin_lock_irqsave(&port->lock, flags); /* Disable all interrupts now */ pp->imr = 0; writeb(pp->imr, port->membase + MCFUART_UIMR); /* Disable UART transmitter and receiver */ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old){ unsigned long flags; unsigned int baud, baudclk; unsigned char mr1, mr2; baud = uart_get_baud_rate(port, termios, old, 0, 230400); baudclk = ((MCF_BUSCLK / baud) + 16) / 32; mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; mr2 = 0; switch (termios->c_cflag & CSIZE) { case CS5: mr1 |= MCFUART_MR1_CS5; break; case CS6: mr1 |= MCFUART_MR1_CS6; break; case CS7: mr1 |= MCFUART_MR1_CS7; break; case CS8: default: mr1 |= MCFUART_MR1_CS8; break; } if (termios->c_cflag & PARENB) { if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) mr1 |= MCFUART_MR1_PARITYMARK; else mr1 |= MCFUART_MR1_PARITYSPACE; } else { if (termios->c_cflag & PARODD) mr1 |= MCFUART_MR1_PARITYODD; else mr1 |= MCFUART_MR1_PARITYEVEN; } } else { mr1 |= MCFUART_MR1_PARITYNONE; } if (termios->c_cflag & CSTOPB) mr2 |= MCFUART_MR2_STOP2; else mr2 |= MCFUART_MR2_STOP1; if (termios->c_cflag & CRTSCTS) { mr1 |= MCFUART_MR1_RXRTS; mr2 |= MCFUART_MR2_TXCTS; } spin_lock_irqsave(&port->lock, flags); writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETMRPTR, port->membase + MCFUART_UCR); writeb(mr1, port->membase + MCFUART_UMR); writeb(mr2, port->membase + MCFUART_UMR); writeb((baudclk & 0xff00) >> 8, port->membase + MCFUART_UBG1); writeb((baudclk & 0xff), port->membase + MCFUART_UBG2); writeb(MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER, port->membase + MCFUART_UCSR); writeb(MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); spin_unlock_irqrestore(&port->lock, flags);}/****************************************************************************/static void mcf_rx_chars(struct mcf_uart *pp){ struct uart_port *port = (struct uart_port *) pp; unsigned char status, ch, flag; while ((status = readb(port->membase + MCFUART_USR)) & MCFUART_USR_RXREADY) { ch = readb(port->membase + MCFUART_URB); flag = TTY_NORMAL; port->icount.rx++; if (status & MCFUART_USR_RXERR) { writeb(MCFUART_UCR_CMDRESETERR, port->membase + MCFUART_UCR); if (status & MCFUART_USR_RXBREAK) { port->icount.brk++; if (uart_handle_break(port)) continue; } else if (status & MCFUART_USR_RXPARITY) { port->icount.parity++; } else if (status & MCFUART_USR_RXOVERRUN) { port->icount.overrun++; } else if (status & MCFUART_USR_RXFRAMING) { port->icount.frame++; } status &= port->read_status_mask; if (status & MCFUART_USR_RXBREAK) flag = TTY_BREAK; else if (status & MCFUART_USR_RXPARITY) flag = TTY_PARITY; else if (status & MCFUART_USR_RXFRAMING) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch)) continue; uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag); } tty_flip_buffer_push(port->info->tty);}/****************************************************************************/static void mcf_tx_chars(struct mcf_uart *pp){ struct uart_port *port = (struct uart_port *) pp; struct circ_buf *xmit = &port->info->xmit; if (port->x_char) { /* Send special char - probably flow control */ writeb(port->x_char, port->membase + MCFUART_UTB);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -