//#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/mca.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/interrupt.h>
#include <linux/serial_8250.h>
#include <asm-arm/delay.h>
#define CONFIG_HUB6 1
#include <linux/delay.h>
#include <asm/serial.h>
#include <asm/arch/at91rm9200_mc.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch-at91rm9200/gpio.h>
#include <asm/arch/at91_pmc.h>
#include "ST16C554.h"
#define ST16C554_IRQ 3
#define pr_info(info, arg...) do{ printk(info,##arg);\
mdelay(1000);\
}while(0)
/*------------ 接口全局变量------------*/
static unsigned char * ST16C554PortBase;
static struct platform_device *serial16c554_devs;
struct st16c554_uart_port st16c554_ports[UART_16C554_NUM];
static DECLARE_MUTEX(serial16c554_sem);
static char PortIsOpen[UART_16C554_NR];
/*------------ 接口操作函数------------*/
static struct uart_ops st16c554_pops = {
.tx_empty = st16c554_tx_empty,
.set_mctrl = st16c554_set_mctrl,
.get_mctrl = st16c554_get_mctrl,
.stop_tx = st16c554_stop_tx,
.start_tx = st16c554_start_tx,
.stop_rx = st16c554_stop_rx,
.enable_ms = st16c554_enable_ms,
.break_ctl = st16c554_break_ctl,
.startup = st16c554_startup,
.shutdown = st16c554_shutdown,
.set_termios = st16c554_set_termios,
.pm = st16c554_pm,
.type = st16c554_type,
.release_port = st16c554_release_port,
.request_port = st16c554_request_port,
.config_port = st16c554_config_port,
.verify_port = st16c554_verify_port,
};
struct uart_driver st16c554_reg = {
.owner = THIS_MODULE,
.driver_name = ST16C554_DRIVER_NAME,
// .devfs_name = ST16C554_DEVFS_NAME,
.dev_name = ST16C554_DEV_NAME,
.major = ST16C554_MAJOR,
.minor = ST16C554_MINOR,
.nr = UART_16C554_NR,
.cons = ST16C554_CONSOLE,
};
static unsigned int serial_in(struct uart_port *up, int offset)
{
switch(offset) {
case UART_RX: //0
//case UART_TX: //0
//case UART_DLL: //0
return UART_URXH(up);
case UART_IER: //1
//case UART_DLM: //1
return UART_UIER(up);
case UART_FCR://2
//case UART_IIR: //2
return UART_UFCON(up);
case UART_LCR://3
return UART_ULCON(up);
case UART_MCR: //4
return UART_UMCON(up);
case UART_LSR://5
return UART_ULSTAT(up);
case UART_MSR://6
return UART_UMSTAT(up);
case UART_SCR://7
return UART_URSCRR(up);
default:
return 0;
}
}
/***************************************
**************************************/
unsigned int st16c554_tx_empty(struct uart_port *port)
{
unsigned long flags;
unsigned int ret;
spin_lock_irqsave(&port->lock, flags);
ret = serial_in(port, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
spin_unlock_irqrestore(&port->lock, flags);
return 1;
}
/***************************************
**************************************/
void st16c554_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
unsigned char mcr = 0;
//printk("Now Start st16c554_set_mctrl,line= %d\n",port->line);
if (mctrl & TIOCM_RTS)
mcr |= 0x02;
if (mctrl & TIOCM_DTR)
mcr |= 0x01;
if (mctrl & TIOCM_OUT1)
mcr |= 0x04;
if (mctrl & TIOCM_OUT2)
mcr |= 0x80;
if (mctrl & TIOCM_LOOP)
mcr |= 0x10;
/* Enable interrupt */
mcr |= 0x08;
UART_UMCON(port) = mcr;
//printk("st16c554_set_mctrl->set MCR to 0x%02x\n",mcr);
return;
}
/***************************************
**************************************/
unsigned int st16c554_get_mctrl(struct uart_port *port)
{
unsigned char status;
unsigned int ret;
printk("Now Start st16c554_get_mctrl,line= %d\n",port->line);
status = UART_UMSTAT(port);
ret = 0;
if (status & 0x80)
ret |= TIOCM_CAR;
if (status & 0x40)
ret |= TIOCM_RNG;
if (status & 0x20)
ret |= TIOCM_DSR;
if (status & 0x10)
ret |= TIOCM_CTS;
return ret;
}
/***************************************
**************************************/
void st16c554_stop_tx(struct uart_port *port)
{
struct st16c554_uart_port *up;
printk("Now Start st16c554_stop_tx,line= %d\n",port->line);
up=&st16c554_ports[port->line];
up->ier&= ~0x02;
UART_UIER(port) = up->ier;
return;
}
/***************************************
**************************************/
void st16c554_start_tx(struct uart_port *port)
{
struct uart_info *info;
struct st16c554_uart_port *up;
printk("Now Start st16c554_start_tx,line= %d\n",port->line);
info=port->info;
up=&st16c554_ports[port->line];
// up->ier|= 0x02;
// UART_UIER(port) = up->ier;
tx_interrupt(info, port);
return ;
}
/***************************************
**************************************/
void st16c554_stop_rx(struct uart_port *port)
{
struct st16c554_uart_port *up;
printk("Now Start st16c554_stop_rx,line= %d\n",port->line);
up=&st16c554_ports[port->line];
up->ier&= ~0x01;
UART_UIER(port) = up->ier;
return;
}
/***************************************
开启Modem中断
**************************************/
void st16c554_enable_ms(struct uart_port *port)
{
struct st16c554_uart_port *up;
//printk("Now Start st16c554_enable_ms,line= %d\n",port->line);
up=&st16c554_ports[port->line];
up->ier |= 0x08;
UART_UIER(port) = up->ier;
return;
}
/***************************************
break_state!=0:发送break信号,否则,恢复正常模式
**************************************/
void st16c554_break_ctl(struct uart_port *port, int break_state)
{
//printk("Now Start st16c554_break_ctl,line= %d\n",port->line);
struct st16c554_uart_port *up = &st16c554_ports[port->line];
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
if (break_state == -1)
up->lcr |= UART_LCR_SBC;
else
up->lcr &= ~UART_LCR_SBC;
UART_ULCON(port)=up->lcr;
spin_unlock_irqrestore(&port->lock, flags);
return;
}
/***************************************
Need debug
注意:
不能直接操作IRQ,因为别的端口与这个端口的IRQ相同
**************************************/
int st16c554_startup(struct uart_port *port)
{
struct st16c554_uart_port *up = &st16c554_ports[port->line];
unsigned long Ret;
unsigned char Data;
printk("Now Start st16c554_startup,line= %d\n",port->line);
//UART_UIER(port) = 0x07;
//UART_UFCON(port) = 0x07;
//UART_UFCON(port) = 0xcf;
//udelay(100);
//UART_UFCON(port) = 0xc9;
//st16c554_set_mctrl(port,port->mctrl);
//UART_ULCON(port) = up->lcr=0x83;
//UART_UBRDIVL(port)= (0x0c); //default is 9600 bps
//UART_UBRDIVM(port)= (0x00);
//UART_ULCON(port) = up->lcr=0x03;
//空读一次
Data=UART_ULCON(port) ;
//确保收状态
Ret=1;
while(Ret){
Data=UART_ULSTAT(port);
if(Data&0x01){
printk("st16c554_startup->Receive FIFO is not ready.\n");
Data=UART_URXH(port);
}else{
Ret=0;
}
}
//指示已经打开的端口
PortIsOpen[port->line]=1;
printk("st16c554_startup->Now Set line %d to 1\n",port->line);
up->ier = UART_IER_RLSI | UART_IER_RDI;
UART_UIER(port) = up->ier;
return 0;
}
/***************************************
Need debug
注意:
不能直接删除IRQ,因为别的端口与这个端口的IRQ相同
**************************************/
void st16c554_shutdown(struct uart_port *port)
{
unsigned long flags;
struct st16c554_uart_port *up = &st16c554_ports[port->line];
//printk("Now Start st16c554_shutdown,line= %d\n",port->line);
up->ier = 0;
UART_UIER(port) = up->ier;
spin_lock_irqsave(&port->lock, flags);
port->mctrl &= ~TIOCM_OUT2;
st16c554_set_mctrl(port,port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
UART_ULCON(port) = 0x00;