201 lines
6.0 KiB
Diff
201 lines
6.0 KiB
Diff
|
From 5c37079957c5e5555aa8284a879f8cc44fa8eb25 Mon Sep 17 00:00:00 2001
|
||
|
From: Alison Wang <b18965@freescale.com>
|
||
|
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 <b18965@freescale.com>
|
||
|
---
|
||
|
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 <gerg@snapgear.com>
|
||
|
+ * 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 <linux/serial.h>
|
||
|
#include <linux/serial_core.h>
|
||
|
#include <linux/io.h>
|
||
|
+#include <linux/delay.h>
|
||
|
#include <asm/coldfire.h>
|
||
|
#include <asm/mcfsim.h>
|
||
|
#include <asm/mcfuart.h>
|
||
|
+#include <asm/m5485psc.h>
|
||
|
#include <asm/nettel.h>
|
||
|
|
||
|
/****************************************************************************/
|
||
|
@@ -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);
|
||
|
}
|