IMX6下移植WKxxx驱动
wkXXX.c
#include<linux/init.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 <linux/delay.h> #include <linux/err.h> #include <linux/freezer.h> #include <linux/spi/spi.h> #include <linux/timer.h> #include <linux/gpio.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/platform_device.h> //#include <mach/map.h> #include <asm/irq.h> #include <asm/io.h> #include "wk2166.h" /************硬件相关***************/ #include <mach/iomux-mx6q.h> #define wk2166_irq IMX_GPIO_NR(7,6)// probe里做其他初始化 #define wk2166__cs IMX_GPIO_NR(5,29)//IMX_GPIO_NR(7,2) MODULE_LICENSE("Dual BSD/GPL"); #define SPI_BUFSIZ max(32,SMP_CACHE_BYTES) //#define _DEBUG_WK2XXX //#define _DEBUG_WK2XXX1 //#define _DEBUG_WK2XXX2 //#define _DEBUG_WK2XXX4 //#define _DEBUG_tla001 //#define _DEBUG_rx #define CONFIG_DEVFS_FS #define WK2XXX_PAGE1 1 #define WK2XXX_PAGE0 0 #define WK2XXX_STATUS_PE 1 #define WK2XXX_STATUS_FE 2 #define WK2XXX_STATUS_BRK 4 #define WK2XXX_STATUS_OE 8 static DEFINE_MUTEX(wk2xxxs_lock); /* race on probe */ static DEFINE_MUTEX(wk2xxs_work_lock); /* work on probe */ static DEFINE_MUTEX(wk2xxs_spi_lock); /* spi read & write */ struct wk2xxx_port { //struct timer_list mytimer; struct uart_port port;//[NR_PORTS]; struct spi_device *spi_wk; spinlock_t conf_lock; /* shared data */ struct workqueue_struct *workqueue; struct work_struct work; int suspending; void (*wk2xxx_hw_suspend) (int suspend); int tx_done; int force_end_work; int irq; int minor; /* minor number */ int tx_empty; int tx_empty_flag; //int start_tx; int start_tx_flag; int stop_tx_flag; int stop_rx_flag; int irq_flag; int conf_flag; int tx_empty_fail; int start_tx_fail; int stop_tx_fail; int stop_rx_fail; int irq_fail; int conf_fail; /* int work_tx_empty_flag; int work_start_tx_flag; int work_stop_rx_flag; int work_stop_tx_flag; int work_irq_flag; //int work_irq_fail; int work_conf_flag; */ uint8_t new_lcr; uint8_t new_scr; /*set baud 0f register*/ uint8_t new_baud1; uint8_t new_baud0; uint8_t new_pres; }; static struct wk2xxx_port wk2xxxs[NR_PORTS]; /* the chips */ static int wk2xxx_read_reg(struct spi_device *spi,uint8_t port,uint8_t reg,uint8_t *dat) { struct spi_message msg; uint8_t buf_wdat[2]; uint8_t buf_rdat[2]; int status; mutex_lock(&wk2xxs_spi_lock); struct spi_transfer index_xfer = { .len = 2, .cs_change = 1, }; status =0; __gpio_set_value(wk2166__cs,0); spi_message_init(&msg); buf_wdat[0] = 0x40|(((port-1)<<4)|reg); buf_wdat[1] = 0x00; buf_rdat[0] = 0x00; buf_rdat[1] = 0x00; index_xfer.tx_buf = buf_wdat; index_xfer.rx_buf =(void *) buf_rdat; spi_message_add_tail(&index_xfer, &msg); status = spi_sync(spi, &msg); udelay(5); if(status) { return status; } *dat = buf_rdat[1]; __gpio_set_value(wk2166__cs,1); mutex_unlock(&wk2xxs_spi_lock); return 0; } static int wk2xxx_write_reg(struct spi_device *spi,uint8_t port,uint8_t reg,uint8_t dat) { struct spi_message msg; uint8_t buf_reg[2]; int status; mutex_lock(&wk2xxs_spi_lock); struct spi_transfer index_xfer = { .len = 2, .cs_change = 1, }; __gpio_set_value(wk2166__cs,0); spi_message_init(&msg); /* register index */ buf_reg[0] = ((port-1)<<4)|reg; buf_reg[1] = dat; index_xfer.tx_buf = buf_reg; spi_message_add_tail(&index_xfer, &msg); status = spi_sync(spi, &msg); udelay(5); if(status) { return status; } __gpio_set_value(wk2166__cs,1); mutex_unlock(&wk2xxs_spi_lock); return status; } static void wk2xxxirq_app(struct uart_port *port);// static void conf_wk2xxx_subport(struct uart_port *port);// static void wk2xxx_work(struct work_struct *w); static void wk2xxx_stop_tx(struct uart_port *port);// static u_int wk2xxx_tx_empty(struct uart_port *port);// or query the tx fifo is not empty? static int wk2xxx_dowork(struct wk2xxx_port *s) { #ifdef _DEBUG_WK2XXX printk("--wk2xxx_dowork---in---\n"); #endif if (!s->force_end_work && !work_pending(&s->work) && !freezing(current) && !s->suspending) { queue_work(s->workqueue, &s->work);// #ifdef _DEBUG_WK2XXX printk("--queue_work---ok---\n"); printk("--wk2xxx_dowork---exit---\n"); // printk("work_pending =: %d s->force_end_work = : %d freezing(current) = :%d s->suspending= :%d\n" ,work_pending(&s->work),s->force_end_work ,freezing(current),s->suspending); #endif return 1; } else { #ifdef _DEBUG_WK2XXX printk("--queue_work---error---\n"); printk("--wk2xxx_dowork---exit---\n"); #endif //printk("work_pending =: %d s->force_end_work = : %d freezing(current) = :%d s->suspending= :%d\n" ,work_pending(&s->work),s->force_end_work ,freezing(current),s->suspending); // return 0; // printk("work_pending() =: %d tx_empty_flag = : %d start_tx_flag = :%d stop_tx_flag = :%d conf_flag =: %d irq_flag =: %d tx_empty=:%d\n",work_pending(&s->work),s->tx_empty_flag,s->start_tx_flag,s->stop_tx_flag,s->stop_rx_flag,s->conf_flag,s->irq_flag,s->tx_empty); return 0; } } static void wk2xxx_work(struct work_struct *w) { #ifdef _DEBUG_WK2XXX printk("--wk2xxx_work---in---\n"); #endif struct wk2xxx_port *s = container_of(w, struct wk2xxx_port, work); uint8_t rx; int work_tx_empty_flag; int work_start_tx_flag; int work_stop_rx_flag; int work_stop_tx_flag; int work_irq_flag; //int work_irq_fail; int work_conf_flag; do { mutex_lock(&wk2xxs_work_lock); //spin_lock(&s->conf_lock); /*work_tx_empty_flag = s->tx_empty_flag; if(work_tx_empty_flag) s->tx_empty_flag = 0;*/ work_start_tx_flag = s->start_tx_flag; if(work_start_tx_flag) s->start_tx_flag = 0; /*work_stop_tx_flag = s->stop_tx_flag; if(work_stop_tx_flag) s->stop_tx_flag = 0;*/ work_stop_rx_flag = s->stop_rx_flag; if(work_stop_rx_flag) s->stop_rx_flag = 0; work_conf_flag = s->conf_flag; if(work_conf_flag) s->conf_flag = 0; work_irq_flag = s->irq_flag; if(work_irq_flag) s->irq_flag = 0; //work_irq_fail = s->irq_fail; //if(work_irq_fail) //s->irq_fail = 0; //spin_unlock(&s->conf_lock); mutex_unlock(&wk2xxs_work_lock); if(work_conf_flag) { conf_wk2xxx_subport(&s->port); } /*if(work_tx_empty_flag) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,&rx); s->tx_empty = (rx & WK2XXX_TDAT)<=0; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "s->tx_empty_fail----FSR:%d--s->tx_empty:%d--\n",rx,s->tx_empty); #endif }*/ if(work_start_tx_flag) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx |= WK2XXX_TFTRIG_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); } /* if(work_stop_tx_flag) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx &=~WK2XXX_TFTRIG_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_TFTRIG_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); }*/ if(work_stop_rx_flag) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "stop_rx_flag----SIER:%d--\n",rx); #endif rx &=~WK2XXX_RFTRIG_IEN; rx &=~WK2XXX_RXOUT_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "stop_rx_flag----SIFR:%d--\n",rx); #endif wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_RFTRIG_INT; rx &= ~WK2XXX_RXOVT_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "stop_rx_flag----SIFR:%d--\n",rx); #endif } if(work_irq_flag) { wk2xxxirq_app(&s->port); s->irq_fail = 1; } }while (!s->force_end_work && !freezing(current) && \ (work_irq_flag || work_stop_rx_flag || \ work_stop_tx_flag || work_tx_empty_flag || work_conf_flag)); /* }while (!s->force_end_work && !freezing(current) && \ ((s->work_irq_flag != s->irq_flag) ||\ (s->work_stop_rx_flag != s->stop_rx_flag) ||\ (s->work_stop_tx_flag != s->stop_tx_flag) ||\ (s->work_tx_empty_flag != s->tx_empty_flag) ||\ (s->work_conf_flag != s->conf_flag))); */ #ifdef _DEBUG_WK2XXX printk("-----exit------- work ------\n"); #endif if(s->conf_fail) { conf_wk2xxx_subport(&s->port); s->conf_fail =0; } /*if(s->tx_empty_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,&rx); s->tx_empty = (rx & WK2XXX_TDAT) == 0; s->tx_empty_fail =0; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "s->tx_empty_fail----FSR:%d--s->tx_empty:%d--s->tx_empty_fail :%d--\n",rx,s->tx_empty,s->tx_empty_fail ); #endif }*/ if(s->start_tx_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx |= WK2XXX_TFTRIG_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); s->start_tx_fail =0; } /* if(s->stop_tx_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx &=~WK2XXX_TFTRIG_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_TFTRIG_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); s->stop_tx_fail =0; }*/ if(s->stop_rx_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx &=~WK2XXX_RFTRIG_IEN; rx &=~WK2XXX_RXOUT_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_RFTRIG_INT; rx &= ~WK2XXX_RXOVT_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); s->stop_rx_fail =0; } if(s->irq_fail) { s->irq_fail = 0; enable_irq(s->port.irq); //s->irq_fail = 0; } //printk("work_pending() =: %d tx_empty_flag = : %d start_tx_flag = :%d stop_tx_flag = :%d conf_flag =: %d irq_flag =: %d tx_empty=:%d\n",work_pending(&s->work),s->tx_empty_flag,s->start_tx_flag,s->stop_tx_flag,s->stop_rx_flag,s->conf_flag,s-> irq_flag,s->tx_empty); #ifdef _DEBUG_WK2XXX printk("--wk2xxx_work---exit---\n"); #endif //mutex_unlock(&wk2xxs_work_lock); } static void wk2xxx_rx_chars(struct uart_port *port)//vk32xx_port *port) { #ifdef _DEBUG_rx printk(KERN_ALERT "wk2xxx_rx_chars()---------in---\n"); #endif struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); uint8_t fsr,lsr,dat[1]; unsigned int ch, flg, ignored=0,status = 0,rx_count=0; #ifdef _DEBUG_tla001 int i; for(i=1;i<5;i++) { wk2xxx_write_reg(s->spi_wk,i,WK2XXX_SPAGE,WK2XXX_PAGE0); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_GENA,dat); printk(KERN_ALERT "Port%d WK2XXX_GENA****0x%x\n",i,dat[0]); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_SIER,dat); printk(KERN_ALERT "Port%d WK2XXX_SIER****0x%x\n",i,dat[0]); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_SIFR,dat); printk(KERN_ALERT "Port%d WK2XXX_SIFR****0x%x\n",i,dat[0]); wk2xxx_write_reg(s->spi_wk,i,WK2XXX_SPAGE,WK2XXX_PAGE1); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_BAUD1,dat); printk(KERN_ALERT "Port%d WK2XXX_BAUD1****0x%x\n",i,dat[0]); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_BAUD0,dat); printk(KERN_ALERT "Port%d WK2XXX_BAUD0****0x%x\n",i,dat[0]); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_RFTL,dat); printk(KERN_ALERT "Port%d WK2XXX_RFTL****0x%x\n",i,dat[0]); wk2xxx_read_reg(s->spi_wk,i,WK2XXX_TFTL,dat); printk(KERN_ALERT "Port%d WK2XXX_TFTL****0x%x\n\n",i,dat[0]); } #endif wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0 wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_LSR,dat); lsr = dat[0]; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "wk2xxx_rx_chars()----port:%d--fsr:%d--lsr:%d--\n",s->port.iobase,fsr,lsr); #endif while (fsr& WK2XXX_RDAT)/**/ { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FDAT,dat); ch = (int)dat[0]; #ifdef _DEBUG_WK2XXX4 printk(KERN_ALERT "wk2xxx_rx_chars()----port:%d--RXDAT:0x%x----\n",s->port.iobase,ch); #endif s->port.icount.rx++; //rx_count++; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "icount.rx:%d\n",s->port.icount.rx); #endif flg = TTY_NORMAL; if (lsr&(WK2XXX_OE |WK2XXX_FE|WK2XXX_PE|WK2XXX_BI)) { printk(KERN_ALERT "all err\n"); //goto handle_error; if (lsr & WK2XXX_PE) { s->port.icount.parity++; status |= WK2XXX_STATUS_PE; flg = TTY_PARITY; } if (lsr & WK2XXX_FE) { s->port.icount.frame++; status |= WK2XXX_STATUS_FE; flg = TTY_FRAME; } if (lsr & WK2XXX_OE) { s->port.icount.overrun++; status |= WK2XXX_STATUS_OE; flg = TTY_OVERRUN; } if(lsr&fsr & WK2XXX_BI) { s->port.icount.brk++; status |= WK2XXX_STATUS_BRK; flg = TTY_BREAK; } if (++ignored > 100) goto out; goto ignore_char; } error_return: if (uart_handle_sysrq_char(&s->port,ch))//.state, ch)) goto ignore_char; uart_insert_char(&s->port, status, WK2XXX_STATUS_OE, ch, flg); rx_count++; if ((rx_count >= 8 ) && (s->port.state->port.tty != NULL)) { tty_flip_buffer_push(s->port.state->port.tty); rx_count = 0; } #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT " s->port.icount.rx = 0x%X char = 0x%X flg = 0x%X port = %d rx_count = %d\n",s->port.icount.rx,ch,flg,s->port.iobase,rx_count); #endif ignore_char: wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_LSR,dat); lsr = dat[0]; } out: if((rx_count > 0)&&(s->port.state->port.tty != NULL)) { #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "push buffer tty flip port = :%d count = :%d\n",s->port.iobase,rx_count); #endif tty_flip_buffer_push(s->port.state->port.tty); } #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "wk2xxx_rx_chars()---------out---\n"); #endif return; #ifdef SUPPORT_SYSRQ s->port.state->sysrq = 0; #endif goto error_return; #ifdef _DEBUG_rx printk("--wk2xxx_rx_chars---exit---\n"); #endif } static void wk2xxx_tx_chars(struct uart_port *port)// { #ifdef _DEBUG_WK2XXX4 printk("--wk2xxx_tx_chars---in---\n"); #endif struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); uint8_t fsr,dat[1]; int count; #ifdef _DEBUG_WK2XXX printk(KERN_ALERT " in wk2xxx_tx_chars()\n"); #endif if (s->port.x_char) { wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_FDAT,s->port.x_char); s->port.icount.tx++; s->port.x_char = 0; goto out; //return; } if(uart_circ_empty(&s->port.state->xmit) || uart_tx_stopped(&s->port)) { //wk2xxx_stop_tx(&s->port); goto out; //return; } /* * Tried using FIFO (not checking TNF) for fifo fill: * still had the '1 bytes repeated' problem. */ wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "fsr:%x\n",fsr); #endif //count = s->port.fifosize / 2; count = s->port.fifosize; //count = 64; do { if((fsr & WK2XXX_TFULL)|uart_circ_empty(&s->port.state->xmit)) goto out; // break; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_FDAT,s->port.state->xmit.buf[s->port.state->xmit.tail]); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_tx_chars()----port:%d--TXDAT:0x%x----\n",s->port.iobase,s->port.state->xmit.buf[s->port.state->xmit.tail]); #endif //udelay(1000); s->port.state->xmit.tail = (s->port.state->xmit.tail + 1) & (UART_XMIT_SIZE - 1); s->port.icount.tx++; #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "xmit.head:%d,xmit.tail:%d,char:%d,fsr:0x%X,port = %d\n",s->port.state->xmit.head,s->port.state->xmit.tail,s->port.state->xmit.buf[s->port.state->xmit.tail],fsr,s->port.iobase); #endif wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; }while(--count>0); #ifdef _DEBUG_WK2XXX do { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; }while(fsr&WK2XXX_TDAT>0); printk(KERN_ALERT "tx_char --fsr:0x%X,port = %d\n",fsr,s->port.iobase); #endif out:wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); fsr = dat[0]; //printk(KERN_ALERT "tx_char --fsr:0x%X,port = %d\n",fsr,s->port.iobase); if((fsr&WK2XXX_TDAT)==0) { //printk(KERN_ALERT "tx_char1 --fsr:0x%X,port = %d\n",fsr,s->port.iobase); if (uart_circ_chars_pending(&s->port.state->xmit) < WAKEUP_CHARS) uart_write_wakeup(&s->port); if (uart_circ_empty(&s->port.state->xmit)) { wk2xxx_stop_tx(&s->port); } } #ifdef _DEBUG_WK2XXX printk("--wk2xxx_tx_chars---exit---\n"); #endif } static irqreturn_t wk2xxx_irq(int irq, void *dev_id)// { #ifdef _DEBUG_WK2XXX printk("--wk2xxx_irq---in---\n"); #endif struct wk2xxx_port *s = dev_id; //char sier; disable_irq_nosync(s->port.irq); //s->irq_fail=1; //s->irq_flag = 1; //mutex_unlock(&vk32xxs_work_lock); //vk32xx_dowork(s); if(wk2xxx_dowork(s)) { //disable_irq_nosync(s->port.irq); //if(!s->irq_fail) //{ s->irq_flag = 1; #ifdef _DEBUG_tla00 printk(KERN_ALERT "****** irq_flag=1*****\n"); #endif //s->irq_fail = 0; //} } else { //if(!s->irq_flag) s->irq_fail = 1; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** irq_fail=1*****\n"); #endif } //disable_irq_nosysc(s->port.irq); #ifdef _DEBUG_WK2XXX printk("--wk2xxx_irq---exit---\n"); #endif return IRQ_HANDLED; } static void wk2xxxirq_app(struct uart_port *port)// { struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "wk2xxxirq_app()------port:%d--------------\n",s->port.iobase); #endif unsigned int pass_counter = 0; uint8_t sifr,gifr,sier,dat[1]; uint8_t sifr0,sifr1,sifr2,sifr3,sier1,sier0,sier2,sier3; wk2xxx_read_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIFR ,dat); gifr = dat[0]; wk2xxx_write_reg(s->spi_wk,1,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0 wk2xxx_write_reg(s->spi_wk,2,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0 wk2xxx_write_reg(s->spi_wk,3,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0 wk2xxx_write_reg(s->spi_wk,4,WK2XXX_SPAGE,WK2XXX_PAGE0);//set register in page0 wk2xxx_read_reg(s->spi_wk,1,WK2XXX_SIFR,&sifr0); wk2xxx_read_reg(s->spi_wk,2,WK2XXX_SIFR,&sifr1); wk2xxx_read_reg(s->spi_wk,3,WK2XXX_SIFR,&sifr2); wk2xxx_read_reg(s->spi_wk,4,WK2XXX_SIFR,&sifr3); wk2xxx_read_reg(s->spi_wk,1,WK2XXX_SIER,&sier0); wk2xxx_read_reg(s->spi_wk,2,WK2XXX_SIER,&sier1); wk2xxx_read_reg(s->spi_wk,3,WK2XXX_SIER,&sier2); wk2xxx_read_reg(s->spi_wk,4,WK2XXX_SIER,&sier3); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "irq_app....gifr:%x sier1:%x sier2:%x sier3:%x sier4:%x sifr1:%x sifr2:%x sifr3:%x sifr4:%x \n",gifr,sier0,sier1,sier2,sier3,sifr0,sifr1,sifr2,sifr3); #endif switch(s->port.iobase) { case 1 : if(!(gifr & WK2XXX_UT1INT)) { return; } break; case 2 : if(!(gifr & WK2XXX_UT2INT)) { return; } break; case 3 : if(!(gifr & WK2XXX_UT3INT)) { return; } break; case 4 : if(!(gifr & WK2XXX_UT4INT)) { return; } break; default: break; } wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,dat); sifr = dat[0]; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,dat); sier = dat[0]; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "irq_app..........sifr:%x sier:%x \n",sifr,sier); #endif do { if ((sifr&WK2XXX_RFTRIG_INT)||(sifr&WK2XXX_RXOVT_INT)) { wk2xxx_rx_chars(&s->port); } if ((sifr & WK2XXX_TFTRIG_INT)&&(sier & WK2XXX_TFTRIG_IEN )) { wk2xxx_tx_chars(&s->port); return; } if (pass_counter++ > WK2XXX_ISR_PASS_LIMIT) break; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,dat); sifr = dat[0]; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,dat); sier = dat[0]; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "irq_app...........rx............tx sifr:%x sier:%x port:%x\n",sifr,sier,s->port.iobase); #endif } while ((sifr&WK2XXX_RXOVT_INT)||(sifr & WK2XXX_RFTRIG_INT)||((sifr & WK2XXX_TFTRIG_INT)&&(sier & WK2XXX_TFTRIG_IEN))); #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "sifr:%d\n",sifr); #endif #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "wk2xxxirq_app()---------exit---\n"); #endif } /* * Return TIOCSER_TEMT when transmitter is not busy. */ static u_int wk2xxx_tx_empty(struct uart_port *port)// or query the tx fifo is not empty? { uint8_t rx; mutex_lock(&wk2xxxs_lock); struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_tx_empty()---------in---\n"); #endif // mutex_lock(&wk2xxxs_lock); //s->tx_empty_flag = 1; /*if(!(s->tx_empty_flag || s->tx_empty_fail)) { if(wk2xxx_dowork(s)) { s->tx_empty_flag = 1; #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "tx_empty_flag=1"); #endif } else { #ifdef _DEBUG_WK2XXX1 printk(KERN_ALERT "tx_empty_fail=1"); #endif s->tx_empty_fail = 1; } }*/ if(!(s->tx_empty_flag || s->tx_empty_fail)) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,&rx); s->tx_empty = (rx & WK2XXX_TDAT)<=0; if(s->tx_empty) { s->tx_empty_flag =0; s->tx_empty_fail=0; } else { s->tx_empty_fail=0; s->tx_empty_flag =0; } } #ifdef _DEBUG_WK2XXX4 printk(KERN_ALERT "s->tx_empty_fail----FSR:%d--s->tx_empty:%d--\n",rx,s->tx_empty); #endif #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_tx_empty----------exit---\n"); #endif mutex_unlock(&wk2xxxs_lock); return s->tx_empty; } static void wk2xxx_set_mctrl(struct uart_port *port, u_int mctrl)//nothing { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_set_mctrl---------exit---\n"); #endif } static u_int wk2xxx_get_mctrl(struct uart_port *port)// since no modem control line { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_get_mctrl---------exit---\n"); #endif return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; } /* * interrupts disabled on entry */ static void wk2xxx_stop_tx(struct uart_port *port)// { mutex_lock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_stop_tx------in---\n"); #endif uint8_t rx; //mutex_lock(&wk2xxxs_lock); //disable the interrupt,clear the corresponding bit in GIR struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); //s->stop_tx_flag = 1; /* if(!(s->stop_tx_flag||s->stop_tx_fail)) { if(wk2xxx_dowork(s)) { s->stop_tx_flag =1; } else { s->stop_tx_fail =1; } }*/ if(!(s->stop_tx_flag||s->stop_tx_fail)) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); s->stop_tx_fail=rx&WK2XXX_TFTRIG_IEN>0; if(s->stop_tx_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx &=~WK2XXX_TFTRIG_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_TFTRIG_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); s->stop_tx_fail =0; s->stop_tx_flag=0; } else { s->stop_tx_fail =0; s->stop_tx_flag=0; } } //mutex_unlock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX4 printk(KERN_ALERT "-wk2xxx_stop_tx------exit---\n"); #endif mutex_unlock(&wk2xxxs_lock); } /* * * interrupts may not be disabled on entry */ static void wk2xxx_start_tx(struct uart_port *port) { //mutex_lock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_start_tx------in---\n"); #endif // mutex_lock(&wk2xxxs_lock); struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); // uint8_t rx; //s->start_tx_flag = 1; //vk32xx_dowork(s); if(!(s->start_tx_flag||s->start_tx_fail)) { if(wk2xxx_dowork(s)) { s->start_tx_flag = 1; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** start_tx_flag=1*****\n"); #endif } else { s->start_tx_fail = 1; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** start_tx_fail=1*****\n"); #endif } } // mutex_unlock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_start_tx------exit---\n"); #endif // mutex_unlock(&wk2xxxs_lock); // vk32xx_read_reg(s->spi_vk,s->port.iobase,VK32XX_SIER,&rx); // rx |= VK32XX_TRIEN; // vk32xx_write_reg(s->spi_vk,s->port.iobase,VK32XX_SIER,rx); } /* * * Interrupts enabled */ static void wk2xxx_stop_rx(struct uart_port *port) { //mutex_lock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_stop_rx------in---\n"); #endif // uint8_t rx; struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); //s->stop_rx_flag = 1; // mutex_lock(&wk2xxxs_lock); if(!(s->stop_rx_flag ||s->stop_rx_fail )) { if(wk2xxx_dowork(s)) { s->stop_rx_flag = 1; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** stop_rx_flag=1*****\n"); #endif } else { s->stop_rx_fail = 1; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** stop_rx_fail=1*****\n"); #endif } } /* if(!(s->stop_rx_flag ||s->stop_rx_fail )) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); s->stop_rx_fail=rx&WK2XXX_RFTRIG_IEN||rx&WK2XXX_RXOUT_IEN>0; if(s->stop_rx_fail) { wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,&rx); rx &=~WK2XXX_RFTRIG_IEN; rx &=~WK2XXX_RXOUT_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,rx); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,&rx); rx &= ~WK2XXX_RFTRIG_INT; rx &= ~WK2XXX_RXOVT_INT; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIFR,rx); s->stop_rx_fail =0; s->stop_rx_flag = 0; } else { s->stop_rx_fail =0; s->stop_rx_flag = 0; } }*/ // mutex_unlock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_stop_rx------exit---\n"); #endif //mutex_unlock(&wk2xxxs_lock); } /* * * No modem control lines * */ static void wk2xxx_enable_ms(struct uart_port *port) //nothing { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_enable_ms------exit---\n"); #endif } /* * * Interrupts always disabled. */ static void wk2xxx_break_ctl(struct uart_port *port, int break_state) { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_break_ctl------exit---\n"); #endif //break operation, but there seems no such operation in vk32 } static int wk2xxx_startup(struct uart_port *port)//i { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_startup------in---\n"); #endif uint8_t gena,grst,gier,sier,scr,dat[1]; struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); char b[12]; if (s->suspending) return 0; //printk("work_pending() =: %d tx_empty_flag = : %d start_tx_flag = :%d stop_tx_flag = :%d conf_flag =: %d irq_flag =: %d tx_empty=:%d\n",work_pending(&s->work),s->tx_empty_flag,s->start_tx_flag,s->stop_tx_flag,s->stop_rx_flag,s->conf_flag,s-> irq_flag,s->tx_empty); s->force_end_work = 0; sprintf(b, "wk2xxx-%d", (uint8_t)s->port.iobase); //s->workqueue = create_singlethread_workqueue(b); s->workqueue = create_workqueue(b); if (!s->workqueue) { dev_warn(&s->spi_wk->dev, "cannot create workqueue\n"); return -EBUSY; } INIT_WORK(&s->work, wk2xxx_work); if (s->wk2xxx_hw_suspend) s->wk2xxx_hw_suspend(0); //wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE ,0); wk2xxx_read_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,dat);//默认0x30 #ifdef _DEBUG_tla001 printk(KERN_ALERT "******read WK2XXX_GENA*****0x%x\n",dat[0]); #endif gena=dat[0]; switch (s->port.iobase) { case 1: gena|=WK2XXX_UT1EN; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,gena); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk1 write WK2XXX_GENA*****0x%x\n",gena); #endif break; case 2: gena|=WK2XXX_UT2EN; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,gena); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk2 write WK2XXX_GENA*****0x%x\n",gena); #endif break; case 3: gena|=WK2XXX_UT3EN; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,gena); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk3 write WK2XXX_GENA*****0x%x\n",gena); #endif break; case 4: gena|=WK2XXX_UT4EN; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,gena); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk4 write WK2XXX_GENA*****0x%x\n",gena); #endif break; default: printk(KERN_ALERT ":con_wk2xxx_subport bad iobase %d\n", (uint8_t)s->port.iobase); } wk2xxx_read_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GRST,dat); grst=dat[0]; #ifdef _DEBUG_tla001 printk(KERN_ALERT "******read WK2XXX_GRST*****0x%x\n",grst); #endif switch (s->port.iobase) { case 1: grst|=WK2XXX_UT1RST; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GRST,grst); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk1 write WK2XXX_GRST*****0x%x\n",grst); #endif break; case 2: grst|=WK2XXX_UT2RST; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GRST,grst); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk2 write WK2XXX_GRST*****0x%x\n",grst); #endif break; case 3: grst|=WK2XXX_UT3RST; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GRST,grst); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk3 write WK2XXX_GRST*****0x%x\n",grst); #endif break; case 4: grst|=WK2XXX_UT4RST; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GRST,grst); #ifdef _DEBUG_tla001 printk(KERN_ALERT "******wk4 write WK2XXX_GRST*****0x%x\n",grst); #endif break; default: printk(KERN_ALERT ":con_wk2xxx_subport bad iobase %d\n", (uint8_t)s->port.iobase); } wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,dat); sier = dat[0]; sier &= ~WK2XXX_TFTRIG_IEN; sier |= WK2XXX_RFTRIG_IEN; sier |= WK2XXX_RXOUT_IEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER,sier); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR,dat); scr = dat[0] | WK2XXX_TXEN|WK2XXX_RXEN; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR,scr); //initiate the fifos wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_FCR,0x0f);//initiate the fifos wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_FCR,0x0c); //enable the sub port interrupt wk2xxx_read_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIER,dat); gier = dat[0]; switch (s->port.iobase){ case 1: gier|=WK2XXX_UT1IE; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIER,gier); break; case 2: gier|=WK2XXX_UT2IE; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIER,gier); break; case 3: gier|=WK2XXX_UT3IE; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIER,gier); break; case 4: gier|=WK2XXX_UT4IE; wk2xxx_write_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GIER,gier); break; default: printk(KERN_ALERT ": bad iobase %d\n", (uint8_t)s->port.iobase); } if (s->wk2xxx_hw_suspend) s->wk2xxx_hw_suspend(0); msleep(50); uart_circ_clear(&s->port.state->xmit); wk2xxx_enable_ms(&s->port); // request irq if(request_irq(s->port.irq, wk2xxx_irq,IRQF_SHARED|IRQF_TRIGGER_LOW,"wk2xxxspi", s) < 0) { dev_warn(&s->spi_wk->dev, "cannot allocate irq %d\n", s->irq); s->port.irq = 0; #ifdef _DEBUG_tla001 printk(KERN_ALERT "****** start_tx_fail=1*****\n"); #endif destroy_workqueue(s->workqueue); s->workqueue = NULL; return -EBUSY; } udelay(100); udelay(100); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_startup------exit---\n"); #endif return 0; } //* Power down all displays on reboot, poweroff or halt * static void wk2xxx_shutdown(struct uart_port *port)// { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_shutdown------in---\n"); #endif struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); if (s->suspending) return; s->force_end_work = 1; if (s->workqueue) { flush_workqueue(s->workqueue); destroy_workqueue(s->workqueue); s->workqueue = NULL; } if (s->port.irq) { disable_irq_nosync(s->port.irq); printk(KERN_ALERT "irq---%d\n",s->port.line); free_irq(s->port.irq,s); } //printk("work_pending() =: %d tx_empty_flag = : %d start_tx_flag = :%d stop_tx_flag = :%d conf_flag =: %d irq_flag =: %d tx_empty=:%d\n",work_pending(&s->work),s->tx_empty_flag,s->start_tx_flag,s->stop_tx_flag,s->stop_rx_flag,s->conf_flag,s-> irq_flag,s->tx_empty); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_shutdown-----exit---\n"); #endif return; } static void conf_wk2xxx_subport(struct uart_port *port)//i { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-conf_wk2xxx_subport------in---\n"); #endif struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); uint8_t old_sier,lcr,scr,scr_ss,dat[1],gena,test1,baud0_ss,baud1_ss,pres_ss; lcr = s->new_lcr; scr_ss = s->new_scr; baud0_ss=s->new_baud0; baud1_ss=s->new_baud1; pres_ss=s->new_pres; wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER ,dat); old_sier = dat[0]; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER ,old_sier&(~(WK2XXX_TFTRIG_IEN | WK2XXX_RFTRIG_IEN | WK2XXX_RXOUT_IEN))); //local_irq_restore(flags); do{ wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_FSR,dat); //ssr = dat[0]; } while (dat[0] & WK2XXX_TBUSY); // then, disable everything wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR,dat); scr = dat[0]; scr &= 0x0f; scr |= scr_ss; wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR ,scr&(~(WK2XXX_RXEN|WK2XXX_TXEN))); // set the parity, stop bits and data size // wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_LCR ,lcr); // set the baud rate // wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SIER ,old_sier); // wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR ,scr|(WK2XXX_RXEN|WK2XXX_TXEN)); // set the baud rate // wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE ,1); wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_BAUD0 ,baud0_ss); wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_BAUD1 ,baud1_ss); wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_PRES ,pres_ss); #ifdef _DEBUG_WK2XXX2 wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_BAUD0,dat); printk(KERN_ALERT ":WK2XXX_BAUD0=0x%X\n", dat[0]); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_BAUD1,dat); printk(KERN_ALERT ":WK2XXX_BAUD1=0x%X\n", dat[0]); wk2xxx_read_reg(s->spi_wk,s->port.iobase,WK2XXX_PRES,dat); printk(KERN_ALERT ":WK2XXX_PRES=0x%X\n", dat[0]); #endif wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SPAGE ,0); wk2xxx_write_reg(s->spi_wk,s->port.iobase,WK2XXX_SCR ,scr|(WK2XXX_RXEN|WK2XXX_TXEN) ); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-conf_wk2xxx_subport------exit---\n"); #endif } // change speed static void wk2xxx_termios( struct uart_port *port, struct ktermios *termios, struct ktermios *old) { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-vk32xx_termios------in---\n"); #endif struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); int baud = 0; uint8_t lcr,scr,baud1,baud0,pres; unsigned short cflag; unsigned short lflag; //u32 param_new, param_mask; // mutex_lock(&wk2xxxs_lock); cflag = termios->c_cflag; lflag = termios->c_lflag; #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "cflag := 0x%X lflag : = 0x%X\n",cflag,lflag); #endif baud1=0; baud0=0; pres=0; baud = tty_termios_baud_rate(termios); switch (baud) { case 600: baud1=0x4; baud0=0x7f; pres=0; break; case 1200: baud1=0x2; baud0=0x3F; pres=0; break; case 2400: baud1=0x1; baud0=0x1f; pres=0; break; case 4800: baud1=0x00; baud0=0x8f; pres=0; break; case 9600: baud1=0x00; baud0=0x47; pres=0; break; case 19200: baud1=0x00; baud0=0x23; pres=0; break; case 38400: baud1=0x00; baud0=0x11; pres=0; break; case 76800: baud1=0x00; baud0=0x08; pres=0; break; case 1800: baud1=0x01; baud0=0x7f; pres=0; break; case 3600: baud1=0x00; baud0=0xbf; pres=0; break; case 7200: baud1=0x00; baud0=0x5f; pres=0; break; case 14400: baud1=0x00; baud0=0x2f; pres=0; break; case 28800: baud1=0x00; baud0=0x17; pres=0; break; case 57600: baud1=0x00; baud0=0x0b; pres=0; break; case 115200: baud1=0x00; baud0=0x05; pres=0; #ifdef _DEBUG_tla001 printk(KERN_ALERT "set baud=115200bps\n"); #endif break; case 230400: baud1=0x00; baud0=0x02; pres=0; break; default: baud1=0x00; baud0=0x00; pres=0; } tty_termios_encode_baud_rate(termios, baud, baud); /* we are sending char from a workqueue so enable */ //spin_lock(&s->conf_lock); //s->port.state->port.tty->low_latency = 1; //termios->c_lflag &= ~ECHO; lcr =0; if (cflag & CSTOPB) lcr|=WK2XXX_STPL;//two stop_bits else lcr&=~WK2XXX_STPL;//one stop_bits if (cflag & PARENB) { lcr|=WK2XXX_PAEN;//enbale spa if (!(cflag & PARODD)){ lcr |= WK2XXX_PAM0;//PAM0=1 lcr &= ~WK2XXX_PAM0;//PAM1=0 } else{ lcr |= WK2XXX_PAM1; lcr &= ~WK2XXX_PAM0; } } else{ lcr&=~WK2XXX_PAEN; } //scr = 0; //scr &= 0x0f; //scr |= param_new<<4; s->new_baud1=baud1; s->new_baud0=baud0; s->new_pres=pres; //spin_lock(&s->conf_lock); //s->conf_flag =1; s->new_lcr = lcr; s->new_scr = scr; //spin_unlock(&s->conf_lock); //vk32xx_dowork(s); if(!(s->conf_flag|| s->conf_fail)) { if(wk2xxx_dowork(s)) { s->conf_flag =1; } else { s->conf_fail =1; } } #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-vk32xx_termios------exit---\n"); #endif // mutex_unlock(&wk2xxxs_lock); return ; } static const char *wk2xxx_type(struct uart_port *port) { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_type-------------out-------- \n"); #endif return port->type == PORT_WK2XXX ? "wk2xxx" : NULL;//this is defined in serial_core.h } /* * Release the memory region(s) being used by 'port'. */ static void wk2xxx_release_port(struct uart_port *port) { printk(KERN_ALERT "wk2xxx_release_port\n"); // struct vk32xx_port *s = container_of(port,struct vk32xx_port,port); // dev_dbg(&s->spi_vk->dev, "%s\n", __func__); //no such memory region for vk32 } /* * Request the memory region(s) being used by 'port'. */ static int wk2xxx_request_port(struct uart_port *port)//no such memory region needed for vk32 { printk(KERN_ALERT "wk2xxx_request_port\n"); // struct vk32xx_port *s = container_of(port,struct vk32xx_port,port); return 0; } /* * Configure/autoconfigure the port*/ static void wk2xxx_config_port(struct uart_port *port, int flags) { struct wk2xxx_port *s = container_of(port,struct wk2xxx_port,port); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_config_port \n"); #endif if (flags & UART_CONFIG_TYPE && wk2xxx_request_port(port) == 0) s->port.type = PORT_WK2XXX; } /* * Verify the new serial_struct (for TIOCSSERIAL). * The only change we allow are to the flags and type, and * even then only between PORT_vk32xx and PORT_UNKNOWN */ static int wk2xxx_verify_port(struct uart_port *port, struct serial_struct *ser) { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "wk2xxx_verify_port \n"); #endif int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_WK2XXX) ret = -EINVAL; if (port->irq != ser->irq) ret = -EINVAL; if (ser->io_type != SERIAL_IO_PORT) ret = -EINVAL; //if (port->uartclk / 16 != ser->baud_base)//?a??2?猫路?篓 // ret = -EINVAL; if (port->iobase != ser->port) ret = -EINVAL; if (ser->hub6 != 0) ret = -EINVAL; return ret; } static struct uart_ops wk2xxx_pops = { tx_empty: wk2xxx_tx_empty, set_mctrl: wk2xxx_set_mctrl, get_mctrl: wk2xxx_get_mctrl, stop_tx: wk2xxx_stop_tx, start_tx: wk2xxx_start_tx, stop_rx: wk2xxx_stop_rx, enable_ms: wk2xxx_enable_ms, break_ctl: wk2xxx_break_ctl, startup: wk2xxx_startup, shutdown: wk2xxx_shutdown, set_termios: wk2xxx_termios, type: wk2xxx_type, release_port: wk2xxx_release_port, request_port: wk2xxx_request_port, config_port: wk2xxx_config_port, verify_port: wk2xxx_verify_port, }; static struct uart_driver wk2xxx_uart_driver = { owner: THIS_MODULE, major: SERIAL_WK2XXX_MAJOR, #ifdef CONFIG_DEVFS_FS driver_name: "ttySWK", dev_name: "ttysWK", #else driver_name: "ttySWK", dev_name: "ttysWK", #endif minor: MINOR_START, nr: NR_PORTS, cons: NULL//WK2Xxx_CONSOLE, }; static int uart_driver_registered; int wk2166_irq1; static int __devinit wk2xxx_probe(struct spi_device *spi) { #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_probe()------in---\n"); #endif uint8_t i; int status; i=0; /* static volatile unsigned long *gpbcon_addr; #define GPBCONWWWWW 0xE020004C gpbcon_addr = ioremap(GPBCONWWWWW, 4); status = *gpbcon_addr; printk(KERN_ERR "GPB_DRV...........= 0x%X\n",status); *gpbcon_addr |= 0xaa00; status = *gpbcon_addr; printk(KERN_ERR "GPB_DRV...........= 0x%X\n",status); printk(KERN_ALERT "wk2xxx_probe wk2xxx\n");*/ mutex_lock(&wk2xxxs_lock); if(!uart_driver_registered) { uart_driver_registered = 1; status=uart_register_driver(&wk2xxx_uart_driver); if (status) { printk(KERN_ALERT "Couldn't register wk2xxx uart driver\n"); mutex_unlock(&wk2xxxs_lock); return status; } } printk(KERN_ALERT "wk2xxx_serial_init()\n"); /********IO初始化***********/ gpio_free(wk2166_irq); gpio_request(wk2166_irq,"wk2166_irq"); gpio_direction_input(wk2166_irq); wk2166_irq1=gpio_to_irq(wk2166_irq); printk(KERN_ALERT "wk2166_irq1=%d\n",wk2166_irq1); for(i =0;i<NR_PORTS;i++) { struct wk2xxx_port *s = &wk2xxxs[i];//container_of(port,struct vk32xx_port,port); s->tx_done =0; s->spi_wk = spi; s->port.line = i; s->port.ops = &wk2xxx_pops; s->port.uartclk = WK_CRASTAL_CLK; s->port.fifosize = 256; s->port.iobase = i+1; s->port.irq = wk2166_irq1; s->port.iotype = SERIAL_IO_PORT; s->port.flags = ASYNC_BOOT_AUTOCONF; //s->minor = i; status = uart_add_one_port(&wk2xxx_uart_driver, &s->port); if(status<0) { //dev_warn(&spi->dev,"uart_add_one_port failed for line i:= %d with error %d\n",i,status); printk(KERN_ALERT "uart_add_one_port failed for line i:= %d with error %d\n",i,status); } } printk(KERN_ALERT "uart_add_one_port = 0x%d\n",status); mutex_unlock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX // while(1) // wk2xxx_read_reg(s->spi_wk,WK2XXX_GPORT,WK2XXX_GENA,0XFF); printk(KERN_ALERT "-wk2xxx_probe()------exit---\n"); #endif return 0; } /* static int vk32xx_suspend(struct spi_device *spi) { printk(KERN_ALERT "vk32xx_suspend vk32xx"); return 0; } */ static int __devexit wk2xxx_remove(struct spi_device *spi) { //struct wk2xxx_port *s = dev_get_drvdata(&spi->dev); int i; #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_remove()------in---\n"); #endif mutex_lock(&wk2xxxs_lock); for(i =0;i<NR_PORTS;i++) { struct wk2xxx_port *s = &wk2xxxs[i]; uart_remove_one_port(&wk2xxx_uart_driver, &s->port); } printk(KERN_ALERT "removing wk2xxx driver\n"); uart_unregister_driver(&wk2xxx_uart_driver); mutex_unlock(&wk2xxxs_lock); #ifdef _DEBUG_WK2XXX printk(KERN_ALERT "-wk2xxx_remove()------exit---\n"); #endif /***********释放中断号*************************/ free_irq(wk2166_irq1,1); gpio_free(wk2166_irq); return 0; } static int wk2xxx_resume(struct spi_device *spi) { printk(KERN_ALERT "resume wk2xxx"); return 0; } static struct spi_driver wk2xxx_driver = { .driver = { .name = "wk2166", .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = wk2xxx_probe, .remove = __devexit_p(wk2xxx_remove), .resume = wk2xxx_resume, }; static int __init wk2xxx_init(void) { int retval; mxc_iomux_v3_setup_pad(MX6Q_PAD_SD3_DAT2__GPIO_7_6); //mxc_iomux_v3_setup_pad(MX6Q_PAD_SD3_CMD__GPIO_7_2); mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_CS0__ECSPI2_SCLK); mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_CS1__ECSPI2_MOSI); mxc_iomux_v3_setup_pad(MX6Q_PAD_EIM_OE__ECSPI2_MISO); mxc_iomux_v3_setup_pad(MX6Q_PAD_CSI0_DAT11__GPIO_5_29); __gpio_set_value(wk2166__cs,1); retval = spi_register_driver(&wk2xxx_driver); printk(KERN_ALERT "rgister spi return v = :%d\n",retval); return retval; } static void __exit wk2xxx_exit(void) { spi_unregister_driver(&wk2xxx_driver); printk(KERN_ALERT "TEST_REG:quit "); } module_init(wk2xxx_init); module_exit(wk2xxx_exit); MODULE_AUTHOR("WKIC Ltd"); MODULE_DESCRIPTION("wk2xxx generic serial port driver"); MODULE_LICENSE("GPL");
wkXXX.h
#ifndef _SERIAL_WK2166_H #define _SERIAL_WK2166_H //#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/io.h> //#include <asm/hardware.h> //EINT15 GPG7 //wkxxxx Global rigister address defines #define WK2XXX_GENA 0X00 //全局控制寄存器 #define WK2XXX_GRST 0X01 //全局子串口复位寄存器 #define WK2XXX_GMUT 0X02 #define WK2XXX_GIER 0X10 //全局中断寄存器 #define WK2XXX_GIFR 0X11 //全局中断标志寄存器 #define WK2XXX_GPDIR 0X21 #define WK2XXX_GPDAT 0X31 #define WK2XXX_GPORT 1 // //wkxxxx slave uarts rigister address defines #define WK2XXX_SPAGE 0X03 //子串口页控制寄存器 //PAGE0 #define WK2XXX_SCR 0X04 //子串口使能寄存器 #define WK2XXX_LCR 0X05 //子串口配置寄存器 #define WK2XXX_FCR 0X06 //子串口FIFO控制寄存器 #define WK2XXX_SIER 0X07 //子串口中断使能寄存器 #define WK2XXX_SIFR 0X08 //子串口中断标志寄存器 #define WK2XXX_TFCNT 0X09 //子串口发送FIFO计数寄存器 #define WK2XXX_RFCNT 0X0A //子串口接收FIFO计数寄存器 #define WK2XXX_FSR 0X0B //子串口FIFO状态寄存器 #define WK2XXX_LSR 0X0C //子串口接收状态寄存器 #define WK2XXX_FDAT 0X0D //子串口FIFO数据寄存器 #define WK2XXX_FWCR 0X0E // #define WK2XXX_RS485 0X0F // //PAGE1 #define WK2XXX_BAUD1 0X04 //子串口波特率配置寄存器高字节 #define WK2XXX_BAUD0 0X05 //子串口波特率配置寄存器低字节 #define WK2XXX_PRES 0X06 //子串口波特率配置寄存器小数部分 #define WK2XXX_RFTL 0X07 //子串口接收FIFO中断触发点配置寄存器 #define WK2XXX_TFTL 0X08 //子串口发送FIFO中断触发点配置寄存器 #define WK2XXX_FWTH 0X09 // #define WK2XXX_FWTL 0X0A // #define WK2XXX_XON1 0X0B // #define WK2XXX_XOFF1 0X0C // #define WK2XXX_SADR 0X0D // #define WK2XXX_SAEN 0X0D // #define WK2XXX_RRSDLY 0X0F // /******全局控制寄存器GENA******/ #define WK2XXX_UT4EN 0x08 //子串口4时钟使能位 #define WK2XXX_UT3EN 0x04 //子串口3时钟使能位 #define WK2XXX_UT2EN 0x02 //子串口2时钟使能位 #define WK2XXX_UT1EN 0x01 //子串口1时钟使能位 /***全局子串口复位寄存器GRST***/ #define WK2XXX_UT4SLEEP 0x80 //子串口4休眠状态位 #define WK2XXX_UT3SLEEP 0x40 //子串口3休眠状态位 #define WK2XXX_UT2SLEEP 0x20 //子串口2休眠状态位 #define WK2XXX_UT1SLEEP 0x10 //子串口1休眠状态位 #define WK2XXX_UT4RST 0x08 //子串口4软复位控制位 #define WK2XXX_UT3RST 0x04 //子串口3软复位控制位 #define WK2XXX_UT2RST 0x02 //子串口2软复位控制位 #define WK2XXX_UT1RST 0x01 //子串口1软复位控制位 /******全局中断寄存器GIER******/ #define WK2XXX_UT4IE 0x08 //子串口4中断使能控制位 #define WK2XXX_UT3IE 0x04 //子串口3中断使能控制位 #define WK2XXX_UT2IE 0x02 //子串口2中断使能控制位 #define WK2XXX_UT1IE 0x01 //子串口1中断使能控制位 /****全局中断标志寄存器GIFR****/ #define WK2XXX_UT4INT 0x08 //子串口4中断标志位 #define WK2XXX_UT3INT 0x04 //子串口3中断标志位 #define WK2XXX_UT2INT 0x02 //子串口2中断标志位 #define WK2XXX_UT1INT 0x01 //子串口1中断标志位 /****子串口页控制寄存器SPAGE***/ #define WK2XXX_SPAGE0 0x00 //PAGE0 #define WK2XXX_SPAGE1 0x01 //PAGE1 /*****子串口控制寄存器SCR******/ #define WK2XXX_SLEEPEN 0x04 //子串口休眠使能位 #define WK2XXX_TXEN 0x02 //子串口发送使能位 #define WK2XXX_RXEN 0x01 //子串口接收使能位 /*****子串口配置寄存器LCR******/ #define WK2XXX_BREAK 0x20 //子串口Line-Break输出控制位 #define WK2XXX_IREN 0x10 //子串口红外使能位 #define WK2XXX_PAEN 0x08 //子串口校验使能位 #define WK2XXX_PAM1 0x04 //子串口校验模式选择位00:0 校验;01:奇校验; #define WK2XXX_PAM0 0x02 //子串口校验模式选择位10:偶校验;11:1 校验 #define WK2XXX_STPL 0x01 //子串口停止位长度控制位0:1bit;1:2bit /****子串口FIFO控制寄存FRC*****/ /****子串口FIFO控制寄存SIER****/ #define WK2XXX_FERR_IEN 0x80 //接收FIFO数据错误中断使能位 #define WK2XXX_CTS_IEN 0x40 // #define WK2XXX_RTS_IEN 0x20 // #define WK2XXX_XOFF_IEN 0x10 // #define WK2XXX_TFEMPTY_IEN 0x08 //发送FIFO空中断使能位 #define WK2XXX_TFTRIG_IEN 0x04 //发送FIFO触点中断使能位 #define WK2XXX_RXOUT_IEN 0x02 //接收FIFO超时中断使能位 #define WK2XXX_RFTRIG_IEN 0x01 //接收FIFO触点中断使能位 /****子串口FIFO控制寄存SIFR****/ #define WK2XXX_FERR_INT 0x80 //接收FIFO数据错误中断标志位 #define WK2XXX_CTS_INT 0x40 // #define WK2XXX_RTS_INT 0x20 // #define WK2XXX_XOFF_INT 0x10 // #define WK2XXX_TFEMPTY_INT 0x08 //发送FIFO空中断标志位 #define WK2XXX_TFTRIG_INT 0x04 //发送FIFO触点中断标志位 #define WK2XXX_RXOVT_INT 0x02 //接收FIFO超时中断标志位 #define WK2XXX_RFTRIG_INT 0x01 //接收FIFO触点中断标志位 /*子串口发送FIFO计数寄存器TFCNT*/ /**子串口接收FIFO计数寄存RFCNT**/ /****子串口FIFO 状态寄存FSR****/ #define WK2XXX_RFOE 0x80 //子串口接收FIFO中数据溢出出错标志位 #define WK2XXX_RFBI 0x40 //子串口接收FIFO中数据有Line-Break错误 #define WK2XXX_RFFE 0x20 //子串口接收FIFO中数据帧错误标志位 #define WK2XXX_RFPE 0x10 //子串口接收FIFO中数据校验错误标志位 #define WK2XXX_RDAT 0x08 //子串口接收FIFO空标志位 #define WK2XXX_TDAT 0x04 //子串口发送FIFO空标志位 #define WK2XXX_TFULL 0x02 //子串口发送FIFO满标志位 #define WK2XXX_TBUSY 0x01 //子串口发送TX忙标志位 /***子串口接收状态寄存器LSR****/ #define WK2XXX_OE 0x08 //子串口接收FIFO当前被读取的字节溢出出错标志位 #define WK2XXX_BI 0x04 //子串口接收FIFO中当前被读取字节Line-Break错误标志位 #define WK2XXX_FE 0x02 //子串口接收FIFO中当前被读取字节帧错误标志位 #define WK2XXX_PE 0x01 //子串口接收FIFO中当前被读取字节校验错误标志位 //FWCR //RS485 // #define NR_PORTS 4 // #define SERIAL_WK2XXX_MAJOR 207 #define CALLOUT_WK2XXX_MAJOR 208 #define MINOR_START 5 //wk2xxx hardware configuration #define IRQ_WK2XXX_PIN IMX_GPIO_NR(5, 17) #define IRQ_WK2XXX __gpio_to_irq(IRQ_WK2XXX_PIN)//shuould be IRQ_EINT7,but EINT7 of the borad is ocuppied #define WK_CS_PIN IMX_GPIO_NR(2, 26)//should be GPB #define WK_CRASTAL_CLK (3686400*2) #define WK2XXX_CS WK_CS_PIN #define MAX_WK2XXX 4 #define WK2XXX_ISR_PASS_LIMIT 50 //#define _DEBUG_WK2XXX #define PORT_WK2XXX 1 #endif
如果cs信号不能拉低,需要手动拉低,并在spi传输的时候,加锁,不然4路同时读写的时候会冲突
此外,针对不同的外置晶振,需要重新配置波特率的控制字
IMX6下移植WKxxx驱动的更多相关文章
- 第一章 Android系统移植与驱动开发概述
本书第一章首先简单概要地介绍了关于Android系统移植和驱动开发的相关内容. 所谓“移植”是指为特定的自己的设备,如手机定制Android的过程.自己开发一些程序(移植)装载在设备上,使得Andro ...
- 第一章Android系统移植与驱动开发概述--读书笔记
以前,初步学习过嵌入式Linux驱动开发的基础课程,对于驱动开发可以说是有了一点点微末的基础吧.首先我们要对Android嵌入式系统有一个初步的认识,Android系统发展到今天已经具备了完善的架构. ...
- 1Android系统移植与驱动开发概述
1.Android系统架构分为四层,从下至上依次为Linux内核层,C/C++代码库.Android SDK API.应用程序,要熟悉每一层的内容以及功能: 2.Android移植分为应用移植和系统移 ...
- Android系统移植与驱动开发----第一章
第一章 Android系统移植与驱动开发 Android源代码定制完全属于自己的嵌入式系统,但是支持的设备不多,所以要移植,而在移植的过程中使用的不得不提的是驱动开发. Android系统构架主要包括 ...
- 【转】 linux内核移植和驱动添加(三)
原文网址:http://blog.chinaunix.net/uid-29589379-id-4708909.html 原文地址:linux内核移植和驱动添加(三) 作者:genehang 四,LED ...
- 3.移植驱动到3.4内核-移植DM9000C驱动
在上章-使内核支持烧写yaffs2,裁剪内核并制作补丁了 本章,便开始移植以前2.6内核的驱动到3.4新内核 1.介绍 首先内核更新,有可能会重新定义新的宏,去除以前的宏,以前更改函数名等 所以移植驱 ...
- backports移植rtlwifi驱动
/************************************************************************ * backports移植rtlwifi驱动 * 说 ...
- 基于tiny4412的Linux内核移植 -- MMA7660驱动移植(九)
作者信息 作者: 彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台简介 开发板:tiny4412ADK + S700 + 4GB Flash 要移植的内核版本 ...
- I.mx6s上移植wm8960驱动(基于linux3.0.101版本)
I.mx6s上移植wm8960驱动 此篇博文只记录移植的步骤,其他不做分析.首先上一张wm8960的硬件连接图: 1 上电操作 配置wm8960的上电脚,文件位置:arch/arm/mach ...
随机推荐
- No mapping found for HTTP request with URI
原因:spring-mvc 的xml配置文件的包名配置错误 <mvc:annotation-driven /> <context:component-scan base-packag ...
- How to implement updatable view with NHibernate
see : http://msdn.microsoft.com/en-us/library/ms187956.aspx(The constrains of creation updatable vie ...
- Python 基礎 - 數據類型
標準數據類型 Python3 中有六個標準的數據類型 1 Number(數字) 2 String(字符串) 3 List (列表) 4 Tuple (元組) 5 Sets (集合) 6 Diction ...
- Canvas旋转元素
Canvas是HTML5的画布元素,有时需要按指定角度旋转某一个元素. var canvas = document.getElementById("mycanvas"); var ...
- LintCode Binary Tree Inorder Traversal
Binary Tree Inorder Traversal Given a binary tree, return the inorder traversal of its nodes' values ...
- 动态添加Marquee标签,并动态赋值与属性
前台加载js $(function(){ var publishStr="<%=publishText%>" var marqueeStr=" <mar ...
- select 通过jq赋值
<select name="F_YSBAQLX" onchange="selectvalue()" id="lista" prompt ...
- Python变量、数据类型6
1.Python变量 变量,即代表某个value的名字. 变量的值存储在内存中,这意味着在创建变量时会在内存中开辟一个空间. !!!即值并没有保存在变量中,它们保存在计算机内存的深处,被变量引用.所以 ...
- windows环境下 svn 客户端
- TTS多音字问题
今天在CSDN上找到了解决方案,终于解决了多音字问题. Text1.Text = "<pron sym='jia 3'> 贾</pron>宝玉,商<pron ...