/*
* mfd.c: driver for High Speed UART device of Intel Medfield platform
*
* Refer pxa.c, 8250.c and some other drivers in drivers/serial/
*
* (C) Copyright 2010 Intel Corporation
*
* 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; version 2
* of the License.
*/
/* Notes:
* 1. DMA channel allocation: 0/1 channel are assigned to port 0,
* 2/3 chan to port 1, 4/5 chan to port 3. Even number chans
* are used for RX, odd chans for TX
*
* 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always
* asserted, only when the HW is reset the DDCD and DDSR will
* be triggered
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/slab.h>
#include <linux/serial_reg.h>
#include <linux/circ_buf.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial_mfd.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/io.h>
#include <linux/debugfs.h>
#include <linux/pm_runtime.h>
#define HSU_DMA_BUF_SIZE 2048
#define chan_readl(chan, offset) readl(chan->reg + offset)
#define chan_writel(chan, offset, val) writel(val, chan->reg + offset)
#define mfd_readl(obj, offset) readl(obj->reg + offset)
#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset)
static int hsu_dma_enable;
module_param(hsu_dma_enable, int, 0);
MODULE_PARM_DESC(hsu_dma_enable,
"It is a bitmap to set working mode, if bit[x] is 1, then port[x] will work in DMA mode, otherwise in PIO mode.");
struct hsu_dma_buffer {
u8 *buf;
dma_addr_t dma_addr;
u32 dma_size;
u32 ofs;
};
struct hsu_dma_chan {
u32 id;
enum dma_data_direction dirt;
struct uart_hsu_port *uport;
void __iomem *reg;
};
struct uart_hsu_port {
struct uart_port port;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned int lsr_break_flag;
char name[12];
int index;
struct device *dev;
struct hsu_dma_chan *txc;
struct hsu_dma_chan *rxc;
struct hsu_dma_buffer txbuf;
struct hsu_dma_buffer rxbuf;
int use_dma; /* flag for DMA/PIO */
int running;
int dma_tx_on;
};
/* Top level data structure of HSU */
struct hsu_port {
void __iomem *reg;
unsigned long paddr;
unsigned long iolen;
u32 irq;
struct uart_hsu_port port[3];
struct hsu_dma_chan chans[10];
struct dentry *debugfs;
};
static inline unsigned int serial_in(struct uart_hsu_port *up, int offset)
{
unsigned int val;
if (offset > UART_MSR) {
offset <<= 2;
val = readl(up->port.membase + offset);
} else
val = (unsigned int)readb(up->port.membase + offset);
return val;
}
static inline void serial_out(struct uart_hsu_port *up, int offset, int value)
{
|