1d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* 2d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * mfd.c: driver for High Speed UART device of Intel Medfield platform 3d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 4d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Refer pxa.c, 8250.c and some other drivers in drivers/serial/ 5d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 606c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * (C) Copyright 2010 Intel Corporation 7d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 8d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * This program is free software; you can redistribute it and/or 9d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * modify it under the terms of the GNU General Public License 10d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * as published by the Free Software Foundation; version 2 11d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * of the License. 12d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 13d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 14d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* Notes: 1506c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * 1. DMA channel allocation: 0/1 channel are assigned to port 0, 1606c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * 2/3 chan to port 1, 4/5 chan to port 3. Even number chans 1706c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * are used for RX, odd chans for TX 18d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 19085a4f758f0cf95e1865b63892bf4304a149f0caFeng Tang * 2. The RI/DSR/DCD/DTR are not pinned out, DCD & DSR are always 2006c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * asserted, only when the HW is reset the DDCD and DDSR will 2106c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * be triggered 22d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 23d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 24fcd2bb9b5d64d115b4433ddff9fb3289dd9597a2Feng Tang#if defined(CONFIG_SERIAL_MFD_HSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 25fcd2bb9b5d64d115b4433ddff9fb3289dd9597a2Feng Tang#define SUPPORT_SYSRQ 26fcd2bb9b5d64d115b4433ddff9fb3289dd9597a2Feng Tang#endif 27fcd2bb9b5d64d115b4433ddff9fb3289dd9597a2Feng Tang 28d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/module.h> 29d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/init.h> 30d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/console.h> 31d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/sysrq.h> 3263d66cab4755edc86ddc5b78cae657a3fda908e1Andrew Morton#include <linux/slab.h> 33d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/serial_reg.h> 34d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/circ_buf.h> 35d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/delay.h> 36d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/interrupt.h> 37d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/tty.h> 38d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/tty_flip.h> 39d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/serial_core.h> 40d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/serial_mfd.h> 41d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/dma-mapping.h> 42d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/pci.h> 4350827fbde161a4ccb05a649752dd221b083f5ea5Feng Tang#include <linux/nmi.h> 44d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/io.h> 45d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#include <linux/debugfs.h> 4688e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#include <linux/pm_runtime.h> 47d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 48d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define HSU_DMA_BUF_SIZE 2048 49d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 50d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define chan_readl(chan, offset) readl(chan->reg + offset) 51d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define chan_writel(chan, offset, val) writel(val, chan->reg + offset) 52d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 53d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define mfd_readl(obj, offset) readl(obj->reg + offset) 54d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define mfd_writel(obj, offset, val) writel(val, obj->reg + offset) 55d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 56f023eab379821365bf265a0240f30c00cecaef7cFeng Tangstatic int hsu_dma_enable; 57f023eab379821365bf265a0240f30c00cecaef7cFeng Tangmodule_param(hsu_dma_enable, int, 0); 5885ee7a1d39d75d23d21f3871f6dc9b87d572747aJoe PerchesMODULE_PARM_DESC(hsu_dma_enable, 5985ee7a1d39d75d23d21f3871f6dc9b87d572747aJoe Perches "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."); 60f023eab379821365bf265a0240f30c00cecaef7cFeng Tang 61d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstruct hsu_dma_buffer { 62d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u8 *buf; 63d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dma_addr_t dma_addr; 64d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 dma_size; 65d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 ofs; 66d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 67d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 68d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstruct hsu_dma_chan { 69d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 id; 7006c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang enum dma_data_direction dirt; 71d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *uport; 72669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang void __iomem *reg; 73d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 74d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 75d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstruct uart_hsu_port { 76d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_port port; 77d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char ier; 78d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char lcr; 79d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char mcr; 80d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int lsr_break_flag; 81d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang char name[12]; 82d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int index; 83d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct device *dev; 84d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 85d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *txc; 86d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *rxc; 87d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_buffer txbuf; 88d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_buffer rxbuf; 89d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int use_dma; /* flag for DMA/PIO */ 90d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int running; 91d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int dma_tx_on; 92d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 93d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 94d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* Top level data structure of HSU */ 95d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstruct hsu_port { 96d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang void __iomem *reg; 97d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long paddr; 98d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long iolen; 99d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 irq; 100d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 101d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port port[3]; 102d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan chans[10]; 103d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 104d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct dentry *debugfs; 105d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 106d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 107d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline unsigned int serial_in(struct uart_hsu_port *up, int offset) 108d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 109d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int val; 110d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 111d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (offset > UART_MSR) { 112d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang offset <<= 2; 113d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang val = readl(up->port.membase + offset); 114d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else 115d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang val = (unsigned int)readb(up->port.membase + offset); 116d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 117d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return val; 118d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 119d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 120d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline void serial_out(struct uart_hsu_port *up, int offset, int value) 121d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 122d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (offset > UART_MSR) { 123d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang offset <<= 2; 124d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang writel(value, up->port.membase + offset); 125d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else { 126d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char val = value & 0xff; 127d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang writeb(val, up->port.membase + offset); 128d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 129d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 130d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 131d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#ifdef CONFIG_DEBUG_FS 132d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 133d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define HSU_REGS_BUFSIZE 1024 134d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 135d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 136d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic ssize_t port_show_regs(struct file *file, char __user *user_buf, 137d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang size_t count, loff_t *ppos) 138d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 139d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = file->private_data; 140d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang char *buf; 141d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 len = 0; 142d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ssize_t ret; 143d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 144d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); 145d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!buf) 146d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 147d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 148d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 149d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MFD HSU port[%d] regs:\n", up->index); 150d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 151d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 152d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "=================================\n"); 153d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 154d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "IER: \t\t0x%08x\n", serial_in(up, UART_IER)); 155d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 156d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "IIR: \t\t0x%08x\n", serial_in(up, UART_IIR)); 157d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 158d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "LCR: \t\t0x%08x\n", serial_in(up, UART_LCR)); 159d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 160d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MCR: \t\t0x%08x\n", serial_in(up, UART_MCR)); 161d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 162d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "LSR: \t\t0x%08x\n", serial_in(up, UART_LSR)); 163d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 164d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MSR: \t\t0x%08x\n", serial_in(up, UART_MSR)); 165d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 166d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "FOR: \t\t0x%08x\n", serial_in(up, UART_FOR)); 167d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 168d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "PS: \t\t0x%08x\n", serial_in(up, UART_PS)); 169d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 170d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MUL: \t\t0x%08x\n", serial_in(up, UART_MUL)); 171d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 172d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "DIV: \t\t0x%08x\n", serial_in(up, UART_DIV)); 173d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 174a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter if (len > HSU_REGS_BUFSIZE) 175a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter len = HSU_REGS_BUFSIZE; 176a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter 177d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 178d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang kfree(buf); 179d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 180d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 181d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 182d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic ssize_t dma_show_regs(struct file *file, char __user *user_buf, 183d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang size_t count, loff_t *ppos) 184d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 185d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *chan = file->private_data; 186d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang char *buf; 187d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 len = 0; 188d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ssize_t ret; 189d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 190d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang buf = kzalloc(HSU_REGS_BUFSIZE, GFP_KERNEL); 191d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!buf) 192d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 193d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 194d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 195d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MFD HSU DMA channel [%d] regs:\n", chan->id); 196d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 197d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 198d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "=================================\n"); 199d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 200d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "CR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_CR)); 201d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 202d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "DCR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_DCR)); 203d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 204d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "BSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_BSR)); 205d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 206d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "MOTSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_MOTSR)); 207d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 208d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0SAR)); 209d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 210d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D0TSR)); 211d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 212d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1SAR)); 213d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 214d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D1TSR)); 215d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 216d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2SAR)); 217d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 218d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D2TSR)); 219d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 220d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0SAR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3SAR)); 221d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang len += snprintf(buf + len, HSU_REGS_BUFSIZE - len, 222d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "D0TSR: \t\t0x%08x\n", chan_readl(chan, HSU_CH_D3TSR)); 223d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 224a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter if (len > HSU_REGS_BUFSIZE) 225a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter len = HSU_REGS_BUFSIZE; 226a95898114059e1038f3f7ee9bd2e43aefa62709aDan Carpenter 227d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 228d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang kfree(buf); 229d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 230d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 231d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 232d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic const struct file_operations port_regs_ops = { 233d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .owner = THIS_MODULE, 234234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 235d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .read = port_show_regs, 2366038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = default_llseek, 237d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 238d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 239d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic const struct file_operations dma_regs_ops = { 240d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .owner = THIS_MODULE, 241234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 242d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .read = dma_show_regs, 2436038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = default_llseek, 244d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 245d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 246d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int hsu_debugfs_init(struct hsu_port *hsu) 247d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 248d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int i; 249d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang char name[32]; 250d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 251d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->debugfs = debugfs_create_dir("hsu", NULL); 252d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!hsu->debugfs) 253d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return -ENOMEM; 254d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 255d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang for (i = 0; i < 3; i++) { 256d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang snprintf(name, sizeof(name), "port_%d_regs", i); 257d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang debugfs_create_file(name, S_IFREG | S_IRUGO, 258d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->debugfs, (void *)(&hsu->port[i]), &port_regs_ops); 259d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 260d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 261d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang for (i = 0; i < 6; i++) { 262d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang snprintf(name, sizeof(name), "dma_chan_%d_regs", i); 263d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang debugfs_create_file(name, S_IFREG | S_IRUGO, 264d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->debugfs, (void *)&hsu->chans[i], &dma_regs_ops); 265d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 266d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 267d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 268d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 269d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 270d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void hsu_debugfs_remove(struct hsu_port *hsu) 271d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 272d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (hsu->debugfs) 273d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang debugfs_remove_recursive(hsu->debugfs); 274d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 275d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 276d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#else 277d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline int hsu_debugfs_init(struct hsu_port *hsu) 278d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 279d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 280d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 281d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 282d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline void hsu_debugfs_remove(struct hsu_port *hsu) 283d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 284d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 285d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#endif /* CONFIG_DEBUG_FS */ 286d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 287d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_enable_ms(struct uart_port *port) 288d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 289d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 290d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 291d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 292d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier |= UART_IER_MSI; 293d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 294d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 295d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 2969baaa6747e84b078e42b1a6d17088049b5320167Jingoo Hanstatic void hsu_dma_tx(struct uart_hsu_port *up) 297d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 298d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct circ_buf *xmit = &up->port.state->xmit; 299d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_buffer *dbuf = &up->txbuf; 300d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int count; 301d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 302d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* test_and_set_bit may be better, but anyway it's in lock protected mode */ 303d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->dma_tx_on) 304d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 305d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 306d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Update the circ buf info */ 307d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang xmit->tail += dbuf->ofs; 308d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang xmit->tail &= UART_XMIT_SIZE - 1; 309d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 310d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.tx += dbuf->ofs; 311d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->ofs = 0; 312d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 313d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Disable the channel */ 314d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_CR, 0x0); 315d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 316d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) { 317d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dma_sync_single_for_device(up->port.dev, 318d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_addr, 319d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_size, 320d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang DMA_TO_DEVICE); 321d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 322d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); 323d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->ofs = count; 324d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 325d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Reprogram the channel */ 326d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail); 327d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_D0TSR, count); 328d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 329d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Reenable the channel */ 330d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_DCR, 0x1 331d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 8) 332d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 16) 333d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 24)); 334d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->dma_tx_on = 1; 335d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_CR, 0x1); 336d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 337d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 338d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 339d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_write_wakeup(&up->port); 340d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 341d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 342d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* The buffer is already cache coherent */ 3439baaa6747e84b078e42b1a6d17088049b5320167Jingoo Hanstatic void hsu_dma_start_rx_chan(struct hsu_dma_chan *rxc, 3449baaa6747e84b078e42b1a6d17088049b5320167Jingoo Han struct hsu_dma_buffer *dbuf) 345d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 346d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->ofs = 0; 347d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 348d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_BSR, 32); 349d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_MOTSR, 4); 350d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 351d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_D0SAR, dbuf->dma_addr); 352d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_D0TSR, dbuf->dma_size); 353d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_DCR, 0x1 | (0x1 << 8) 354d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 16) 355d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ 356d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ); 357d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(rxc, HSU_CH_CR, 0x3); 358d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 359d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 360d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* Protected by spin_lock_irqsave(port->lock) */ 361d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_start_tx(struct uart_port *port) 362d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 363d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 364d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 365d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 366d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->use_dma) { 367d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_dma_tx(up); 368d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else if (!(up->ier & UART_IER_THRI)) { 369d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier |= UART_IER_THRI; 370d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 371d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 372d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 373d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 374d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_stop_tx(struct uart_port *port) 375d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 376d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 377d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 378d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *txc = up->txc; 379d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 380d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->use_dma) 381d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(txc, HSU_CH_CR, 0x0); 382d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else if (up->ier & UART_IER_THRI) { 383d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier &= ~UART_IER_THRI; 384d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 385d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 386d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 387d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 388d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* This is always called in spinlock protected mode, so 389d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * modify timeout timer is safe here */ 3909baaa6747e84b078e42b1a6d17088049b5320167Jingoo Hanstatic void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts, 3919baaa6747e84b078e42b1a6d17088049b5320167Jingoo Han unsigned long *flags) 392d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 393d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_buffer *dbuf = &up->rxbuf; 394d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *chan = up->rxc; 395d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_port *port = &up->port; 39605c7cd39907184328f48d3e7899f9cdd653ad336Jiri Slaby struct tty_port *tport = &port->state->port; 397d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int count; 398d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 399d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 40006c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * First need to know how many is already transferred, 401d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * then check if its a timeout DMA irq, and return 402d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * the trail bytes out, push them up and reenable the 40306c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * channel 404d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 405d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 40606c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang /* Timeout IRQ, need wait some time, see Errata 2 */ 407d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (int_sts & 0xf00) 408d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang udelay(2); 409d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 410d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Stop the channel */ 411d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_CR, 0x0); 412d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 413d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang count = chan_readl(chan, HSU_CH_D0SAR) - dbuf->dma_addr; 414669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang if (!count) { 41506c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang /* Restart the channel before we leave */ 416669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang chan_writel(chan, HSU_CH_CR, 0x3); 417d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 418669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang } 419d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 420d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dma_sync_single_for_cpu(port->dev, dbuf->dma_addr, 421d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_size, DMA_FROM_DEVICE); 422d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 423d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 42406c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang * Head will only wrap around when we recycle 425d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * the DMA buffer, and when that happens, we 426d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * explicitly set tail to 0. So head will 427d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * always be greater than tail. 428d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 42905c7cd39907184328f48d3e7899f9cdd653ad336Jiri Slaby tty_insert_flip_string(tport, dbuf->buf, count); 430d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang port->icount.rx += count; 431d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 432d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dma_sync_single_for_device(up->port.dev, dbuf->dma_addr, 433d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_size, DMA_FROM_DEVICE); 434d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 435d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Reprogram the channel */ 436d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_D0SAR, dbuf->dma_addr); 437d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_D0TSR, dbuf->dma_size); 438d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_DCR, 0x1 439d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 8) 440d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 16) 441d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang | (0x1 << 24) /* timeout bit, see HSU Errata 1 */ 442d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ); 4438dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar spin_unlock_irqrestore(&up->port.lock, *flags); 4442e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(tport); 4458dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar spin_lock_irqsave(&up->port.lock, *flags); 446669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang 447d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_CR, 0x3); 448d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 449d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 450d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 451d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_stop_rx(struct uart_port *port) 452d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 453d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 454d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 455d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *chan = up->rxc; 456d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 457d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->use_dma) 458d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_CR, 0x2); 459d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else { 460d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier &= ~UART_IER_RLSI; 461d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.read_status_mask &= ~UART_LSR_DR; 462d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 463d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 464d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 465d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 4668dedc88776319f06cca3f25e7ec543244015a800Viresh Kumarstatic inline void receive_chars(struct uart_hsu_port *up, int *status, 4678dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar unsigned long *flags) 468d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 469d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int ch, flag; 470d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int max_count = 256; 471d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 472d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang do { 473d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ch = serial_in(up, UART_RX); 474d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang flag = TTY_NORMAL; 475d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.rx++; 476d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 477d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | 478d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_LSR_FE | UART_LSR_OE))) { 479d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 480d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dev_warn(up->dev, "We really rush into ERR/BI case" 481d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "status = 0x%02x", *status); 482d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* For statistics only */ 483d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (*status & UART_LSR_BI) { 484d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang *status &= ~(UART_LSR_FE | UART_LSR_PE); 485d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.brk++; 486d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 487d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * We do the SysRQ and SAK checking 488d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * here because otherwise the break 489d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * may get masked by ignore_status_mask 490d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * or read_status_mask. 491d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 492d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_handle_break(&up->port)) 493d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto ignore_char; 494d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else if (*status & UART_LSR_PE) 495d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.parity++; 496d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else if (*status & UART_LSR_FE) 497d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.frame++; 498d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (*status & UART_LSR_OE) 499d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.overrun++; 500d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 501d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Mask off conditions which should be ignored. */ 502d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang *status &= up->port.read_status_mask; 503d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 504d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE 505d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->port.cons && 506d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.cons->index == up->port.line) { 507d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Recover the break flag from console xmit */ 508d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang *status |= up->lsr_break_flag; 509d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->lsr_break_flag = 0; 510d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 511d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#endif 512d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (*status & UART_LSR_BI) { 513d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang flag = TTY_BREAK; 514d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else if (*status & UART_LSR_PE) 515d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang flag = TTY_PARITY; 516d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else if (*status & UART_LSR_FE) 517d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang flag = TTY_FRAME; 518d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 519d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 520d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_handle_sysrq_char(&up->port, ch)) 521d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto ignore_char; 522d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 523d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag); 524d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ignore_char: 525d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang *status = serial_in(up, UART_LSR); 526d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } while ((*status & UART_LSR_DR) && max_count--); 5278dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar 5288dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar spin_unlock_irqrestore(&up->port.lock, *flags); 5292e124b4a390ca85325fae75764bef92f0547fa25Jiri Slaby tty_flip_buffer_push(&up->port.state->port); 5308dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar spin_lock_irqsave(&up->port.lock, *flags); 531d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 532d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 533d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void transmit_chars(struct uart_hsu_port *up) 534d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 535d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct circ_buf *xmit = &up->port.state->xmit; 536d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int count; 537d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 538d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->port.x_char) { 539d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_TX, up->port.x_char); 540d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.tx++; 541d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.x_char = 0; 542d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 543d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 544d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { 545d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_stop_tx(&up->port); 546d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 547d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 548d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 549085a4f758f0cf95e1865b63892bf4304a149f0caFeng Tang /* The IRQ is for TX FIFO half-empty */ 550d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang count = up->port.fifosize / 2; 551085a4f758f0cf95e1865b63892bf4304a149f0caFeng Tang 552d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang do { 553d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_TX, xmit->buf[xmit->tail]); 554d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); 555d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 556d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.tx++; 557d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_circ_empty(xmit)) 558d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 559d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } while (--count > 0); 560d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 561d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) 562d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_write_wakeup(&up->port); 563d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 564d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (uart_circ_empty(xmit)) 565d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_stop_tx(&up->port); 566d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 567d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 568d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline void check_modem_status(struct uart_hsu_port *up) 569d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 570d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int status; 571d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 572d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang status = serial_in(up, UART_MSR); 573d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 574d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if ((status & UART_MSR_ANY_DELTA) == 0) 575d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 576d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 577d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_TERI) 578d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.rng++; 579d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_DDSR) 580d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.icount.dsr++; 581d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* We may only get DDCD when HW init and reset */ 582d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_DDCD) 583d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); 58406c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang /* Will start/stop_tx accordingly */ 585d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_DCTS) 586d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_handle_cts_change(&up->port, status & UART_MSR_CTS); 587d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 588d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang wake_up_interruptible(&up->port.state->port.delta_msr_wait); 589d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 590d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 591d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* 592d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * This handles the interrupt from one port. 593d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 594d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic irqreturn_t port_irq(int irq, void *dev_id) 595d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 596d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = dev_id; 597d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int iir, lsr; 598d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 599d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 600d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (unlikely(!up->running)) 601d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return IRQ_NONE; 602d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 60306c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang spin_lock_irqsave(&up->port.lock, flags); 604d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->use_dma) { 605d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang lsr = serial_in(up, UART_LSR); 606d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE | 607d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_LSR_FE | UART_LSR_OE))) 608d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dev_warn(up->dev, 609d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang "Got lsr irq while using DMA, lsr = 0x%2x\n", 610d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang lsr); 611d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang check_modem_status(up); 61206c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 613d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return IRQ_HANDLED; 614d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 615d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 616d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang iir = serial_in(up, UART_IIR); 617d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (iir & UART_IIR_NO_INT) { 618d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 619d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return IRQ_NONE; 620d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 621d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 622d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang lsr = serial_in(up, UART_LSR); 623d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (lsr & UART_LSR_DR) 6248dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar receive_chars(up, &lsr, &flags); 62506c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang check_modem_status(up); 626d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 627d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* lsr will be renewed during the receive_chars */ 628d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (lsr & UART_LSR_THRE) 629d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang transmit_chars(up); 630d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 631d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 632d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return IRQ_HANDLED; 633d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 634d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 635d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline void dma_chan_irq(struct hsu_dma_chan *chan) 636d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 637d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = chan->uport; 638d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 639d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 int_sts; 640d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 641d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 642d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 643d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!up->use_dma || !up->running) 644d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto exit; 645d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 646d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 647d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * No matter what situation, need read clear the IRQ status 648d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * There is a bug, see Errata 5, HSD 2900918 649d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 650d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int_sts = chan_readl(chan, HSU_CH_SR); 651d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 652d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Rx channel */ 653d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (chan->dirt == DMA_FROM_DEVICE) 6548dedc88776319f06cca3f25e7ec543244015a800Viresh Kumar hsu_dma_rx(up, int_sts, &flags); 655d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 656d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Tx channel */ 657d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (chan->dirt == DMA_TO_DEVICE) { 658d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(chan, HSU_CH_CR, 0x0); 659d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->dma_tx_on = 0; 660d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_dma_tx(up); 661d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 662d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 663d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangexit: 664d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 665d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 666d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 667d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 668d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic irqreturn_t dma_irq(int irq, void *dev_id) 669d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 670d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_port *hsu = dev_id; 671d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang u32 int_sts, i; 672d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 673d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int_sts = mfd_readl(hsu, HSU_GBL_DMAISR); 674d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 675d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Currently we only have 6 channels may be used */ 676d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang for (i = 0; i < 6; i++) { 677d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (int_sts & 0x1) 678d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dma_chan_irq(&hsu->chans[i]); 679d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int_sts >>= 1; 680d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 681d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 682d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return IRQ_HANDLED; 683d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 684d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 685d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic unsigned int serial_hsu_tx_empty(struct uart_port *port) 686d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 687d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 688d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 689d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 690d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int ret; 691d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 692d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 693d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; 694d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 695d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 696d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 697d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 698d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 699d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic unsigned int serial_hsu_get_mctrl(struct uart_port *port) 700d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 701d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 702d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 703d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char status; 704d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int ret; 705d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 706d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang status = serial_in(up, UART_MSR); 707d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 708d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = 0; 709d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_DCD) 710d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret |= TIOCM_CAR; 711d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_RI) 712d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret |= TIOCM_RNG; 713d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_DSR) 714d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret |= TIOCM_DSR; 715d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_MSR_CTS) 716d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret |= TIOCM_CTS; 717d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 718d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 719d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 720d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_set_mctrl(struct uart_port *port, unsigned int mctrl) 721d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 722d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 723d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 724d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char mcr = 0; 725d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 726d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (mctrl & TIOCM_RTS) 727d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= UART_MCR_RTS; 728d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (mctrl & TIOCM_DTR) 729d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= UART_MCR_DTR; 730d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (mctrl & TIOCM_OUT1) 731d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= UART_MCR_OUT1; 732d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (mctrl & TIOCM_OUT2) 733d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= UART_MCR_OUT2; 734d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (mctrl & TIOCM_LOOP) 735d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= UART_MCR_LOOP; 736d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 737d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mcr |= up->mcr; 738d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 739d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_MCR, mcr); 740d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 741d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 742d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_break_ctl(struct uart_port *port, int break_state) 743d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 744d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 745d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 746d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 747d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 748d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 749d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (break_state == -1) 750d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->lcr |= UART_LCR_SBC; 751d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else 752d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->lcr &= ~UART_LCR_SBC; 753d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_LCR, up->lcr); 754d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 755d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 756d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 757d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* 758d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * What special to do: 759d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 1. chose the 64B fifo mode 760085a4f758f0cf95e1865b63892bf4304a149f0caFeng Tang * 2. start dma or pio depends on configuration 761085a4f758f0cf95e1865b63892bf4304a149f0caFeng Tang * 3. we only allocate dma memory when needed 762d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 763d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int serial_hsu_startup(struct uart_port *port) 764d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 765d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 766d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 767d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 768d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 76988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_get_sync(up->dev); 77088e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 771d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 772d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Clear the FIFO buffers and disable them. 773d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * (they will be reenabled in set_termios()) 774d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 775d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); 776d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 777d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 778d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, 0); 779d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 780d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Clear the interrupt registers. */ 781d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_LSR); 782d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_RX); 783d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_IIR); 784d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_MSR); 785d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 786d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Now, initialize the UART, default is 8n1 */ 787d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_LCR, UART_LCR_WLEN8); 788d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 789d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 790d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 791d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.mctrl |= TIOCM_OUT2; 792d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_set_mctrl(&up->port, up->port.mctrl); 793d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 794d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 795d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Finally, enable interrupts. Note: Modem status interrupts 796d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * are set via set_termios(), which will be occurring imminently 797d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * anyway, so we don't enable them here. 798d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 799d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!up->use_dma) 800d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE; 801d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else 802d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier = 0; 803d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 804d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 805d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 806d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 807d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* DMA init */ 808d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->use_dma) { 809d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_buffer *dbuf; 810d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct circ_buf *xmit = &port->state->xmit; 811d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 812d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->dma_tx_on = 0; 813d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 814d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* First allocate the RX buffer */ 815d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf = &up->rxbuf; 816d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->buf = kzalloc(HSU_DMA_BUF_SIZE, GFP_KERNEL); 817d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!dbuf->buf) { 818d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->use_dma = 0; 819d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto exit; 820d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 821d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_addr = dma_map_single(port->dev, 822d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->buf, 823d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang HSU_DMA_BUF_SIZE, 824d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang DMA_FROM_DEVICE); 825d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_size = HSU_DMA_BUF_SIZE; 826d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 827d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Start the RX channel right now */ 828d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_dma_start_rx_chan(up->rxc, dbuf); 829d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 830d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Next init the TX DMA */ 831d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf = &up->txbuf; 832d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->buf = xmit->buf; 833d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_addr = dma_map_single(port->dev, 834d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->buf, 835d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_XMIT_SIZE, 836d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang DMA_TO_DEVICE); 837d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->dma_size = UART_XMIT_SIZE; 838d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 839d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* This should not be changed all around */ 840d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_BSR, 32); 841d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang chan_writel(up->txc, HSU_CH_MOTSR, 4); 842d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dbuf->ofs = 0; 843d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 844d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 845d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangexit: 846d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* And clear the interrupt registers again for luck. */ 847d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_LSR); 848d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_RX); 849d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_IIR); 850d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang (void) serial_in(up, UART_MSR); 851d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 852d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->running = 1; 853d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 854d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 855d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 856d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_shutdown(struct uart_port *port) 857d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 858d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 859d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 860d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 861d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 862d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Disable interrupts from this port */ 863d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier = 0; 864d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, 0); 865d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->running = 0; 866d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 867d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 868d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.mctrl &= ~TIOCM_OUT2; 869d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_set_mctrl(&up->port, up->port.mctrl); 870d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 871d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 872d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Disable break condition and FIFOs */ 873d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC); 874d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | 875d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_FCR_CLEAR_RCVR | 876d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang UART_FCR_CLEAR_XMIT); 877d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, 0); 87888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 87988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_put(up->dev); 880d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 881d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 882d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void 883d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, 884d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct ktermios *old) 885d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 886d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 887d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 888d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned char cval, fcr = 0; 889d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 890d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int baud, quot; 891a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang u32 ps, mul; 892d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 893d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang switch (termios->c_cflag & CSIZE) { 894d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case CS5: 895d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval = UART_LCR_WLEN5; 896d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 897d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case CS6: 898d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval = UART_LCR_WLEN6; 899d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 900d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case CS7: 901d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval = UART_LCR_WLEN7; 902d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 903d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang default: 904d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case CS8: 905d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval = UART_LCR_WLEN8; 906d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 907d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 908d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 909d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* CMSPAR isn't supported by this driver */ 910604fdb75094a7367e1794fd0f62183380364ce13Alan Cox termios->c_cflag &= ~CMSPAR; 911d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 912d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_cflag & CSTOPB) 913d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval |= UART_LCR_STOP; 914d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_cflag & PARENB) 915d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval |= UART_LCR_PARITY; 916d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!(termios->c_cflag & PARODD)) 917d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang cval |= UART_LCR_EPAR; 918d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 919d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 920e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * The base clk is 50Mhz, and the baud rate come from: 921e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * baud = 50M * MUL / (DIV * PS * DLAB) 922e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * 923d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * For those basic low baud rate we can get the direct 924e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * scalar from 2746800, like 115200 = 2746800/24. For those 925e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * higher baud rate, we handle them case by case, mainly by 926e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * adjusting the MUL/PS registers, and DIV register is kept 927e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang * as default value 0x3d09 to make things simple 928d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 929d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang baud = uart_get_baud_rate(port, termios, old, 0, 4000000); 930d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 931e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang quot = 1; 932a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang ps = 0x10; 933a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang mul = 0x3600; 934d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang switch (baud) { 935d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 3500000: 936d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mul = 0x3345; 937d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ps = 0xC; 938e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang break; 939e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang case 1843200: 940d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang mul = 0x2400; 941d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 942a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang case 3000000: 943a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang case 2500000: 944a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang case 2000000: 945d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 1500000: 946e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang case 1000000: 947e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang case 500000: 948a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang /* mul/ps/quot = 0x9C4/0x10/0x1 will make a 500000 bps */ 949a5880a9e5bb40fbae55de60051d69a29091053c3Feng Tang mul = baud / 500000 * 0x9C4; 950d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 951d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang default: 952e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang /* Use uart_get_divisor to get quot for other baud rates */ 953e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang quot = 0; 954d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 955d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 956e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang if (!quot) 957e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang quot = uart_get_divisor(port, baud); 958e5586eccc9aaf485985480e4d3049acffaa3fa90Feng Tang 959d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if ((up->port.uartclk / quot) < (2400 * 16)) 960d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_1B; 961d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else if ((up->port.uartclk / quot) < (230400 * 16)) 962d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_16B; 963d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else 964d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang fcr = UART_FCR_ENABLE_FIFO | UART_FCR_HSU_64_32B; 965d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 966d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang fcr |= UART_FCR_HSU_64B_FIFO; 967d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 968d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 969d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Ok, we're now changing the port state. Do it with 970d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * interrupts disabled. 971d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 972d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock_irqsave(&up->port.lock, flags); 973d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 974d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Update the per-port timeout */ 975d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_update_timeout(port, termios->c_cflag, baud); 976d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 977d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 978d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_iflag & INPCK) 979d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; 980ef8b9ddcb45fa3b1e11acd72be2398001e807d14Peter Hurley if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) 981d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.read_status_mask |= UART_LSR_BI; 982d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 983d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Characters to ignore */ 984d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.ignore_status_mask = 0; 985d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_iflag & IGNPAR) 986d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 987d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_iflag & IGNBRK) { 988d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.ignore_status_mask |= UART_LSR_BI; 989d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 990d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * If we're ignoring parity and break indicators, 991d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * ignore overruns too (for real raw support). 992d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 993d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_iflag & IGNPAR) 994d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.ignore_status_mask |= UART_LSR_OE; 995d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 996d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 997d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Ignore all characters if CREAD is not set */ 998d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if ((termios->c_cflag & CREAD) == 0) 999d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.ignore_status_mask |= UART_LSR_DR; 1000d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1001d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 1002d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * CTS flow control flag and modem status interrupts, disable 1003d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * MSI by default 1004d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 1005d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier &= ~UART_IER_MSI; 1006d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (UART_ENABLE_MS(&up->port, termios->c_cflag)) 1007d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->ier |= UART_IER_MSI; 1008d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1009d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, up->ier); 1010d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1011d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (termios->c_cflag & CRTSCTS) 1012d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->mcr |= UART_MCR_AFE | UART_MCR_RTS; 1013d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else 1014d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->mcr &= ~UART_MCR_AFE; 1015d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1016d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ 1017d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ 1018d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ 1019d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_LCR, cval); /* reset DLAB */ 1020d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_MUL, mul); /* set MUL */ 1021d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_PS, ps); /* set PS */ 1022d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->lcr = cval; /* Save LCR */ 1023d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_set_mctrl(&up->port, up->port.mctrl); 1024d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_FCR, fcr); 1025d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock_irqrestore(&up->port.lock, flags); 1026d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1027d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1028d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void 1029d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_pm(struct uart_port *port, unsigned int state, 1030d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int oldstate) 1031d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1032d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1033d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1034d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_release_port(struct uart_port *port) 1035d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1036d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1037d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1038d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int serial_hsu_request_port(struct uart_port *port) 1039d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1040d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 1041d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1042d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1043d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_config_port(struct uart_port *port, int flags) 1044d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1045d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 1046d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 1047d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->port.type = PORT_MFD; 1048d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1049d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1050d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int 1051d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_verify_port(struct uart_port *port, struct serial_struct *ser) 1052d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1053d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* We don't want the core code to modify any port params */ 1054d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return -EINVAL; 1055d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1056d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1057d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic const char * 1058d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_type(struct uart_port *port) 1059d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1060d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 1061d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 1062d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return up->name; 1063d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1064d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1065d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* Mainly for uart console use */ 1066d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct uart_hsu_port *serial_hsu_ports[3]; 1067d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct uart_driver serial_hsu_reg; 1068d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1069d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#ifdef CONFIG_SERIAL_MFD_HSU_CONSOLE 1070d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1071d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) 1072d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1073d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* Wait for transmitter & holding register to empty */ 1074d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic inline void wait_for_xmitr(struct uart_hsu_port *up) 1075d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1076d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int status, tmout = 1000; 1077d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1078d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Wait up to 1ms for the character to be sent. */ 1079d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang do { 1080d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang status = serial_in(up, UART_LSR); 1081d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1082d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (status & UART_LSR_BI) 1083d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up->lsr_break_flag = UART_LSR_BI; 1084d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1085d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (--tmout == 0) 1086d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 1087d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang udelay(1); 1088d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } while (!(status & BOTH_EMPTY)); 1089d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1090d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Wait up to 1s for flow control if necessary */ 1091d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->port.flags & UPF_CONS_FLOW) { 1092d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang tmout = 1000000; 1093d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang while (--tmout && 1094d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) 1095d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang udelay(1); 1096d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1097d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1098d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1099d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_console_putchar(struct uart_port *port, int ch) 1100d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1101d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = 1102d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang container_of(port, struct uart_hsu_port, port); 1103d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1104d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang wait_for_xmitr(up); 1105d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_TX, ch); 1106d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1107d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1108d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* 1109d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Print a string to the serial port trying not to disturb 1110d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * any possible real use of the port... 1111d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * 1112d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * The console_lock must be held when we get here. 1113d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 1114d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void 1115d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_console_write(struct console *co, const char *s, unsigned int count) 1116d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1117d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up = serial_hsu_ports[co->index]; 1118d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned long flags; 1119d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang unsigned int ier; 1120d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int locked = 1; 1121d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 112250827fbde161a4ccb05a649752dd221b083f5ea5Feng Tang touch_nmi_watchdog(); 112350827fbde161a4ccb05a649752dd221b083f5ea5Feng Tang 1124d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang local_irq_save(flags); 1125d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (up->port.sysrq) 1126d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang locked = 0; 1127d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang else if (oops_in_progress) { 1128d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang locked = spin_trylock(&up->port.lock); 1129d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else 1130d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_lock(&up->port.lock); 1131d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1132d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* First save the IER then disable the interrupts */ 1133d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ier = serial_in(up, UART_IER); 1134d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, 0); 1135d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1136d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_console_write(&up->port, s, count, serial_hsu_console_putchar); 1137d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1138d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* 1139d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * Finally, wait for transmitter to become empty 1140d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang * and restore the IER 1141d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang */ 1142d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang wait_for_xmitr(up); 1143d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_out(up, UART_IER, ier); 1144d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1145d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (locked) 1146d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang spin_unlock(&up->port.lock); 1147d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang local_irq_restore(flags); 1148d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1149d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1150d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct console serial_hsu_console; 1151d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1152d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int __init 1153d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangserial_hsu_console_setup(struct console *co, char *options) 1154d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1155d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up; 1156d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int baud = 115200; 1157d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int bits = 8; 1158d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int parity = 'n'; 1159d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int flow = 'n'; 1160d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1161d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (co->index == -1 || co->index >= serial_hsu_reg.nr) 1162d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang co->index = 0; 1163d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang up = serial_hsu_ports[co->index]; 1164d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!up) 1165d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return -ENODEV; 1166d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1167d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (options) 1168d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_parse_options(options, &baud, &parity, &bits, &flow); 1169d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1170b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg return uart_set_options(&up->port, co, baud, parity, bits, flow); 1171d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1172d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1173d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct console serial_hsu_console = { 1174d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .name = "ttyMFD", 1175d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .write = serial_hsu_console_write, 1176d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .device = uart_console_device, 1177d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .setup = serial_hsu_console_setup, 1178d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .flags = CON_PRINTBUFFER, 1179b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg .index = -1, 1180d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .data = &serial_hsu_reg, 1181d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 1182b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg 1183b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg#define SERIAL_HSU_CONSOLE (&serial_hsu_console) 1184b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg#else 1185b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg#define SERIAL_HSU_CONSOLE NULL 1186d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#endif 1187d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 11889baaa6747e84b078e42b1a6d17088049b5320167Jingoo Hanstatic struct uart_ops serial_hsu_pops = { 1189d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .tx_empty = serial_hsu_tx_empty, 1190d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .set_mctrl = serial_hsu_set_mctrl, 1191d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .get_mctrl = serial_hsu_get_mctrl, 1192d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .stop_tx = serial_hsu_stop_tx, 1193d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .start_tx = serial_hsu_start_tx, 1194d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .stop_rx = serial_hsu_stop_rx, 1195d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .enable_ms = serial_hsu_enable_ms, 1196d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .break_ctl = serial_hsu_break_ctl, 1197d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .startup = serial_hsu_startup, 1198d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .shutdown = serial_hsu_shutdown, 1199d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .set_termios = serial_hsu_set_termios, 1200d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .pm = serial_hsu_pm, 1201d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .type = serial_hsu_type, 1202d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .release_port = serial_hsu_release_port, 1203d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .request_port = serial_hsu_request_port, 1204d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .config_port = serial_hsu_config_port, 1205d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .verify_port = serial_hsu_verify_port, 1206d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 1207d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1208d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct uart_driver serial_hsu_reg = { 1209d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .owner = THIS_MODULE, 1210d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .driver_name = "MFD serial", 1211d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .dev_name = "ttyMFD", 1212d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .major = TTY_MAJOR, 1213d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .minor = 128, 1214d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .nr = 3, 1215b82e324b3c46a554595c12b45465d1943a57326cMika Westerberg .cons = SERIAL_HSU_CONSOLE, 1216d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 1217d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1218d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#ifdef CONFIG_PM 1219d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) 1220d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 12213c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang void *priv = pci_get_drvdata(pdev); 1222d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up; 1223d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 12243c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang /* Make sure this is not the internal dma controller */ 12253c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang if (priv && (pdev->device != 0x081E)) { 12263c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang up = priv; 12273c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang uart_suspend_port(&serial_hsu_reg, &up->port); 12283c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang } 1229d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 12303c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang pci_save_state(pdev); 12313c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang pci_set_power_state(pdev, pci_choose_state(pdev, state)); 1232d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 1233d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1234d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1235d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int serial_hsu_resume(struct pci_dev *pdev) 1236d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 12373c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang void *priv = pci_get_drvdata(pdev); 1238d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *up; 12393c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang int ret; 1240d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 12413c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang pci_set_power_state(pdev, PCI_D0); 12423c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang pci_restore_state(pdev); 12433c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang 12443c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang ret = pci_enable_device(pdev); 12453c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang if (ret) 12463c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang dev_warn(&pdev->dev, 12473c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang "HSU: can't re-enable device, try to continue\n"); 12483c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang 12493c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang if (priv && (pdev->device != 0x081E)) { 12503c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang up = priv; 12513c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang uart_resume_port(&serial_hsu_reg, &up->port); 12523c4108c82f7769fcd265dc77a5bb0c6d8bcea25fFeng Tang } 1253d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 1254d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1255d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#else 1256d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define serial_hsu_suspend NULL 1257d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#define serial_hsu_resume NULL 1258d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang#endif 1259d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 126088e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#ifdef CONFIG_PM_RUNTIME 126188e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardistatic int serial_hsu_runtime_idle(struct device *dev) 126288e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi{ 126345f0a85c8258741d11bda25c0a5669c06267204aRafael J. Wysocki pm_schedule_suspend(dev, 500); 126445f0a85c8258741d11bda25c0a5669c06267204aRafael J. Wysocki return -EBUSY; 126588e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi} 126688e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 126788e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardistatic int serial_hsu_runtime_suspend(struct device *dev) 126888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi{ 126988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi return 0; 127088e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi} 127188e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 127288e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardistatic int serial_hsu_runtime_resume(struct device *dev) 127388e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi{ 127488e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi return 0; 127588e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi} 127688e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#else 127788e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#define serial_hsu_runtime_idle NULL 127888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#define serial_hsu_runtime_suspend NULL 127988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#define serial_hsu_runtime_resume NULL 128088e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi#endif 128188e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 128288e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardistatic const struct dev_pm_ops serial_hsu_pm_ops = { 128388e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi .runtime_suspend = serial_hsu_runtime_suspend, 128488e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi .runtime_resume = serial_hsu_runtime_resume, 128588e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi .runtime_idle = serial_hsu_runtime_idle, 128688e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi}; 128788e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 1288d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* temp global pointer before we settle down on using one or four PCI dev */ 1289d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct hsu_port *phsu; 1290d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1291d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int serial_hsu_probe(struct pci_dev *pdev, 1292d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang const struct pci_device_id *ent) 1293d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1294d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *uport; 1295d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int index, ret; 1296d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1297d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang printk(KERN_INFO "HSU: found PCI Serial controller(ID: %04x:%04x)\n", 1298d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pdev->vendor, pdev->device); 1299d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1300d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang switch (pdev->device) { 1301d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 0x081B: 1302d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang index = 0; 1303d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 1304d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 0x081C: 1305d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang index = 1; 1306d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 1307d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 0x081D: 1308d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang index = 2; 1309d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 1310d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang case 0x081E: 1311d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* internal DMA controller */ 1312d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang index = 3; 1313d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang break; 1314d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang default: 1315d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dev_err(&pdev->dev, "HSU: out of index!"); 1316d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return -ENODEV; 1317d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1318d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1319d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = pci_enable_device(pdev); 1320d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (ret) 1321d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 1322d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1323d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (index == 3) { 1324d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* DMA controller */ 1325d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = request_irq(pdev->irq, dma_irq, 0, "hsu_dma", phsu); 1326d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (ret) { 1327d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dev_err(&pdev->dev, "can not get IRQ\n"); 1328d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto err_disable; 1329d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1330d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pci_set_drvdata(pdev, phsu); 1331d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } else { 1332d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* UART port 0~2 */ 1333d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport = &phsu->port[index]; 1334d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.irq = pdev->irq; 1335d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.dev = &pdev->dev; 1336d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->dev = &pdev->dev; 1337d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1338d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = request_irq(pdev->irq, port_irq, 0, uport->name, uport); 1339d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (ret) { 1340d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dev_err(&pdev->dev, "can not get IRQ\n"); 1341d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto err_disable; 1342d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1343d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_add_one_port(&serial_hsu_reg, &uport->port); 1344d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1345d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pci_set_drvdata(pdev, uport); 1346d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1347d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 134888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_put_noidle(&pdev->dev); 134988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_allow(&pdev->dev); 135088e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 1351d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return 0; 1352d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1353d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangerr_disable: 1354d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pci_disable_device(pdev); 1355d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 1356d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1357d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1358d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void hsu_global_init(void) 1359d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1360d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_port *hsu; 1361d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct uart_hsu_port *uport; 1362d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang struct hsu_dma_chan *dchan; 1363d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int i, ret; 1364d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1365d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu = kzalloc(sizeof(struct hsu_port), GFP_KERNEL); 1366d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!hsu) 1367d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 1368d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1369d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Get basic io resource and map it */ 1370d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->paddr = 0xffa28000; 1371d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->iolen = 0x1000; 1372d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1373d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!(request_mem_region(hsu->paddr, hsu->iolen, "HSU global"))) 1374d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pr_warning("HSU: error in request mem region\n"); 1375d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1376d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu->reg = ioremap_nocache((unsigned long)hsu->paddr, hsu->iolen); 1377d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (!hsu->reg) { 1378d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pr_err("HSU: error in ioremap\n"); 1379d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = -ENOMEM; 1380d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang goto err_free_region; 1381d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1382d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1383d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Initialise the 3 UART ports */ 1384d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport = hsu->port; 1385d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang for (i = 0; i < 3; i++) { 1386d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.type = PORT_MFD; 1387d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.iotype = UPIO_MEM; 1388d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.mapbase = (resource_size_t)hsu->paddr 1389d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang + HSU_PORT_REG_OFFSET 1390d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang + i * HSU_PORT_REG_LENGTH; 1391d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.membase = hsu->reg + HSU_PORT_REG_OFFSET 1392d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang + i * HSU_PORT_REG_LENGTH; 1393d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1394d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang sprintf(uport->name, "hsu_port%d", i); 1395d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.fifosize = 64; 1396d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.ops = &serial_hsu_pops; 1397d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.line = i; 1398d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.flags = UPF_IOREMAP; 139906c77e21ae7c199435097116b8212b0761fc8ba8Feng Tang /* set the scalable maxim support rate to 2746800 bps */ 1400d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->port.uartclk = 115200 * 24 * 16; 1401d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1402d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->running = 0; 1403d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->txc = &hsu->chans[i * 2]; 1404d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->rxc = &hsu->chans[i * 2 + 1]; 1405d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1406d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang serial_hsu_ports[i] = uport; 1407d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport->index = i; 1408f023eab379821365bf265a0240f30c00cecaef7cFeng Tang 1409f023eab379821365bf265a0240f30c00cecaef7cFeng Tang if (hsu_dma_enable & (1<<i)) 1410f023eab379821365bf265a0240f30c00cecaef7cFeng Tang uport->use_dma = 1; 1411f023eab379821365bf265a0240f30c00cecaef7cFeng Tang else 1412f023eab379821365bf265a0240f30c00cecaef7cFeng Tang uport->use_dma = 0; 1413f023eab379821365bf265a0240f30c00cecaef7cFeng Tang 1414d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uport++; 1415d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1416d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1417d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang /* Initialise 6 dma channels */ 1418d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan = hsu->chans; 1419d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang for (i = 0; i < 6; i++) { 1420d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan->id = i; 1421d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan->dirt = (i & 0x1) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; 1422d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan->uport = &hsu->port[i/2]; 1423d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan->reg = hsu->reg + HSU_DMA_CHANS_REG_OFFSET + 1424d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang i * HSU_DMA_CHANS_REG_LENGTH; 1425669b7a0938e759097c150400cd36bd49befaf5bbFeng Tang 1426d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang dchan++; 1427d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang } 1428d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1429d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang phsu = hsu; 1430d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_debugfs_init(hsu); 1431d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 1432d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1433d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangerr_free_region: 1434d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang release_mem_region(hsu->paddr, hsu->iolen); 1435d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang kfree(hsu); 1436d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 1437d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1438d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1439d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void serial_hsu_remove(struct pci_dev *pdev) 1440d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1441e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang void *priv = pci_get_drvdata(pdev); 1442e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang struct uart_hsu_port *up; 1443d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1444e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang if (!priv) 1445d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return; 1446d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 144788e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_forbid(&pdev->dev); 144888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi pm_runtime_get_noresume(&pdev->dev); 144988e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi 1450e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang /* For port 0/1/2, priv is the address of uart_hsu_port */ 1451e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang if (pdev->device != 0x081E) { 1452e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang up = priv; 1453e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang uart_remove_one_port(&serial_hsu_reg, &up->port); 1454e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang } 1455d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1456e3671ac429fe50cf0c1b4f1dc4b7237207f1d956Feng Tang free_irq(pdev->irq, priv); 1457d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pci_disable_device(pdev); 1458d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1459d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1460d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang/* First 3 are UART ports, and the 4th is the DMA */ 1461512f82a064e397e437845c3f03a3c6dc3e610e8bBill Pembertonstatic const struct pci_device_id pci_ids[] = { 1462d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081B) }, 1463d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081C) }, 1464d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081D) }, 1465d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081E) }, 1466d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang {}, 1467d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 1468d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1469d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic struct pci_driver hsu_pci_driver = { 1470d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .name = "HSU serial", 1471d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .id_table = pci_ids, 1472d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .probe = serial_hsu_probe, 14732d47b7160243b1422006b91debf438484a4fde58Bill Pemberton .remove = serial_hsu_remove, 1474d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .suspend = serial_hsu_suspend, 1475d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang .resume = serial_hsu_resume, 147688e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi .driver = { 147788e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi .pm = &serial_hsu_pm_ops, 147888e5173ff12e6832899ac74ed0f3395107af2811Kristen Carlson Accardi }, 1479d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang}; 1480d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1481d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic int __init hsu_pci_init(void) 1482d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1483d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang int ret; 1484d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1485d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_global_init(); 1486d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1487d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang ret = uart_register_driver(&serial_hsu_reg); 1488d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang if (ret) 1489d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return ret; 1490d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1491d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang return pci_register_driver(&hsu_pci_driver); 1492d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1493d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1494d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangstatic void __exit hsu_pci_exit(void) 1495d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang{ 1496d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang pci_unregister_driver(&hsu_pci_driver); 1497d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang uart_unregister_driver(&serial_hsu_reg); 1498d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1499d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang hsu_debugfs_remove(phsu); 1500d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1501d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang kfree(phsu); 1502d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang} 1503d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1504d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangmodule_init(hsu_pci_init); 1505d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tangmodule_exit(hsu_pci_exit); 1506d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng Tang 1507d843fc6e9dc9bee7061b6833594860ea93ad98e1Feng TangMODULE_LICENSE("GPL v2"); 150812d493c791876519393a483fa46bc4893379d523Ben HutchingsMODULE_DEVICE_TABLE(pci, pci_ids); 1509