📄 tl16c554_linux.c
字号:
/* * tl16c554.c * * TL16C554 driver for SAMSUNG S3C2410 * * Author: Yongping wu <godiscrazy@163.com> * Date : $Date: 2006/03/14 16:13:04 $ * * $Revision: 1.1V $ *TL16C554APN3.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 1UART0B:0x2800_2000---0x2800_2003;0x2880_2000---0x2880_2003UART0C:0x2800_4000---0x2800_4003;0x2880_4000---0x2880_4003UART0D:0x2800_6000---0x2800_6003;0x2880_6000---0x2880_6003UART1A:0x2800_8000---0x2800_8003;0x2880_8000---0x2880_8003UART1B:0x2800_A000---0x2800_A003;0x2880_A000---0x2880_A003UART1C:0x2800_C000---0x2800_C003;0x2880_C000---0x2880_C003UART1D:0x2800_E000---0x2800_E003;0x2880_E000---0x2880_E003控制寄存器Line-control register(LCR)0x03FIFO-control register(FCR)0x02Modem-control register(MCR)0x04Divisor-latch LSB(DLL)LCR(bit7=1)0x00Divisor-latch MSB(DLM)LCR(bit7=1)0x01Interrupt enable register(IER)0x01状态寄存器Line-status register(LSR)0x05Modem-status register(MSR)0x06数据寄存器Receiver-buffer register(RBR)0x00Transmitter-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 34typedef 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 160typedef 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 3static 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){//缓冲区满时, 最后一个接收数据放在最后一个位置 tl0D.abyRecvData[tl0D.sRecvTail] = byRx; if(!tl0dIsFull_rx()){ tl0D.sRecvTail++; tl0D.sRecvTail %= TL_RECV_LEN; }}inline unsigned char tl0apopRX(void){//为空时返回最后接收到的一个数据,从未接收到数据时返回缓冲区第一个字节数据 unsigned char byRet; byRet = tl0A.abyRecvData[tl0A.sRecvHead]; if(!tl0aIsEmpty_rx()){ tl0A.sRecvHead++; tl0A.sRecvHead %= TL_RECV_LEN; } return byRet;}inline unsigned char tl0bpopRX(void){//为空时返回最后接收到的一个数据,从未接收到数据时返回缓冲区第一个字节数据 unsigned char byRet; byRet = tl0B.abyRecvData[tl0B.sRecvHead]; if(!tl0bIsEmpty_rx()){ tl0B.sRecvHead++; tl0B.sRecvHead %= TL_RECV_LEN; } return byRet;}inline unsigned char tl0cpopRX(void){//为空时返回最后接收到的一个数据,从未接收到数据时返回缓冲区第一个字节数据 unsigned char byRet; byRet = tl0C.abyRecvData[tl0C.sRecvHead]; if(!tl0cIsEmpty_rx()){ tl0C.sRecvHead++; tl0C.sRecvHead %= TL_RECV_LEN; } return byRet;}inline unsigned char tl0dpopRX(void){//为空时返回最后接收到的一个数据,从未接收到数据时返回缓冲区第一个字节数据 unsigned char byRet; byRet = tl0D.abyRecvData[tl0D.sRecvHead]; if(!tl0dIsEmpty_rx()){ tl0D.sRecvHead++; tl0D.sRecvHead %= TL_RECV_LEN; } return byRet;}//TL16C554初始化void Init_TL0A(int nBaud, unsigned char byMode){ volatile unsigned char byRx; int i; if(0 != tl0A.sInited){ iounmap((void *) (tl0A.pbyBase0)); iounmap((void *) (tl0A.pbyBase1)); } tl0A.pbyBase0 = (unsigned char *)ioremap_nocache(tl0A.nAddress0, 4); tl0A.pbyBase1 = (unsigned char *)ioremap_nocache(tl0A.nAddress1, 4); tl0A.RBR = (int)(tl0A.pbyBase0); tl0A.THR = (int)(tl0A.pbyBase0); tl0A.LSR = (int)(tl0A.pbyBase1+1); tl0A.MSR = (int)(tl0A.pbyBase1+2); tl0A.LCR = (int)(tl0A.pbyBase0+3); tl0A.FCR = (int)(tl0A.pbyBase0+2); tl0A.MCR = (int)(tl0A.pbyBase1); tl0A.DLL = (int)(tl0A.pbyBase0); tl0A.DLM = (int)(tl0A.pbyBase0+1); tl0A.IER = (int)(tl0A.pbyBase0+1); tl0A.SPR = (int)(tl0A.pbyBase1+3); tl0A.IIR = (int)(tl0A.pbyBase0+2); tl0A.sRecvHead = 0; tl0A.sRecvTail = 0; tl0A.sSendHead = 0; tl0A.sSendTail = 0; //IER //接收保持和中断允许 *(volatile unsigned char *)(tl0A.IER) = 0x01;//0x05; //FIFO控制器 //set FCR.FIFO允许,RXD复位,TXD复位,DMAmode=1,触发为14 *(volatile unsigned char *)(tl0A.FCR) = 0xcf; for(i=0; i<100; i++); //set FCR.RXD复位,TXD复位 *(volatile unsigned char *)(tl0A.FCR) = 0xc9; //Modem状态 //set MCR.中断A-D开 *(volatile unsigned char *)(tl0A.MCR) = 0x08; if(byMode&0x80){ *(volatile unsigned char *)(tl0A.LCR) = 0x82|(byMode&0x7f);//7 bit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -