📄 serial_vk32xx.c
字号:
/*
* VKIC Co. Ltd. 2007
* By Huangwei
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/serial_core.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include "serial_vk32xx.h"
static void vk32xx_tx_chars(struct uart_info *info);
inline void setup_spi(void)
{
SPCON0=SPCON_MSTR|SPCON_ENSCK;
//config SPPIN
//USE DEFAULT VALLUE
//config the baud rate register SPPRE
SPPRE0=0x04;//set bandrate
//0x0f->2.1M Hz
//0x08->3.7M Hz
//0x04->6.67M Hz
write_gpio_bit(VK32_CS,1);
}
uint8_t spi_send_byte(uint8_t dat)
{
write_gpio_bit(VK32_CS,0);
SPTDAT0=dat;
while(!(SPSTA0&SPSTA_READY));
write_gpio_bit(VK32_CS,1);
return SPRDAT0;
}
void vk3xxx_write_reg(uint8_t port,uint8_t reg,uint8_t dat)
{
spi_send_byte(0x80|((port-1)<<5)|(reg<<1));
spi_send_byte(dat);
}
uint8_t vk3xxx_read_reg(uint8_t port,uint8_t reg)
{
spi_send_byte(((port-1)<<5)+(reg<<1));
return spi_send_byte(0x00);
}
static struct tty_driver normal, callout;
static struct tty_struct *vk32xx_table[NR_PORTS];
static struct termios *vk32xx_termios[NR_PORTS], *vk32xx_termios_locked[NR_PORTS];
//static int (*vk32xx_open)(struct uart_port *, struct uart_info *);
static void (*vk32xx_close)(struct uart_port *, struct uart_info *);
/*
* interrupts disabled on entry
*/
static void vk32xx_stop_tx(struct uart_port *port, u_int from_tty)
{
//disable the interrupt,clear the corresponding bit in GIR
uint8_t sier;
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);
sier&=~VK32XX_TRIEN;
vk3xxx_write_reg(port->iobase,VK32XX_SIER,sier);
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_stop_tx\n");
#endif
}
/*
* interrupts may not be disabled on entry
*/
static void vk32xx_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
{
struct uart_info * info =(struct uart_info *)(port->membase);
// printk(KERN_ALERT "vk32xx_start_tx\n");
if (nonempty) {
//unsigned long flags;
uint8_t sier;
#ifdef _DEBUG_VK32XX
uint8_t gir,sier,sifr;
printk(KERN_ALERT "VK32XX_start_tx nonempty\n");
#endif
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);
sier|=VK32XX_TRIEN;
vk3xxx_write_reg(port->iobase,VK32XX_SIER,sier);
#ifdef _DEBUG_VK32XX
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);
// sifr|=TFINT;
// vk3xxx_write_reg(port->iobase,SIFR,sifr);
// sifr=vk3xxx_read_reg(port->iobase,SIFR);
// printk(KERN_ALERT "sifr:%x\n",sifr);
gir=vk3xxx_read_reg(port->iobase,VK32XX_GIR);
sifr=vk3xxx_read_reg(port->iobase,VK32XX_SIFR);
printk(KERN_ALERT "gir:%x sifr:%x sier:%x\n",gir,sifr,sier);
//local_irq_restore(flags);
#endif
// vk32xx_tx_chars(info);
enable_irq(port->irq);
}
}
/*
* Interrupts enabled
*/
static void vk32xx_stop_rx(struct uart_port *port)
{
//disable the rx interrupt
uint8_t sier;
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "stop_rx\n");
#endif
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);
sier&=~VK32XX_RFIEN;
vk3xxx_write_reg(port->iobase,VK32XX_SIER,sier);
}
/*
* No modem control lines
*/
static void vk32xx_enable_ms(struct uart_port *port) //nothing
{
}
static void
vk32xx_rx_chars(struct uart_info *info, struct pt_regs *regs)
{
uint8_t ssr;
struct tty_struct *tty = info->tty;
unsigned int ch, flg, ignored = 0;
struct uart_port *port = info->port;
//得到状态
//此处需要得到SSR值
#ifdef _DEBUG_VK32XX1
printk(KERN_ALERT "vk32xx_rx_chars()\n");
#endif
ssr=vk3xxx_read_reg(port->iobase,VK32XX_SSR);
while (!(ssr& VK32XX_RFEM)){//接收FIFO不空
ch =vk3xxx_read_reg(port->iobase,VK32XX_SFDR); ;//得到一个字符的数据
if (tty->flip.count >= TTY_FLIPBUF_SIZE){
printk(KERN_ALERT "1\n");
goto ignore_char;
}
port->icount.rx++;
#ifdef _DEBUG_VK32XX1
printk(KERN_ALERT __FUNCTION__ "icount.rx:%d\n",port->icount.rx);
#endif
flg = TTY_NORMAL;
/*
* note that the error handling code is
* out of the main execution path
*/
if (ssr&(VK32XX_OE|VK32XX_FE|VK32XX_PE)){//是否有错
printk(KERN_ALERT "2\n");
goto handle_error;
}
if (uart_handle_sysrq_char(info, ch, regs))
goto ignore_char;
error_return:
*tty->flip.flag_buf_ptr++ = flg;
*tty->flip.char_buf_ptr++ = ch;
tty->flip.count++;
#ifdef _DEBUG_VK32XX1
printk(KERN_ALERT __FUNCTION__ " flip.count:%d char:%d\n",tty->flip.count,ch);
#endif
ignore_char:
ssr=vk3xxx_read_reg(port->iobase,VK32XX_SSR);//得到更新的状态
}
out:
tty_flip_buffer_push(tty);
return;
handle_error:
if (ssr & VK32XX_PE)//检查是哪种错误, 并对其进行计数
port->icount.parity++;
if (ssr & VK32XX_FE)
port->icount.frame++;
if (ssr & VK32XX_OE)
port->icount.overrun++;
//if (ssr & port->ignore_status_mask) {//忽略它并计数
//!!!!此处mask没有实现, 则只要有错全部忽略
if (++ignored > 100)
goto out;
goto ignore_char;
#ifdef SUPPORT_SYSRQ
info->sysrq = 0;
#endif
goto error_return;
}
static void vk32xx_tx_chars(struct uart_info *info)
{
struct uart_port * port = info->port;
uint8_t ssr;
printk(KERN_ALERT "tx_chars\n");
if (port->x_char) {
//向FIFO写入一个数据
vk3xxx_write_reg(port->iobase,VK32XX_SFDR,port->x_char);
port->icount.tx++;
port->x_char = 0;
return;
}
if (info->xmit.head == info->xmit.tail
|| info->tty->stopped
|| info->tty->hw_stopped) {
vk32xx_stop_tx(info->port, 0);
return;
}
/*
* Tried using FIFO (not checking TNF) for fifo fill:
* still had the '4 bytes repeated' problem.
*/
ssr=vk3xxx_read_reg(port->iobase,VK32XX_SSR);
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "ssr:%x\n",ssr);
#endif
while (!(ssr & VK32XX_TFFL)){//发送FIFO为空则继续发
//printk(KERN_ALERT "sending\n");
// printk(KERN_ALERT "tx char:%d\n",info->xmit.buf[info->xmit.tail]);
vk3xxx_write_reg(port->iobase,VK32XX_SFDR,info->xmit.buf[info->xmit.tail]);
info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
#ifdef _DEBUG_VK32XX1
printk(KERN_ALERT "xmit.head:%d,xmit.tail:%d,char:%d\n",info->xmit.head,info->xmit.tail,info->xmit.buf[info->xmit.tail]);
#endif
if (info->xmit.head == info->xmit.tail)
break;
ssr=vk3xxx_read_reg(port->iobase,VK32XX_SSR);
}
printk(KERN_ALERT "ssr:%x\n",ssr);
if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) <
WAKEUP_CHARS)
uart_event(info, EVT_WRITE_WAKEUP);
if (info->xmit.head == info->xmit.tail)
vk32xx_stop_tx(info->port, 0);
}
static void vk32xx_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct uart_info *info = dev_id;
struct uart_port *port = info->port;
unsigned int pass_counter = 0;
uint8_t sifr,gir,sier;
gir=vk3xxx_read_reg(port->iobase,VK32XX_GIR);
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_int()gir:%x\n",gir);
#endif
switch(port->iobase){
case 1 :
if(!(gir & VK32XX_U1IF))//这个子通道没有中断
return;
break;
case 2 :
if(!(gir & VK32XX_U2IF))//这个子通道没有中断
return;
break;
case 3 :
if(!(gir & VK32XX_U3IF))//这个子通道没有中断
return;
break;
case 4 :
if(!(gir & VK32XX_U4IF))//这个子通道没有中断
return;
break;
default:
break;
}
sifr=vk3xxx_read_reg(port->iobase,VK32XX_SIFR);//读取状态判断是哪里产生的中断。对vk32读取SIFR
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);//读取状态判断是哪里产生的中断。对vk32读取SIFR
//这里mask没有实现,则不需要屏蔽
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_int()sifr:%x sier:%x \n",sifr,sier);
#endif
do {
if (sifr&VK32XX_RFINT) {//是否发送中断
printk(KERN_ALERT " in inttrupt rx_chars\n");
vk32xx_rx_chars(info, regs);
}
if ((sifr & VK32XX_TFINT)&&(sier & VK32XX_TRIEN)){
printk(KERN_ALERT " int tx_char\n");
vk32xx_tx_chars(info);
}
if (pass_counter++ > VK32XX_ISR_PASS_LIMIT)
break;
sifr=vk3xxx_read_reg(port->iobase,VK32XX_SIFR);
sier=vk3xxx_read_reg(port->iobase,VK32XX_SIER);//读取状态判断是哪里产生的中断。对vk32读取SIFR
printk(KERN_ALERT "af rd sifr:%x sier:%x\n",sifr,sier);
} while ((sifr & VK32XX_RFINT)||((sifr & VK32XX_TFINT)&&(sier & VK32XX_TRIEN)));
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "sifr:%d\n",sifr);
#endif
}
/*
* Return TIOCSER_TEMT when transmitter is not busy.
*/
static u_int vk32xx_tx_empty(struct uart_port *port)// or query the tx fifo is not empty?
{
uint8_t ssr;
#ifdef _DEBUG_VK32XX
printk(KERN_ALERT "vk32xx_tx_empty\n");
#endif
ssr=vk3xxx_read_reg(port->iobase,VK32XX_SSR);
return ssr & VK32XX_TFEM ? 0 : TIOCSER_TEMT;
}
static u_int vk32xx_get_mctrl(struct uart_port *port)// since no modem control line
{
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
}
static void vk32xx_set_mctrl(struct uart_port *port, u_int mctrl)//nothing
{
}
/*
* Interrupts always disabled.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -