improve spi_uart.c for bt

This commit is contained in:
luowei
2010-08-28 21:47:00 +08:00
parent b9faec95ac
commit 850053192e
3 changed files with 223 additions and 29 deletions

View File

@@ -15,7 +15,7 @@ defines of FPGA chip ICE65L08's register
#define SPI_FPGA_I2C_EVENT 1
#define SPI_FPGA_POLL_WAIT 0
#define SPI_FPGA_TRANS_WORK 0
#define SPI_FPGA_TRANS_WORK 1
#define SPI_FPGA_TEST_DEBUG 0
#if SPI_FPGA_TEST_DEBUG
#define SPI_FPGA_TEST_DEBUG_PIN RK2818_PIN_PE0

View File

@@ -43,7 +43,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <mach/rk2818_iomap.h>
#include <linux/poll.h>
#include <mach/spi_fpga.h>
#if defined(CONFIG_SPI_FPGA_INIT_DEBUG)
@@ -54,6 +54,178 @@
struct spi_fpga_port *pFpgaPort;
#if SPI_FPGA_TRANS_WORK
#define ID_SPI_FPGA_WRITE 1
#define ID_SPI_FPGA_READ 2
struct spi_fpga_transfer
{
const u8 *txbuf;
unsigned n_tx;
u8 *rxbuf;
unsigned n_rx;
int id;
struct list_head queue;
};
static void spi_fpga_trans_work_handler(struct work_struct *work)
{
struct spi_fpga_port *port =
container_of(work, struct spi_fpga_port, fpga_trans_work);
while (!list_empty(&port->trans_queue))
{
struct spi_fpga_transfer *t = NULL;
list_for_each_entry(t, &port->trans_queue, queue)
{
if (t->id == 0)
break;
DBG("%s:id=%d,txbuf=0x%x\n",__FUNCTION__,t->id,(int)t->txbuf);
switch(t->id)
{
case ID_SPI_FPGA_WRITE:
spi_write(port->spi, t->txbuf, t->n_tx);
break;
default:
break;
}
kfree(t);
kfree(t->txbuf);
}
list_del_init(&port->trans_queue);
}
}
int spi_write_work(struct spi_device *spi, const u8 *buf, size_t len)
{
struct spi_fpga_port *port = spi_get_drvdata(spi);
struct spi_fpga_transfer *t;
unsigned long flags;
t = kzalloc(sizeof(struct spi_fpga_transfer), GFP_KERNEL);
if (!t)
{
printk("err:%s:ENOMEM\n",__FUNCTION__);
return ;
}
t->txbuf = (char *)kmalloc(32, GFP_KERNEL);
if(t->txbuf == NULL)
{
printk("%s:t->txbuf kzalloc err!!!\n",__FUNCTION__);
return -ENOMEM;
}
memcpy(t->txbuf, buf, len);
t->n_tx = len;
t->id = ID_SPI_FPGA_WRITE;
spin_lock_irqsave(&port->work_lock, flags);
list_add_tail(&t->queue, &port->trans_queue);
queue_work(port->fpga_trans_workqueue, &port->fpga_trans_work);
spin_unlock_irqrestore(&port->work_lock, flags);
return 0;
}
#endif
#if SPI_FPGA_POLL_WAIT
#define SPI_BUFSIZE 1028
static void spi_fpga_complete(void *arg)
{
struct spi_fpga_port *port = pFpgaPort;
msleep(5);
wake_up_interruptible(&port->spi_wait_q);
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
}
int spi_fpga_write(struct spi_device *spi, const u8 *buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = len,
};
struct spi_message m;
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
spi_message_init(&m);
spi_message_add_tail(&t, &m);
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
return spi_async(spi, &m);
}
struct poll_table_struct wait;
struct file filp;
int spi_fpga_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx)
{
struct spi_fpga_port *port = spi_get_drvdata(spi);
int status;
struct spi_message message;
struct spi_transfer x[2];
u8 *local_buf;
printk("%s:line=%d,n_tx+n_rx=%d\n",__FUNCTION__,__LINE__,(n_tx + n_rx));
/* Use preallocated DMA-safe buffer. We can't avoid copying here,
* (as a pure convenience thing), but we can keep heap costs
* out of the hot path ...
*/
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
if ((n_tx + n_rx) > SPI_BUFSIZE)
return -EINVAL;
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
spi_message_init(&message);
memset(x, 0, sizeof x);
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
if (n_tx) {
x[0].len = n_tx;
spi_message_add_tail(&x[0], &message);
}
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
if (n_rx) {
x[1].len = n_rx;
spi_message_add_tail(&x[1], &message);
}
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
/* ... unless someone else is using the pre-allocated buffer */
local_buf = kmalloc(SPI_BUFSIZE, GFP_KERNEL);
if (!local_buf)
return -ENOMEM;
memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
message.complete = spi_fpga_complete;
/* do the i/o */
status = spi_async(spi, &message);
#if 1
//poll_wait(&filp, &port->spi_wait_q, &wait);
//if (status == 0)
memcpy(rxbuf, x[1].rx_buf, n_rx);
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
kfree(local_buf);
printk("%s:line=%d\n",__FUNCTION__,__LINE__);
#endif
return status;
}
#define spi_write spi_fpga_write
#define spi_write_then_read spi_fpga_write_then_read
#endif
/*------------------------spi<70><69>д<EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>-----------------------*/
unsigned int spi_in(struct spi_fpga_port *port, int reg, int type)
{
@@ -138,7 +310,7 @@ void spi_out(struct spi_fpga_port *port, int reg, int value, int type)
{
unsigned char index = 0;
unsigned char tx_buf[3];
//printk("index2=%d,",index);
int reg_temp = reg;
switch(type)
{
#if defined(CONFIG_SPI_FPGA_UART)
@@ -148,6 +320,9 @@ void spi_out(struct spi_fpga_port *port, int reg, int value, int type)
tx_buf[0] = reg & 0xff;
tx_buf[1] = (value>>8) & 0xff;
tx_buf[2] = value & 0xff;
if(reg_temp == UART_IER)
spi_write_work(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf));
else
spi_write(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf));
DBG("%s,SEL_UART reg=0x%x,value=0x%x\n",__FUNCTION__,reg&0xff,value&0xffff);
break;
@@ -347,12 +522,27 @@ static int __devinit spi_fpga_probe(struct spi_device * spi)
if (!port)
return -ENOMEM;
DBG("port=0x%x\n",(int)port);
spin_lock_init(&port->work_lock);
mutex_init(&port->spi_lock);
spin_lock_init(&port->work_lock);
spi_open_sysclk(GPIO_HIGH);
#if SPI_FPGA_TRANS_WORK
init_waitqueue_head(&port->wait_wq);
init_waitqueue_head(&port->wait_rq);
port->write_en = TRUE;
port->read_en = TRUE;
sprintf(b, "fpga_trans_workqueue");
port->fpga_trans_workqueue = create_freezeable_workqueue(b);
if (!port->fpga_trans_workqueue) {
printk("cannot create workqueue\n");
return -EBUSY;
}
INIT_WORK(&port->fpga_trans_work, spi_fpga_trans_work_handler);
INIT_LIST_HEAD(&port->trans_queue);
#endif
spi_fpga_rst();
sprintf(b, "fpga_irq_workqueue");
port->fpga_irq_workqueue = create_freezeable_workqueue(b);

View File

@@ -37,7 +37,7 @@
#endif
#define SPI_UART_TEST 0
int gBaud = 0;
#define SPI_UART_FIFO_LEN 32
#define SPI_UART_TXRX_BUF 1 //send or recieve several bytes one time
@@ -309,6 +309,7 @@ static void spi_uart_change_speed(struct spi_uart *uart,
}
//quot = (2 * uart->uartclk + baud) / (2 * baud);
quot = (uart->uartclk / baud);
//gBaud = baud;
printk("baud=%d,quot=0x%x\n",baud,quot);
if (baud < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
@@ -348,19 +349,17 @@ static void spi_uart_change_speed(struct spi_uart *uart,
*/
uart->ier &= ~UART_IER_MSI;
if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
{
//uart->ier |= UART_IER_MSI;
//uart->mcr = UART_MCR_RTS;//mcr = UART_MCR_RTS while start RTSCTS
}
uart->ier |= UART_IER_MSI;
uart->lcr = cval;
spi_out(port, UART_IER, uart->ier, SEL_UART);
spi_out(port, UART_LCR, cval | UART_LCR_DLAB, SEL_UART);
spi_out(port, UART_DLL, quot & 0xff, SEL_UART);
spi_out(port, UART_DLM, quot >> 8, SEL_UART);
spi_out(port, UART_LCR, cval, SEL_UART);
spi_out(port, UART_FCR, fcr, SEL_UART);
spi_out(port, UART_IER, uart->ier, SEL_UART);//slow
DBG("%s:LINE=%d,baud=%d,uart->ier=0x%x,cval=0x%x,fcr=0x%x,quot=0x%x\n",
__FUNCTION__,__LINE__,baud,uart->ier,cval,fcr,quot);
spi_uart_write_mctrl(uart, uart->mctrl);
@@ -369,30 +368,22 @@ static void spi_uart_change_speed(struct spi_uart *uart,
static void spi_uart_start_tx(struct spi_uart *uart)
{
struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);
#if 1
//unsigned long flags;
if (!(uart->ier & UART_IER_THRI)) {
//spin_lock_irqsave(&uart->write_lock, flags);
uart->ier |= UART_IER_THRI;
spi_out(port, UART_IER, uart->ier, SEL_UART);
//spin_unlock_irqrestore(&uart->write_lock, flags);
printk("t,");
}
DBG("%s:UART_IER=0x%x\n",__FUNCTION__,uart->ier);
#endif
}
static void spi_uart_stop_tx(struct spi_uart *uart)
{
struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);
//unsigned long flags;
if (uart->ier & UART_IER_THRI) {
//spin_lock_irqsave(&uart->write_lock, flags);
uart->ier &= ~UART_IER_THRI;
spi_out(port, UART_IER, uart->ier, SEL_UART);
//spin_unlock_irqrestore(&uart->write_lock, flags);
//printk("p");
}
DBG("%s:UART_IER=0x%x\n",__FUNCTION__,uart->ier);
}
@@ -411,12 +402,18 @@ static void spi_uart_receive_chars(struct spi_uart *uart, unsigned int *status)
struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);
unsigned int ch, flag;
int max_count = 1024;
//printk("rx:");
#if SPI_UART_TXRX_BUF
int ret,count,stat = 0,num = 0;
int i;
unsigned char buf[SPI_UART_FIFO_LEN];
while (max_count >0 )
{
stat = spi_in(port, UART_LSR, SEL_UART);
if((((stat >> 8) & 0x3f) != 0) && (!(stat & UART_LSR_DR)))
printk("%s:warning:no receive data but count =%d \n",__FUNCTION__,((stat >> 8) & 0x3f));
if(!(stat & UART_LSR_DR))
break;
ret = spi_in(port, UART_RX, SEL_UART);
count = (ret >> 8) & 0x3f;
DBG("%s:count=%d\n",__FUNCTION__,count);
@@ -430,21 +427,23 @@ static void spi_uart_receive_chars(struct spi_uart *uart, unsigned int *status)
printk("err:%s:stat=%d,fail to read uart data because of spi bus error!\n",__FUNCTION__,stat);
}
max_count -= count;
while (count-- >0 )
for(i=0;i<count;i++)
{
flag = TTY_NORMAL;
uart->icount.rx++;
ch = buf[num++];
tty_insert_flip_char(tty, ch, flag);
//printk("%c,",ch);
//if(gBaud == 1500000)
//printk("0x%x,",ch);
}
//printk("\n");
}
}
tty_flip_buffer_push(tty);
//if(gBaud == 1500000)
//printk("\n");
#else
//printk("rx:");
while (--max_count >0 )
{
ch = spi_in(port, UART_RX, SEL_UART);//
@@ -533,10 +532,15 @@ static void spi_uart_transmit_chars(struct spi_uart *uart)
if (circ_empty(xmit))
break;
buf[SPI_UART_FIFO_LEN - count] = xmit->buf[xmit->tail];
//if(gBaud == 1500000)
//printk("0x%x,",buf[SPI_UART_FIFO_LEN - count]&0xff);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
uart->icount.tx++;
--count;
}
//if(gBaud == 1500000)
//printk("\n");
if(SPI_UART_FIFO_LEN - count > 0)
spi_uart_write_buf(uart,buf,SPI_UART_FIFO_LEN - count);
#else
@@ -573,7 +577,7 @@ static void spi_uart_transmit_chars(struct spi_uart *uart)
DBG("uart->tty->hw_stopped = %d\n",uart->tty->hw_stopped);
}
#if 0
#if 1
static void spi_uart_check_modem_status(struct spi_uart *uart)
{
int status;
@@ -744,7 +748,7 @@ void spi_uart_handle_irq(struct spi_device *spi)
spi_uart_receive_chars(uart, &lsr);
}
//spi_uart_check_modem_status(uart);
spi_uart_check_modem_status(uart);
if (lsr & UART_LSR_THRE)