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