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