From nobody Mon Sep 17 00:00:00 2001
From: Håvard Skinnemoen <hskinnemoen@atmel.com>
Date: Fri Nov 18 16:31:34 2005 +0100
Subject: [PATCH] AVR32: USART3 Serial Driver
---
drivers/serial/Kconfig | 21
drivers/serial/Makefile | 1
drivers/serial/atmel_usart.c | 1086 +++++++++++++++++++++++++++++++++++++++++++
drivers/serial/atmel_usart.h | 290 +++++++++++
4 files changed, 1398 insertions(+)
Index: linux-2.6.18-avr32/drivers/serial/Kconfig
===================================================================
--- linux-2.6.18-avr32.orig/drivers/serial/Kconfig 2006-11-02 14:16:07.000000000 +0100
+++ linux-2.6.18-avr32/drivers/serial/Kconfig 2006-11-02 15:54:18.000000000 +0100
@@ -246,6 +246,27 @@ config SERIAL_8250_AU1X00
comment "Non-8250 serial port support"
+config SERIAL_ATMEL
+ tristate "Atmel USART3 serial port support"
+ depends on AVR32
+ select SERIAL_CORE
+ default y
+ help
+ Support for the Atmel USART3 on-chip USART found in most
+ AT32 and AT91 parts from Atmel.
+
+ If unsure, say Y.
+
+config SERIAL_ATMEL_CONSOLE
+ bool "Support for console on Atmel USART3 serial port"
+ depends on SERIAL_ATMEL=y
+ select SERIAL_CORE_CONSOLE
+ help
+ Say Y here if you wish to use an Atmel USART3 serial port as
+ the system console (the system console is the device which
+ receives all kernel messages and warnings and which allows
+ logins in single user mode).
+
config SERIAL_AMBA_PL010
tristate "ARM AMBA PL010 serial port support"
depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
Index: linux-2.6.18-avr32/drivers/serial/Makefile
===================================================================
--- linux-2.6.18-avr32.orig/drivers/serial/Makefile 2006-11-02 14:16:07.000000000 +0100
+++ linux-2.6.18-avr32/drivers/serial/Makefile 2006-11-02 14:17:29.000000000 +0100
@@ -20,6 +20,7 @@ obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_b
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_AU1X00) += 8250_au1x00.o
+obj-$(CONFIG_SERIAL_ATMEL) += atmel_usart.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
Index: linux-2.6.18-avr32/drivers/serial/atmel_usart.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.18-avr32/drivers/serial/atmel_usart.c 2006-11-02 15:54:18.000000000 +0100
@@ -0,0 +1,1086 @@
+/*
+ * Driver for Atmel USART3 Serial ports
+ *
+ * Based on AT91RM9200 serial driver by Rick Bronson
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ * Based on drivers/serial/sa1100.c by Deep Blue Solutions Ltd.
+ *
+ * Copyright (C) 2004-2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/board.h>
+
+#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#include <linux/sysrq.h>
+#endif
+
+#include <linux/serial_core.h>
+
+#include "atmel_usart.h"
+
+/*
+ * TODO: Move this definition into linux/serial_core.h
+ */
+#define PORT_USART3 60
+
+/*
+ * Use the same major/minor numbers as the AT91 USART, which is
+ * actually the same chip
+ */
+#define SERIAL_USART3_MAJOR TTY_MAJOR
+#define MINOR_START 64
+#define NR_PORTS 4
+
+#define ERROR_FLAGS (USART3_BIT(CSR_PARE) \
+ | USART3_BIT(CSR_FRAME) \
+ | USART3_BIT(CSR_OVRE))
+
+/* Must be a power of two, or everything will break */
+#define RX_BUFFER_SIZE 32
+struct usart3_port {
+ void __iomem *regs;
+ int break_active;
+ unsigned int tx_dma_head;
+ int rx_tail;
+ char *rx_buffer;
+ dma_addr_t rx_dma;
+ dma_addr_t tx_dma;
+ struct clk *mck;
+ unsigned long mapsize;
+ struct uart_port uart;
+};
+#define to_usart3_port(port) container_of(port, struct usart3_port, uart)
+
+static void tx_dma_sync(struct uart_port *port)
+{
+ struct usart3_port *up = to_usart3_port(port);
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (xmit->head < up->tx_dma_head) {
+ dma_sync_single_for_device(port->dev,
+ up->tx_dma + up->tx_dma_head,
+ UART_XMIT_SIZE - up->tx_dma_head,
+ DMA_TO_DEVICE);
+ dma_sync_single_for_device(port->dev, up->tx_dma,
+ xmit->head, DMA_TO_DEVICE);
+ } else {
+ dma_sync_single_for_device(port->dev,
+ up->tx_dma + up->tx_dma_head,
+ xmit->head - up->tx_dma_head,
+ DMA_TO_DEVICE);
+ }
+}
+
+static void tx_dma_update_tail(struct uart_port *port)
+{
+ struct usart3_port *up = to_usart3_port(port);
+ struct circ_buf *xmit = &port->info->xmit;
+ unsigned long status, remaining;
+ unsigned int new_tail;
+
+ /* Account for the characters DMA'ed since last update */
+ remaining = usart3_readl(up, TCR);
+
+ if (up->tx_dma_head < xmit->tail) {
+ /*
+ * We have wrapped around, and there's a chunk at the
+ * beginning of the buffer that has been submitted for
+ * DMA. If the ENDTX bit is set, it means that the
+ * DMA controller also has wrapped around and copied
+ * TNPR/TNCR into TPR/TCR.
+ */
+ status = usart3_readl(up, CSR);
+ BUG_ON((up->tx_dma_head != 0)
+ && (usart3_readl(up, TNCR) == 0)
+ && !(status & USART3_BIT(ENDTX)));
+ if (status & USART3_BIT(ENDTX)) {
+ BUG_ON(usart3_readl(up, TNCR) != 0);
+
+ /* The ENDTX bit might be set after we read TCR */
+ remaining = usart3_readl(up, TCR);
+
+ usart3_writel(up, TNCR, 0);
+ port->icount.tx += UART_XMIT_SIZE - xmit->tail;
+ xmit->tail = 0;
+
+ BUG_ON(remaining > up->tx_dma_head);
+ new_tail = up->tx_dma_head - remaining;
+ } else {
+ /*
+ * The DMA controller hasn't switched yet, so
+ * TCR indicates the number of bytes left
+ * until this happens.
+ */
+ new_tail = UART_XMIT_SIZE - remaining;
+ }
+ } else {
+ /* No wraparound, move the tail closer to dma_head. */
|