From 5c37079957c5e5555aa8284a879f8cc44fa8eb25 Mon Sep 17 00:00:00 2001 From: Alison Wang Date: Thu, 4 Aug 2011 09:59:39 +0800 Subject: [PATCH 05/52] Add serial driver and irda driver support for MCF5445x and MCF547x/MCF548x Add common serial driver for MCF5445x and MCF547x/MCF548x. Also add irda support for MCF547x/MCF548x. Signed-off-by: Alison Wang --- drivers/tty/serial/Kconfig | 20 ++++++++++ drivers/tty/serial/mcf.c | 87 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 0 deletions(-) --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1027,6 +1027,26 @@ config SERIAL_68328_RTS_CTS bool "Support RTS/CTS on 68328 serial port" depends on SERIAL_68328 +config SERIAL_COLDFIRE_IRDA + bool "ColdFire IRDA support" + depends on SERIAL_MCF + help + This driver supports IrDA on the ColdFire platform, + such as MCF547x and MCF548x. + + Say Y here if you want to use IrDA 1.1 SIR mode. + +config SERIAL_COLDFIRE_EDMA + bool "ColdFire serial EDMA support" + depends on SERIAL_MCF + default n + help + Enables Enhanced Direct Memory Access(eDMA) in the Coldfire + serial driver. + + Say Y here if you want to use DMA processing of transmit + and receive data for the serial driver. + config SERIAL_MCF bool "Coldfire serial support" depends on COLDFIRE --- a/drivers/tty/serial/mcf.c +++ b/drivers/tty/serial/mcf.c @@ -4,6 +4,10 @@ * mcf.c -- Freescale ColdFire UART driver * * (C) Copyright 2003-2007, Greg Ungerer + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Jason Jin Jason.Jin@freescale.com + * Shrek Wu B16972@freescale.com + * Chengju Cai b22600@freescale.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 @@ -23,9 +27,11 @@ #include #include #include +#include #include #include #include +#include #include /****************************************************************************/ @@ -46,6 +52,10 @@ #define mcf_setppdtr(p, v) do { } while (0) #endif +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA +#define SERIAL_IRDA_LINE (2) +#endif + /****************************************************************************/ /* @@ -101,6 +111,15 @@ static void mcf_start_tx(struct uart_por { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (port->line == SERIAL_IRDA_LINE) { + /* Disable IRDA receiver*/ + writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); + writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); + + writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR); + } +#endif pp->imr |= MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); } @@ -154,6 +173,30 @@ static int mcf_startup(struct uart_port spin_lock_irqsave(&port->lock, flags); +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (port->line == SERIAL_IRDA_LINE) { + /* Put PSC in IrDA mode */ + MCF_PSC_SICR(port->line) = MCF_PSC_SICR_SIM_SIR; + + /* Set pulse width to 1.6 uS */ + MCF_PSC_IRSDR(port->line) = (uint8_t) + (16 * (CONFIG_MCFCLK / 10000000)); + MCF_PSC_IRCR1(port->line) = MCF_PSC_IRCR1_SPUL; + MCF_PSC_IRCR2(port->line) = 0; + + /* Enable RTS to send */ + MCF_PSC_OPSET(port->line) = MCF_PSC_OPSET_RTS; + + /* Setup FIFO Alarms */ + MCF_PSC_RFAR(port->line) = MCF_PSC_RFAR_ALARM(248); + MCF_PSC_TFAR(port->line) = MCF_PSC_TFAR_ALARM(248); + + MCF_PSC_RFCR(port->line) = MCF_PSC_RFCR_FRMEN + | MCF_PSC_RFCR_GR(4); + MCF_PSC_TFCR(port->line) = MCF_PSC_TFCR_FRMEN + | MCF_PSC_RFCR_GR(4); + } +#endif /* Reset UART, get it into known state... */ writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR); writeb(MCFUART_UCR_CMDRESETTX, port->membase + MCFUART_UCR); @@ -177,7 +220,17 @@ static void mcf_shutdown(struct uart_por { struct mcf_uart *pp = container_of(port, struct mcf_uart, port); unsigned long flags; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + unsigned long delay_counter = 0; +#endif +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + while (!((readb(port->membase + MCFUART_USR)) & MCFUART_USR_TXEMPTY)) { + if (delay_counter++ > 25000) + break; + udelay(10); + } +#endif spin_lock_irqsave(&port->lock, flags); /* Disable all interrupts now */ @@ -202,7 +255,14 @@ static void mcf_set_termios(struct uart_ unsigned int baudfr; #endif unsigned char mr1, mr2; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + int i = 0; /* hush GCC */ +#endif +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + while (i++ < 35000) + udelay(1); +#endif baud = uart_get_baud_rate(port, termios, old, 0, 230400); #if defined(CONFIG_M5272) baudclk = (MCF_BUSCLK / baud) / 32; @@ -331,6 +391,23 @@ static void mcf_tx_chars(struct mcf_uart while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) { if (xmit->head == xmit->tail) break; +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (port->line == SERIAL_IRDA_LINE) { + while (!((readb(port->membase + MCFUART_USR))\ + & MCFUART_USR_TXEMPTY)) + ; + /* delay for settle */ +#if defined(CONFIG_M548X) + udelay(1); +#elif defined(CONFIG_M547X) + udelay(2); +#else + int i = 0; + while (i++ < 25000) + udelay(1); +#endif + } +#endif writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); port->icount.tx++; @@ -340,6 +417,16 @@ static void mcf_tx_chars(struct mcf_uart uart_write_wakeup(port); if (xmit->head == xmit->tail) { +#ifdef CONFIG_SERIAL_COLDFIRE_IRDA + if (port->line == SERIAL_IRDA_LINE) { + /* Enable receiver for IRDA */ + writeb(MCFUART_UCR_CMDRESETRX,\ + port->membase + MCFUART_UCR); + /* reset RX */ + writeb(MCFUART_UCR_TXENABLE | MCFUART_UCR_RXENABLE,\ + port->membase + MCFUART_UCR); + } +#endif pp->imr &= ~MCFUART_UIR_TXREADY; writeb(pp->imr, port->membase + MCFUART_UIMR); }