Newer
Older
* linux/drivers/char/atmel_serial.c
* Driver for Atmel AT91 / AT32 Serial ports
* Copyright (C) 2003 Rick Bronson
*
* Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
* Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/tty_flip.h>
#include <linux/platform_device.h>
#include <linux/atmel_pdc.h>
#include <linux/atmel_serial.h>
#include <asm/io.h>
#include <asm/mach/serial_at91.h>
#include <mach/board.h>
#include <mach/cpu.h>
#include <mach/gpio.h>
#define PDC_BUFFER_SIZE 512
/* Revisit: We should calculate this based on the actual port settings */
#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */
#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#ifdef CONFIG_SERIAL_ATMEL_TTYAT
/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
* should coexist with the 8250 driver, such as if we have an external 16C550
* UART. */
#define SERIAL_ATMEL_MAJOR 204
#define MINOR_START 154
#define ATMEL_DEVICENAME "ttyAT"
#else
/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port
* name, but it is legally reserved for the 8250 driver. */
#define SERIAL_ATMEL_MAJOR TTY_MAJOR
#define ATMEL_DEVICENAME "ttyS"
#define ATMEL_ISR_PASS_LIMIT 256
/* UART registers. CR is write-only, hence no GET macro */
#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR)
#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR)
#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR)
#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER)
#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR)
#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR)
#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR)
#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR)
#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR)
#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR)
#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR)
#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR)
#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR)
#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR)
#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR)
#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR)
#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR)
#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR)
#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR)
#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR)
#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR)
static int (*atmel_open_hook)(struct uart_port *);
static void (*atmel_close_hook)(struct uart_port *);
struct atmel_dma_buffer {
unsigned char *buf;
dma_addr_t dma_addr;
unsigned int dma_size;
unsigned int ofs;
};
struct atmel_uart_char {
u16 status;
u16 ch;
};
#define ATMEL_SERIAL_RINGSIZE 1024
/*
* We wrap our port structure around the generic uart_port.
*/
struct atmel_uart_port {
struct uart_port uart; /* uart */
struct clk *clk; /* uart clock */
unsigned short suspended; /* is port suspended? */
int break_active; /* break being received */
short use_dma_rx; /* enable PDC receiver */
short pdc_rx_idx; /* current PDC RX buffer */
struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */
short use_dma_tx; /* enable PDC transmitter */
struct atmel_dma_buffer pdc_tx; /* PDC transmitter */
struct tasklet_struct tasklet;
unsigned int irq_status;
unsigned int irq_status_prev;
struct circ_buf rx_ring;
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
static struct console atmel_console;
static inline struct atmel_uart_port *
to_atmel_uart_port(struct uart_port *uart)
{
return container_of(uart, struct atmel_uart_port, uart);
}
#ifdef CONFIG_SERIAL_ATMEL_PDC
static bool atmel_use_dma_rx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
return atmel_port->use_dma_rx;
}
static bool atmel_use_dma_tx(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
return atmel_port->use_dma_tx;
}
#else
static bool atmel_use_dma_rx(struct uart_port *port)
{
return false;
}
static bool atmel_use_dma_tx(struct uart_port *port)
{
return false;
}
#endif
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
static u_int atmel_tx_empty(struct uart_port *port)
return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
}
/*
* Set state of the modem control output lines
*/
static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
Loading
Loading full blame...