/*
* tl16c554.c
*
* TL16C554 driver for SAMSUNG S3C2410
*
* Author: Yongping wu <godiscrazy@163.com>
* Date : $Date: 2006/03/14 16:13:04 $
*
* $Revision: 1.1V $
*
TL16C554APN
3.6864mhz
扩展芯片:2*TL16C554APN
可为系统增加8个串口,直接与S3C2410总线连接,8位数据宽度
地址空间:占用系统BANK5
地址从前到后分别对应每个UART0-7个寄存器
UART0A:0x2800_0000---0x2800_0003;0x2880_0000---0x2880_0003
A2A1A0(TL16C554)
0x2800_0000 0 0 0
0x2800_0001 0 0 1
0x2800_0002 0 1 0
0x2800_0003 0 1 1
0x2880_0000 1 0 0
0x2880_0001 1 0 1
0x2880_0002 1 1 0
0x2880_0003 1 1 1
UART0B:0x2800_2000---0x2800_2003;0x2880_2000---0x2880_2003
UART0C:0x2800_4000---0x2800_4003;0x2880_4000---0x2880_4003
UART0D:0x2800_6000---0x2800_6003;0x2880_6000---0x2880_6003
UART1A:0x2800_8000---0x2800_8003;0x2880_8000---0x2880_8003
UART1B:0x2800_A000---0x2800_A003;0x2880_A000---0x2880_A003
UART1C:0x2800_C000---0x2800_C003;0x2880_C000---0x2880_C003
UART1D:0x2800_E000---0x2800_E003;0x2880_E000---0x2880_E003
控制寄存器
Line-control register(LCR)
0x03
FIFO-control register(FCR)
0x02
Modem-control register(MCR)
0x04
Divisor-latch LSB(DLL)
LCR(bit7=1)0x00
Divisor-latch MSB(DLM)
LCR(bit7=1)0x01
Interrupt enable register(IER)
0x01
状态寄存器
Line-status register(LSR)
0x05
Modem-status register(MSR)
0x06
数据寄存器
Receiver-buffer register(RBR)
0x00
Transmitter-holding register(THR)
0x00
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <asm/arch/S3C2410.h>
#include <asm/arch/cpu_s3c2410.h>
#include <asm/hardware.h>
#include <asm/io.h>
#define TL0_A_READ 0
#define TL0_B_READ 1
#define TL0_C_READ 2
#define TL0_D_READ 3
#define TL1_A_READ 4
#define TL1_B_READ 5
#define TL1_C_READ 6
#define TL1_D_READ 7
#define TL0_A_WRITE 8
#define TL0_B_WRITE 9
#define TL0_C_WRITE 10
#define TL0_D_WRITE 11
#define TL1_A_WRITE 12
#define TL1_B_WRITE 13
#define TL1_C_WRITE 14
#define TL1_D_WRITE 15
#define TL_INIT 32
#define GPG2ON 33
#define GPG2OFF 34
typedef struct tagTL_INIT{
int nChn;
int nBaud;
unsigned char byMode;
} myTL_INIT;
myTL_INIT tl0A_init;
myTL_INIT tl0B_init;
myTL_INIT tl0C_init;
myTL_INIT tl0D_init;
#define NONEPARITY 0x00
#define ODDPARITY 0x08
#define EVENPARITY 0x18
#define DATA7BIT 0x80
#define BAUDBASE 0x30 /***4800bps->hex***/
#define TL_COM_CNT 8
#define TL_RECV_LEN 1600
#define TL_SEND_LEN 160
typedef struct {
int nAddress0;
int nAddress1;
int sInited;
unsigned char *pbyBase0;
unsigned char *pbyBase1;
//数据寄存器
int RBR;//Receiver-buffer register 0
int THR;//Transmitter-holding register 0
//状态寄存器
int LSR;//Line-status register 5
int MSR;//Modem-status register 6
//控制寄存器
int LCR;//Line-control register 3
int FCR;//FIFO-control register 2
int MCR;//Modem-control register 4
int DLL;//Divisor-latch LSB 0
int DLM;//Divisor-latch MSB 1
int IER;//Interrupt enable register 1
//其它寄存器
int SPR;//Scratchpad register 7
int IIR;//Interrupt identification register 2
//串口数据接收缓冲区
volatile short sRecvHead;
volatile short sRecvTail;
volatile unsigned char abyRecvData[TL_RECV_LEN];
//串口数据发送缓冲区
volatile short sSendHead;
volatile short sSendTail;
volatile unsigned char abySendData[TL_SEND_LEN];
} TL_COM;
static TL_COM tl0A = {0x28000000,0x28800000,0};
static TL_COM tl0B = {0x28002000,0x28802000,0};
static TL_COM tl0C = {0x28004000,0x28804000,0};
static TL_COM tl0D = {0x28006000,0x28806000,0};
#define DEVICE_NAME "TL16C554"
#define DEVICE_MAJOR 233
#define TL0A 0
#define TL0B 1
#define TL0C 2
#define TL0D 3
static int tlMajor = 233;
inline int get_TL0A_rxLen(void){
if(tl0A.sRecvHead==tl0A.sRecvTail){
return 0;
}
else if(tl0A.sRecvTail>tl0A.sRecvHead){
return (tl0A.sRecvTail-tl0A.sRecvHead);
}
else{
return ( TL_RECV_LEN-(tl0A.sRecvHead-tl0A.sRecvTail) );
}
}
inline int get_TL0B_rxLen(void){
if(tl0B.sRecvHead==tl0B.sRecvTail){
return 0;
}
else if(tl0B.sRecvTail>tl0B.sRecvHead){
return (tl0B.sRecvTail-tl0B.sRecvHead);
}
else{
return ( TL_RECV_LEN-(tl0B.sRecvHead-tl0B.sRecvTail) );
}
}
inline int get_TL0C_rxLen(void){
if(tl0C.sRecvHead==tl0C.sRecvTail){
return 0;
}
else if(tl0C.sRecvTail>tl0C.sRecvHead){
return (tl0C.sRecvTail-tl0C.sRecvHead);
}
else{
return ( TL_RECV_LEN-(tl0C.sRecvHead-tl0C.sRecvTail) );
}
}
inline int get_TL0D_rxLen(void){
if(tl0D.sRecvHead==tl0D.sRecvTail){
return 0;
}
else if(tl0D.sRecvTail>tl0D.sRecvHead){
return (tl0D.sRecvTail-tl0D.sRecvHead);
}
else{
return ( TL_RECV_LEN-(tl0D.sRecvHead-tl0D.sRecvTail) );
}
}
inline int get_TL0A_txLen(void){
if(tl0A.sSendHead==tl0A.sSendTail){
return 0;
}
else if(tl0A.sSendTail>tl0A.sSendHead){
return (tl0A.sSendTail-tl0A.sSendHead);
}
else{
return ( TL_SEND_LEN-(tl0A.sSendHead-tl0A.sSendTail) );
}
}
inline int get_TL0B_txLen(void){
if(tl0B.sSendHead==tl0B.sSendTail){
return 0;
}
else if(tl0B.sSendTail>tl0B.sSendHead){
return (tl0B.sSendTail-tl0B.sSendHead);
}
else{
return ( TL_SEND_LEN-(tl0B.sSendHead-tl0B.sSendTail) );
}
}
inline int get_TL0C_txLen(void){
if(tl0C.sSendHead==tl0C.sSendTail){
return 0;
}
else if(tl0C.sSendTail>tl0C.sSendHead){
return (tl0C.sSendTail-tl0C.sSendHead);
}
else{
return ( TL_SEND_LEN-(tl0C.sSendHead-tl0C.sSendTail) );
}
}
inline int get_TL0D_txLen(void){
if(tl0D.sSendHead==tl0D.sSendTail){
return 0;
}
else if(tl0D.sSendTail>tl0D.sSendHead){
return (tl0D.sSendTail-tl0D.sSendHead);
}
else{
return ( TL_SEND_LEN-(tl0D.sSendHead-tl0D.sSendTail) );
}
}
inline char tl0aIsEmpty_rx(void){
return (tl0A.sRecvHead==tl0A.sRecvTail ? 1 : 0);
}
inline char tl0bIsEmpty_rx(void){
return (tl0B.sRecvHead==tl0B.sRecvTail ? 1 : 0);
}
inline char tl0cIsEmpty_rx(void){
return (tl0C.sRecvHead==tl0C.sRecvTail ? 1 : 0);
}
inline char tl0dIsEmpty_rx(void){
return (tl0D.sRecvHead==tl0D.sRecvTail ? 1 : 0);
}
inline char tl0aIsFull_rx(void){
return (tl0A.sRecvHead==(tl0A.sRecvTail+1)%TL_RECV_LEN ? 1 : 0);
}
inline char tl0bIsFull_rx(void){
return (tl0B.sRecvHead==(tl0B.sRecvTail+1)%TL_RECV_LEN ? 1 : 0);
}
inline char tl0cIsFull_rx(void){
return (tl0C.sRecvHead==(tl0C.sRecvTail+1)%TL_RECV_LEN ? 1 : 0);
}
inline char tl0dIsFull_rx(void){
return (tl0D.sRecvHead==(tl0D.sRecvTail+1)%TL_RECV_LEN ? 1 : 0);
}
inline char tl0aIsEmpty_tx(void){
return (tl0A.sSendHead==tl0A.sSendTail ? 1 : 0);
}
inline char tl0bIsEmpty_tx(void){
return (tl0B.sSendHead==tl0B.sSendTail ? 1 : 0);
}
inline char tl0cIsEmpty_tx(void){
return (tl0C.sSendHead==tl0C.sSendTail ? 1 : 0);
}
inline char tl0dIsEmpty_tx(void){
return (tl0D.sSendHead==tl0D.sSendTail ? 1 : 0);
}
inline char tl0aIsFull_tx(void){
return (tl0A.sSendHead==(tl0A.sSendTail+1)%TL_SEND_LEN ? 1 : 0);
}
inline char tl0bIsFull_tx(void){
return (tl0B.sSendHead==(tl0B.sSendTail+1)%TL_SEND_LEN ? 1 : 0);
}
inline char tl0cIsFull_tx(void){
return (tl0C.sSendHead==(tl0C.sSendTail+1)%TL_SEND_LEN ? 1 : 0);
}
inline char tl0dIsFull_tx(void){
return (tl0D.sSendHead==(tl0D.sSendTail+1)%TL_SEND_LEN ? 1 : 0);
}
inline void pushTL0ARX(unsigned char byRx){//缓冲区满时, 最后一个接收数据放在最后一个位置
tl0A.abyRecvData[tl0A.sRecvTail] = byRx;
if(!tl0aIsFull_rx()){
tl0A.sRecvTail++;
tl0A.sRecvTail %= TL_RECV_LEN;
}
}
inline void pushTL0BRX(unsigned char byRx){//缓冲区满时, 最后一个接收数据放在最后一个位置
tl0B.abyRecvData[tl0B.sRecvTail] = byRx;
if(!tl0bIsFull_rx()){
tl0B.sRecvTail++;
tl0B.sRecvTail %= TL_RECV_LEN;
}
}
inline void pushTL0CRX(unsigned char byRx){//缓冲区满时, 最后一个接收数据放在最后一个位置
tl0C.abyRecvData[tl0C.sRecvTail] = byRx;
if(!tl0cIsFull_rx()){
tl0C.sRecvTail++;
tl0C.sRecvTail %= TL_RECV_LEN;
}
}
inline void pushTL0DRX(unsigned char byRx){//缓冲区满时,
- 1
- 2
前往页