FPGA ICE65L08XX Driver:SPI2UART SPI2GPIO SPI2I2C SPI2DPRAM
authorroot <root@dxj.(none)>
Fri, 16 Jul 2010 07:11:09 +0000 (15:11 +0800)
committerroot <root@dxj.(none)>
Fri, 16 Jul 2010 07:15:16 +0000 (15:15 +0800)
15 files changed:
.gitignore
arch/arm/mach-rk2818/board-midsdk.c
arch/arm/mach-rk2818/board-phonesdk.c
arch/arm/mach-rk2818/devices.c
drivers/Kconfig
drivers/Makefile
drivers/fpga/Kconfig [new file with mode: 0644]
drivers/fpga/Makefile [new file with mode: 0644]
drivers/fpga/spi_dpram.c [new file with mode: 0644]
drivers/fpga/spi_fpga.h [new file with mode: 0644]
drivers/fpga/spi_fpga_init.c [new file with mode: 0644]
drivers/fpga/spi_gpio.c [new file with mode: 0644]
drivers/fpga/spi_i2c.c [new file with mode: 0644]
drivers/fpga/spi_uart.c [new file with mode: 0644]
include/linux/i2c.h

index 946c7ec5c922ff5bb02726144178f56f57c3378d..28d040bd93664aa9e6290154e92ff73983cfcb49 100644 (file)
@@ -29,6 +29,7 @@
 *.lzma
 *.patch
 *.gcno
+Untitled Project.*
 
 #
 # Top-level generic files
index 33c16a855ef5f94f33b949d1484fff1200c71afb..1d68487a1a1d680a6bea3f1fc4b2cac677ac2ea6 100644 (file)
@@ -287,6 +287,21 @@ struct rk2818_i2c_platform_data default_i2c1_data = {
        .cfg_gpio = rk2818_i2c1_cfg_gpio,
 };
 
+struct rk2818_i2c_platform_data default_i2c2_data = { 
+       .bus_num    = 2,
+       .flags      = 0,
+       .slave_addr = 0xff,
+       .scl_rate  = 400*1000,
+       
+};
+struct rk2818_i2c_platform_data default_i2c3_data = { 
+
+       .bus_num    = 3,
+       .flags      = 0,
+       .slave_addr = 0xff,
+       .scl_rate  = 400*1000,
+       
+};
 static struct i2c_board_info __initdata board_i2c0_devices[] = {
 #if defined (CONFIG_RK1000_CONTROL)
        {
@@ -358,12 +373,27 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
        {},
 };
 
+static struct i2c_board_info __initdata board_i2c2_devices[] = {
+
+};
+static struct i2c_board_info __initdata board_i2c3_devices[] = {
+       
+};     
 
 /*****************************************************************************************
  * SPI devices
  *author: lhh
  *****************************************************************************************/
 static struct spi_board_info board_spi_devices[] = {
+#if defined(CONFIG_SPI_FPGA)
+       {       /* fpga ice65l08xx */
+               .modalias       = "spi_fpga",
+               .chip_select    = 1,
+               .max_speed_hz   = 8 * 1000 * 1000,
+               .bus_num        = 0,
+               .mode   = SPI_MODE_0,
+       },
+#endif
 #if defined(CONFIG_ENC28J60)   
        {       /* net chip */
                .modalias       = "enc28j60",
@@ -424,6 +454,12 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_I2C1_RK2818
        &rk2818_device_i2c1,
 #endif
+#ifdef CONFIG_SPI_I2C
+       &rk2818_device_i2c2,
+#endif
+#ifdef CONFIG_SPI_I2C
+       &rk2818_device_i2c3,
+#endif
 #ifdef CONFIG_SDMMC0_RK2818    
        &rk2818_device_sdmmc0,
 #endif
@@ -506,6 +542,12 @@ static void __init machine_rk2818_board_init(void)
 #ifdef CONFIG_I2C1_RK2818
        i2c_register_board_info(default_i2c1_data.bus_num, board_i2c1_devices,
                        ARRAY_SIZE(board_i2c1_devices));
+#endif
+#ifdef CONFIG_SPI_I2C
+       i2c_register_board_info(default_i2c2_data.bus_num, board_i2c2_devices,
+                       ARRAY_SIZE(board_i2c2_devices));
+       i2c_register_board_info(default_i2c3_data.bus_num, board_i2c3_devices,
+                       ARRAY_SIZE(board_i2c3_devices));
 #endif
        platform_add_devices(devices, ARRAY_SIZE(devices));     
        spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices));
index 29576e350747844099f8dbddefacf19486fbd872..401bd72ff0167119ec9a6f339eb29554e9c9dcec 100644 (file)
@@ -285,6 +285,21 @@ struct rk2818_i2c_platform_data default_i2c1_data = {
        .cfg_gpio = rk2818_i2c1_cfg_gpio,
 };
 
+struct rk2818_i2c_platform_data default_i2c2_data = { 
+       .bus_num    = 2,
+       .flags      = 0,
+       .slave_addr = 0xff,
+       .scl_rate  = 400*1000,
+       
+};
+struct rk2818_i2c_platform_data default_i2c3_data = { 
+
+       .bus_num    = 3,
+       .flags      = 0,
+       .slave_addr = 0xff,
+       .scl_rate  = 400*1000,
+       
+};
 static struct i2c_board_info __initdata board_i2c0_devices[] = {
 #if defined (CONFIG_RK1000_CONTROL)
        {
@@ -352,16 +367,39 @@ static struct i2c_board_info __initdata board_i2c1_devices[] = {
                .addr           = 0x79, 
                .flags                  = 0,
        },
+#endif
+#if defined (CONFIG_GS_MMA7660)
+    {
+        .type           = "gs_mma7660",
+        .addr           = 0x4c,
+        .flags          = 0,
+        .irq            = RK2818_PIN_PE3,
+    },
 #endif
        {},
 };
 
+static struct i2c_board_info __initdata board_i2c2_devices[] = {
+
+};
+static struct i2c_board_info __initdata board_i2c3_devices[] = {
+       
+};     
 
 /*****************************************************************************************
  * SPI devices
  *author: lhh
  *****************************************************************************************/
 static struct spi_board_info board_spi_devices[] = {
+#if defined(CONFIG_SPI_FPGA)
+       {       /* fpga ice65l08xx */
+               .modalias       = "spi_fpga",
+               .chip_select    = 1,
+               .max_speed_hz   = 8 * 1000 * 1000,
+               .bus_num        = 0,
+               .mode   = SPI_MODE_0,
+       },
+#endif
 #if defined(CONFIG_ENC28J60)   
        {       /* net chip */
                .modalias       = "enc28j60",
@@ -422,6 +460,12 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_I2C1_RK2818
        &rk2818_device_i2c1,
 #endif
+#ifdef CONFIG_SPI_I2C
+       &rk2818_device_i2c2,
+#endif
+#ifdef CONFIG_SPI_I2C
+       &rk2818_device_i2c3,
+#endif
 #ifdef CONFIG_SDMMC0_RK2818    
        &rk2818_device_sdmmc0,
 #endif
@@ -504,6 +548,12 @@ static void __init machine_rk2818_board_init(void)
 #ifdef CONFIG_I2C1_RK2818
        i2c_register_board_info(default_i2c1_data.bus_num, board_i2c1_devices,
                        ARRAY_SIZE(board_i2c1_devices));
+#endif
+#ifdef CONFIG_SPI_I2C
+       i2c_register_board_info(default_i2c2_data.bus_num, board_i2c2_devices,
+                       ARRAY_SIZE(board_i2c2_devices));
+       i2c_register_board_info(default_i2c3_data.bus_num, board_i2c3_devices,
+                       ARRAY_SIZE(board_i2c3_devices));
 #endif
        platform_add_devices(devices, ARRAY_SIZE(devices));     
        spi_register_board_info(board_spi_devices, ARRAY_SIZE(board_spi_devices));
index 7f37dea89b7ae7da78f89bae23a1d3d151adaccd..001c368280c278b0b2b554fa2c2b220ee50e6ca5 100644 (file)
@@ -169,7 +169,20 @@ struct platform_device rk2818_device_i2c1 = {
                .platform_data = &default_i2c1_data,
        },
 };
-
+struct platform_device rk2818_device_i2c2 = {
+       .name   = "fpga_i2c",
+       .id     = 2,    
+       .dev                    = {
+               .platform_data = &default_i2c2_data,
+       },
+};
+struct platform_device rk2818_device_i2c3 = {
+       .name   = "fpga_i2c",
+       .id     = 3,    
+       .dev                    = {
+               .platform_data = &default_i2c3_data,
+       },
+};
 struct platform_device rk2818_device_uart0 = {
        .name   = "rk2818_serial",
        .id     = 0,
index 5dacbbd4248393c1998fd48bd884fa6f811df86c..d03c2e90610b297380597506d2130be4de20f308 100644 (file)
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/fpga/Kconfig"
+
 source "drivers/pps/Kconfig"
 
 source "drivers/gpio/Kconfig"
index a66fbf89813043ef5958378a601a268dc58a3cdc..f7101a6135717f93748b90e0d6e541bb8c838c42 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_SCSI)            += scsi/
 obj-$(CONFIG_ATA)              += ata/
 obj-$(CONFIG_MTD)              += mtd/
 obj-$(CONFIG_SPI)              += spi/
+obj-$(CONFIG_SPI_FPGA)         += fpga/
 obj-y                          += net/
 obj-$(CONFIG_ATM)              += atm/
 obj-$(CONFIG_FUSION)           += message/
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
new file mode 100644 (file)
index 0000000..47413b0
--- /dev/null
@@ -0,0 +1,86 @@
+#\r
+# FPGA driver configuration\r
+#\r
+# NOTE:  This FPGA(ice65l08xx) support spi2uart,spi2gpio,spi2i2c and spi2dpram.\r
+#\r
+\r
+menuconfig SPI_FPGA\r
+       bool "SPI FPGA(ice65l08xx) support"\r
+       #depends on SPI && SPIM_RK2818\r
+       help\r
+       This fpga(ice65l08xx) is used for spi2uart,spi2gpio,spi2i2c,spi2dpram.\r
+         \r
+if SPI_FPGA\r
+\r
+config SPI_FPGA_INIT\r
+       tristate "spi fpga init support"\r
+       depends on SPI && SPIM_RK2818\r
+       help\r
+       fpga driver for spi init.\r
+\r
+if SPI_FPGA_INIT\r
+       config SPI_FPGA_INIT_DEBUG\r
+       boolean "Debug support for spi fpga init drivers"\r
+       depends on DEBUG_KERNEL\r
+       help\r
+       Say "yes" to enable debug messaging in spi fpga init drivers.\r
+endif\r
+\r
+config SPI_UART\r
+       tristate "spi to uart support"\r
+       depends on SPI && SPIM_RK2818\r
+       help\r
+       fpga driver for spi to uart.\r
+       \r
+if SPI_UART\r
+       config SPI_UART_DEBUG\r
+       boolean "Debug support for spi to uart drivers"\r
+       depends on DEBUG_KERNEL\r
+       help\r
+       Say "yes" to enable debug messaging in spi to uart drivers.\r
+endif\r
+\r
+config SPI_GPIO\r
+       tristate "spi to gpio support"\r
+       depends on SPI && SPIM_RK2818\r
+       help\r
+       fpga driver for spi to gpio.\r
+\r
+if SPI_GPIO\r
+       config SPI_GPIO_DEBUG\r
+       boolean "Debug support for spi to gpio drivers"\r
+       depends on DEBUG_KERNEL\r
+       help\r
+       Say "yes" to enable debug messaging in spi to gpio drivers.\r
+endif\r
+\r
+config SPI_I2C\r
+       tristate "spi to i2c support"\r
+       depends on SPI && SPIM_RK2818\r
+       help\r
+       fpga driver for spi to i2c.\r
+\r
+if SPI_I2C\r
+       config SPI_I2C_DEBUG\r
+       boolean "Debug support for spi to i2c drivers"\r
+       depends on DEBUG_KERNEL\r
+       help\r
+       Say "yes" to enable debug messaging in spi to i2c drivers.\r
+endif\r
+\r
+config SPI_DPRAM\r
+       tristate "spi to dpram support"\r
+       depends on SPI && SPIM_RK2818\r
+       help\r
+       fpga driver for spi to dpram.\r
+\r
+if SPI_DPRAM\r
+       config SPI_DPRAM_DEBUG\r
+       boolean "Debug support for spi to dpram drivers"\r
+       depends on DEBUG_KERNEL\r
+       help\r
+       Say "yes" to enable debug messaging in spi to dpram drivers.\r
+endif\r
+\r
+endif\r
+\r
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
new file mode 100644 (file)
index 0000000..a712a53
--- /dev/null
@@ -0,0 +1,10 @@
+#\r
+# Makefile for fpga(ice65l08xx) drivers.\r
+#\r
+\r
+# fpga drivers\r
+obj-$(CONFIG_SPI_FPGA_INIT)            += spi_fpga_init.o\r
+obj-$(CONFIG_SPI_UART)                 += spi_uart.o\r
+obj-$(CONFIG_SPI_GPIO)                 += spi_gpio.o\r
+obj-$(CONFIG_SPI_I2C)                  += spi_i2c.o\r
+obj-$(CONFIG_SPI_DPRAM)                        += spi_dpram.o
\ No newline at end of file
diff --git a/drivers/fpga/spi_dpram.c b/drivers/fpga/spi_dpram.c
new file mode 100644 (file)
index 0000000..f0e112d
--- /dev/null
@@ -0,0 +1,654 @@
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/mutex.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/gfp.h>\r
+#include <linux/tty.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/spi/spi.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/ioport.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/sched.h>\r
+#include <linux/kthread.h>\r
+#include <linux/jiffies.h>\r
+#include <linux/i2c.h>\r
+#include <mach/rk2818_iomap.h>\r
+\r
+#include "spi_fpga.h"\r
+\r
+#if defined(CONFIG_SPI_DPRAM_DEBUG)\r
+#define DBG(x...)   printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define SPI_DPRAM_TEST 0\r
+/*****RAM0 for bp write and ap read*****/\r
+#define SPI_DPRAM_BPWRITE_START 0\r
+#define SPI_DPRAM_BPWRITE_END  0x0fff\r
+#define SPI_DPRAM_BPWRITE_SIZE 0x1000  // 4K*16bits\r
+/*****RAM1 for ap write and bp read*****/\r
+#define SPI_DPRAM_APWRITE_START 0x1000\r
+#define SPI_DPRAM_APWRITE_END   0x17ff\r
+#define SPI_DPRAM_APWRITE_SIZE 0x0800  // 2K*16bits\r
+/*****RAM2 for log of bp write and ap read*****/\r
+#define SPI_DPRAM_LOG_BPWRITE_START 0x2000\r
+#define SPI_DPRAM_LOG_BPWRITE_END      0x23ff\r
+#define SPI_DPRAM_LOG_BPWRITE_SIZE     0x0400  // 1K*16bits\r
+/*****RAM3 for log of ap write and bp read*****/\r
+#define SPI_DPRAM_LOG_APWRITE_START 0x3000\r
+#define SPI_DPRAM_LOG_APWRITE_END   0x33ff\r
+#define SPI_DPRAM_LOG_APWRITE_SIZE     0x0400  // 1K*16bits\r
+\r
+/*\r
+#define BP_SEND_IN_PTR   0x3FEE\r
+#define BP_SEND_OUT_PTR  0x3FF0\r
+\r
+#define BP_READ_IN_PTR    0x3FF2\r
+#define BP_READ_OUT_PTR   0x3FF4\r
+\r
+#define BP_SEND_IN_PTR   0x3FF6\r
+#define BP_SEND_OUT_PTR  0x3FF8\r
+\r
+#define BP_READ_IN_PTR    0x3FFA\r
+#define BP_READ_OUT_PTR   0x3FFC\r
+\r
+#define BP_SEND_AP_Mailbox£º0x3ffe\r
+#define AP_SEND_BP_Mailbox£º0x3fff\r
+\r
+*/\r
+\r
+#define SPI_DPRAM_PTR0_BPWRITE_APREAD  0X3fee\r
+#define        SPI_DPRAM_PTR0_APWRITE_BPREAD   0X3ff0\r
+\r
+#define SPI_DPRAM_PTR1_BPWRITE_APREAD  0x3ff2\r
+#define        SPI_DPRAM_PTR1_APWRITE_BPREAD   0x3ff4\r
+\r
+#define SPI_DPRAM_PTR2_BPWRITE_APREAD  0x3ff6\r
+#define        SPI_DPRAM_PTR2_APWRITE_BPREAD   0x3ff8\r
+\r
+#define SPI_DPRAM_PTR3_BPWRITE_APREAD  0x3ffa\r
+#define        SPI_DPRAM_PTR3_APWRITE_BPREAD   0x3ffc\r
+\r
+#define SPI_DPRAM_MAILBOX_BPWRITE      0x3ffe\r
+#define SPI_DPRAM_MAILBOX_APWRITE      0x3fff\r
+\r
+/*mailbox comminication's definition*/\r
+#define MAILBOX_BPWRITE_DATA   0x01\r
+#define MAILBOX_BPREAD_DATA            0x02\r
+#define MAILBOX_APSEND_IRQ             0x03\r
+#define MAILBOX_APSEND_ACK             0x04\r
+\r
+#define TRUE           1\r
+#define FALSE          0\r
+\r
+static int spi_dpram_write_buf(struct spi_dpram *dpram, unsigned short int addr, unsigned char *buf, unsigned int len)\r
+{      \r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL) | ICE_SEL_DPRAM_WRITE);\r
+       unsigned char *tx_buf = port->dpram.ptx;        \r
+       int ret;\r
+       *(port->dpram.ptx) = opt;\r
+       *(port->dpram.ptx+1) = ((addr << 1) >> 8) & 0xff;\r
+       *(port->dpram.ptx+2) = ((addr << 1) & 0xff);\r
+       memcpy((port->dpram.ptx + 3), buf, len);\r
+       \r
+       DBG("%s:tx_buf=0x%x,port->dpram.ptx=0x%x,opt=0x%x,addr=0x%x,len=%d\n",__FUNCTION__,(int)tx_buf, (int)port->dpram.ptx, opt, addr&0xffff, len);\r
+       ret = spi_write(port->spi, tx_buf, len+3);\r
+       if(ret)\r
+       printk("spi_write err!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n");\r
+       return 0;\r
+}\r
+\r
+static int spi_dpram_read_buf(struct spi_dpram *dpram, unsigned short int addr, unsigned char *buf, unsigned int len)\r
+{\r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL & ICE_SEL_DPRAM_READ));\r
+       unsigned char tx_buf[3];\r
+       unsigned char stat;\r
+       \r
+       tx_buf[0] = opt;\r
+       tx_buf[1] = ((addr << 1) >> 8) & 0xff;\r
+       tx_buf[2] = ((addr << 1) & 0xff);\r
+       \r
+       stat = spi_write_then_read(port->spi, tx_buf, sizeof(tx_buf), buf, len);        \r
+       if(stat)\r
+       {\r
+               printk("%s:spi_write_then_read is error!,err=%d\n\n",__FUNCTION__,stat);\r
+               return -1;\r
+       }\r
+       DBG("%s:opt=0x%x,addr=0x%x,len=%d\n",__FUNCTION__, opt, addr&0xffff, len);\r
+       return 0;\r
+\r
+}\r
+\r
+\r
+int spi_dpram_write_ptr(struct spi_dpram *dpram, unsigned short int addr, unsigned int size)\r
+{\r
+       int ret;\r
+       //int i;\r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL) | ICE_SEL_DPRAM_WRITE);\r
+       unsigned char tx_buf[5];\r
+       \r
+       tx_buf[0] = opt;\r
+       tx_buf[1] = ((addr << 1) >> 8) & 0xff;\r
+       tx_buf[2] = ((addr << 1) & 0xff);\r
+       tx_buf[3] = (size>>8);\r
+       tx_buf[4] = (size&0xff);\r
+\r
+       //for(i=0;i<5;i++)\r
+       //{\r
+       //      printk("%s:tx_buf[%d]=0x%x\n",__FUNCTION__,i,tx_buf[i]);\r
+       //}\r
+\r
+       ret = spi_write(port->spi, tx_buf, sizeof(tx_buf));\r
+       if(ret)\r
+       {\r
+               printk("%s:spi_write err!\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+       return 0;\r
+\r
+}\r
+\r
+\r
+int spi_dpram_read_ptr(struct spi_dpram *dpram, unsigned short int addr)\r
+{\r
+       int ret;\r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL & ICE_SEL_DPRAM_READ));\r
+       unsigned char tx_buf[3],rx_buf[2];\r
+       \r
+       tx_buf[0] = opt;\r
+       tx_buf[1] = ((addr << 1) >> 8) & 0xff;\r
+       tx_buf[2] = ((addr << 1) & 0xff);\r
+\r
+       ret = spi_write_then_read(port->spi, tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));\r
+       if(ret)\r
+       {\r
+               printk("%s:spi_write_then_read err!\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+       ret = (rx_buf[0] << 8) | rx_buf[1];\r
+       \r
+       return (ret&0xffff);\r
+\r
+}\r
+\r
+\r
+int spi_dpram_write_mailbox(struct spi_dpram *dpram, unsigned int mailbox)\r
+{\r
+       int ret;\r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL) | ICE_SEL_DPRAM_WRITE);\r
+       unsigned char tx_buf[5];\r
+       \r
+       tx_buf[0] = opt;\r
+       tx_buf[1] = ((SPI_DPRAM_MAILBOX_APWRITE << 1) >> 8) & 0xff;\r
+       tx_buf[2] = ((SPI_DPRAM_MAILBOX_APWRITE << 1) & 0xff);\r
+       tx_buf[3] = mailbox>>8;\r
+       tx_buf[4] = mailbox&0xff;\r
+       \r
+       ret = spi_write(port->spi, tx_buf, sizeof(tx_buf));\r
+       if(ret)\r
+       {\r
+               printk("%s:spi_write err!\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+       return 0;\r
+}\r
+\r
+\r
+int spi_dpram_read_mailbox(struct spi_dpram *dpram)\r
+{\r
+       int ret;\r
+       struct spi_fpga_port *port = container_of(dpram, struct spi_fpga_port, dpram);\r
+       unsigned char opt = ((ICE_SEL_DPRAM & ICE_SEL_DPRAM_NOMAL & ICE_SEL_DPRAM_READ));\r
+       unsigned char tx_buf[3],rx_buf[2];\r
+       \r
+       tx_buf[0] = opt;\r
+       tx_buf[1] = ((SPI_DPRAM_MAILBOX_BPWRITE << 1) >> 8) & 0xff;\r
+       tx_buf[2] = ((SPI_DPRAM_MAILBOX_BPWRITE << 1) & 0xff);\r
+\r
+       ret = spi_write_then_read(port->spi, tx_buf, sizeof(tx_buf), rx_buf, sizeof(rx_buf));\r
+       if(ret)\r
+       {\r
+               printk("%s:spi_write_then_read err!\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+       return ((rx_buf[0]<<8) | rx_buf[1]);\r
+}\r
+\r
+\r
+static void spi_dpram_handle_busy(struct spi_device *spi)\r
+{      \r
+\r
+}\r
+\r
+\r
+static void spi_dpram_busy_work_handler(struct work_struct *work)\r
+{\r
+       struct spi_fpga_port *port =\r
+               container_of(work, struct spi_fpga_port, dpram.spi_dpram_busy_work);\r
+       spi_dpram_handle_busy(port->spi);\r
+}\r
+\r
+\r
+static irqreturn_t spi_dpram_busy_irq(int irq, void *dev_id)\r
+{\r
+       struct spi_fpga_port *port = dev_id;\r
+\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       /*\r
+        * Can't do anything in interrupt context because we need to\r
+        * block (spi_sync() is blocking) so fire of the interrupt\r
+        * handling workqueue.\r
+        * Remember that we access ICE65LXX registers through SPI bus\r
+        * via spi_sync() call.\r
+        */\r
+\r
+       queue_work(port->dpram.spi_dpram_busy_workqueue, &port->dpram.spi_dpram_busy_work);\r
+       \r
+       return IRQ_HANDLED;\r
+}\r
+\r
+#if SPI_DPRAM_TEST\r
+#define DPRAM_TEST_LEN 512     //8bit\r
+unsigned char buf_test_dpram[DPRAM_TEST_LEN];\r
+void spi_dpram_work_handler(struct work_struct *work)\r
+{\r
+       int i;\r
+       int ret;\r
+       struct spi_fpga_port *port =\r
+               container_of(work, struct spi_fpga_port, dpram.spi_dpram_work);\r
+       printk("*************test spi_dpram now***************\n");\r
+\r
+       for(i=0; i<(DPRAM_TEST_LEN>>1); i++)\r
+       {\r
+               buf_test_dpram[2*i] = (0xa000+i)>>8;\r
+               buf_test_dpram[2*i+1] = (0xa000+i)&0xff;\r
+       }\r
+#if 0\r
+       //RAM0\r
+       for(i=0;i<(SPI_DPRAM_BPWRITE_SIZE/(DPRAM_TEST_LEN>>1));i++)\r
+       {\r
+               spi_dpram_read_buf(&port->dpram, SPI_DPRAM_BPWRITE_START+(i*DPRAM_TEST_LEN>>1), port->dpram.prx, DPRAM_TEST_LEN);\r
+       }\r
+       \r
+       for(i=0;i<DPRAM_TEST_LEN;i++)\r
+       {\r
+               ret = (*(port->dpram.prx+2*i)<<8) | (*(port->dpram.prx+2*i+1));\r
+               if(ret != 0xa000+i)\r
+               printk("prx[%d]=0x%x ram[%d]=0x%x\n",i,ret&0xffff,i,0xa000+i);\r
+       }\r
+#endif\r
+\r
+       \r
+#if 0  \r
+       //RAM1\r
+       for(i=0;i<(SPI_DPRAM_APWRITE_SIZE/(DPRAM_TEST_LEN>>1));i++)\r
+       {                               \r
+               port->dpram.write_dpram(&port->dpram, ((DPRAM_TEST_LEN*i)>>1)+SPI_DPRAM_APWRITE_START, buf_test_dpram, sizeof(buf_test_dpram));\r
+               mdelay(1);\r
+       }\r
+\r
+       for(i=0;i<DPRAM_TEST_LEN;i++)\r
+       printk("buf_test_dpram[%d]=0x%x\n",i,buf_test_dpram[i]);\r
+       DBG("\n");\r
+#endif\r
+\r
+\r
+#if 0\r
+       //RAM2\r
+       for(i=0;i<(SPI_DPRAM_LOG_BPWRITE_SIZE/(DPRAM_TEST_LEN>>1));i++)\r
+       {\r
+               spi_dpram_read_buf(&port->dpram, SPI_DPRAM_LOG_BPWRITE_START+(i*DPRAM_TEST_LEN>>1), port->dpram.prx, DPRAM_TEST_LEN);\r
+       }\r
+       \r
+       for(i=0;i<DPRAM_TEST_LEN;i++)\r
+       {               \r
+               ret = (*(port->dpram.prx+2*i)<<8) | (*(port->dpram.prx+2*i+1));\r
+               if(ret != 0xc000+i)\r
+               printk("prx[%d]=0x%x ram[%d]=0x%x\n",i,ret&0xffff,i,0xc000+i);\r
+       }\r
+#endif\r
+\r
+#if 0  \r
+       //RAM3\r
+       for(i=0;i<(SPI_DPRAM_LOG_APWRITE_SIZE/(DPRAM_TEST_LEN>>1));i++)\r
+       {                               \r
+               spi_dpram_write_buf(&port->dpram, ((DPRAM_TEST_LEN*i)>>1)+SPI_DPRAM_LOG_APWRITE_START, buf_test_dpram, sizeof(buf_test_dpram));\r
+               mdelay(1);\r
+       }\r
+       \r
+       for(i=0;i<DPRAM_TEST_LEN;i++)\r
+       printk("buf_test_dpram[%d]=0x%x\n",i,buf_test_dpram[i]);\r
+       DBG("\n");\r
+#endif\r
+\r
+#if 1\r
+       port->dpram.write_ptr(&port->dpram, SPI_DPRAM_PTR0_APWRITE_BPREAD, SPI_DPRAM_PTR0_APWRITE_BPREAD);\r
+       port->dpram.write_ptr(&port->dpram, SPI_DPRAM_PTR1_APWRITE_BPREAD, SPI_DPRAM_PTR1_APWRITE_BPREAD);\r
+       port->dpram.write_ptr(&port->dpram, SPI_DPRAM_PTR2_APWRITE_BPREAD, SPI_DPRAM_PTR2_APWRITE_BPREAD);\r
+       port->dpram.write_ptr(&port->dpram, SPI_DPRAM_PTR3_APWRITE_BPREAD, SPI_DPRAM_PTR3_APWRITE_BPREAD);\r
+       port->dpram.write_mailbox(&port->dpram, SPI_DPRAM_MAILBOX_APWRITE);\r
+\r
+       ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR0_BPWRITE_APREAD);\r
+       if(ret != SPI_DPRAM_PTR0_BPWRITE_APREAD)\r
+       {\r
+               //ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR0_BPWRITE_APREAD);\r
+               //if(ret != SPI_DPRAM_PTR0_BPWRITE_APREAD)\r
+               printk("SPI_DPRAM_PTR0_BPWRITE_APREAD(0x%x)=0x%x\n",SPI_DPRAM_PTR0_BPWRITE_APREAD,ret);\r
+       }\r
+       \r
+       ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR1_BPWRITE_APREAD);\r
+       if(ret != SPI_DPRAM_PTR1_BPWRITE_APREAD)\r
+       {\r
+               //ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR1_BPWRITE_APREAD);\r
+               //if(ret != SPI_DPRAM_PTR1_BPWRITE_APREAD)\r
+               printk("SPI_DPRAM_PTR1_BPWRITE_APREAD(0x%x)=0x%x\n",SPI_DPRAM_PTR1_BPWRITE_APREAD,ret);\r
+       }\r
+       \r
+       ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR2_BPWRITE_APREAD);\r
+       if(ret != SPI_DPRAM_PTR2_BPWRITE_APREAD)\r
+       {\r
+               //ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR2_BPWRITE_APREAD);\r
+               //if(ret != SPI_DPRAM_PTR2_BPWRITE_APREAD)\r
+               printk("SPI_DPRAM_PTR2_BPWRITE_APREAD(0x%x)=0x%x\n",SPI_DPRAM_PTR2_BPWRITE_APREAD,ret);\r
+       }\r
+\r
+\r
+       ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR3_BPWRITE_APREAD);\r
+       if(ret != SPI_DPRAM_PTR3_BPWRITE_APREAD)\r
+       {\r
+               //ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_PTR3_BPWRITE_APREAD);\r
+               //if(ret != SPI_DPRAM_PTR3_BPWRITE_APREAD)      \r
+               printk("SPI_DPRAM_PTR3_BPWRITE_APREAD(0x%x)=0x%x\n",SPI_DPRAM_PTR3_BPWRITE_APREAD,ret);\r
+\r
+       }\r
+       mdelay(10);\r
+\r
+       ret = port->dpram.read_mailbox(&port->dpram);\r
+       if(ret != SPI_DPRAM_MAILBOX_BPWRITE)\r
+       {\r
+               //ret = port->dpram.read_ptr(&port->dpram, SPI_DPRAM_MAILBOX_BPWRITE);\r
+               //if(ret != SPI_DPRAM_MAILBOX_BPWRITE)  \r
+               printk("SPI_DPRAM_MAILBOX_BPWRITE(0x%x)=0x%x\n",SPI_DPRAM_MAILBOX_BPWRITE,ret);\r
+       }\r
+\r
+#endif\r
+\r
+\r
+}\r
+\r
+static void spi_testdpram_timer(unsigned long data)\r
+{\r
+       struct spi_fpga_port *port = (struct spi_fpga_port *)data;\r
+       port->dpram.dpram_timer.expires  = jiffies + msecs_to_jiffies(1000);\r
+       add_timer(&port->dpram.dpram_timer);\r
+       //schedule_work(&port->gpio.spi_gpio_work);\r
+       queue_work(port->dpram.spi_dpram_workqueue, &port->dpram.spi_dpram_work);\r
+}\r
+\r
+#endif\r
+\r
+\r
+int spi_dpram_handle_irq(struct spi_device *spi)\r
+{\r
+       struct spi_fpga_port *port = spi_get_drvdata(spi);\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+#if 0\r
+       unsigned char mbox = port->dpram.read_mailbox(&port->dpram);\r
+       unsigned int len;\r
+       switch(mbox)\r
+       {\r
+               case MAILBOX_BPWRITE_DATA:\r
+                       len = port->dpram.read_ptr(&port->dpram,SPI_DPRAM_PTR0_BPWRITE_APREAD);\r
+                       port->dpram.read_dpram(&port->dpram, SPI_DPRAM_BPWRITE_START, port->dpram.prx, len);\r
+                       port->dpram.rec_len += len;\r
+                       break;\r
+               case MAILBOX_BPREAD_DATA:\r
+                       port->dpram.apwrite_en = TRUE;\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+#endif \r
+       return 0;\r
+}\r
+\r
+static int dpr_open(struct inode *inode, struct file *filp)\r
+{\r
+    struct spi_fpga_port *port = pFpgaPort;\r
+\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       filp->private_data = port;\r
+       port->dpram.rec_len = 0;\r
+       port->dpram.send_len = 0;\r
+       port->dpram.apwrite_en = TRUE;\r
+\r
+    return nonseekable_open(inode, filp);\r
+}\r
+\r
+\r
+static int dpr_close(struct inode *inode, struct file *filp)\r
+{\r
+       struct spi_fpga_port *port = pFpgaPort;\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       filp->private_data = NULL;\r
+       return 0;\r
+}\r
+\r
+\r
+static ssize_t dpr_read (struct file *filp, char __user *buffer, size_t count, loff_t *ppos)\r
+{\r
+       //int ret;\r
+       struct spi_fpga_port *port = filp->private_data;\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       \r
+       while(port->dpram.rec_len == 0)\r
+       {\r
+               if( filp->f_flags&O_NONBLOCK )\r
+               return -EAGAIN;\r
+\r
+               if(wait_event_interruptible(port->dpram.recq, (port->dpram.rec_len != 0)))\r
+               {       \r
+                       printk("%s:NO data in dpram!\n",__FUNCTION__);\r
+                       return -ERESTARTSYS;   \r
+               }\r
+       }\r
+\r
+       /*read data from buffer*/\r
+       if(copy_to_user((char*)buffer, (char *)port->dpram.prx, port->dpram.rec_len))\r
+    {\r
+        printk("%s:copy_to_user err!\n",__FUNCTION__);\r
+        return -EFAULT;\r
+    }\r
+\r
+       count = port->dpram.rec_len;\r
+       port->dpram.rec_len = 0;\r
+       \r
+       return count;\r
+}\r
+\r
+\r
+static ssize_t dpr_write (struct file *filp, const char __user *buffer, size_t count, loff_t *ppos)\r
+{\r
+       struct spi_fpga_port *port = filp->private_data;\r
+       //int ret;\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port); \r
+       \r
+       while(port->dpram.apwrite_en == FALSE)\r
+       {\r
+               if(filp->f_flags & O_NONBLOCK)\r
+            return -EAGAIN;\r
+        if(wait_event_interruptible(port->dpram.sendq, (port->dpram.apwrite_en == TRUE)))\r
+            return -ERESTARTSYS;\r
+       }\r
+\r
+       if(count > port->dpram.max_send_len)\r
+       {\r
+               count = port->dpram.max_send_len;\r
+               printk("%s:count is large than max_send_len(%d),and only %d's bytes is valid!\n",__FUNCTION__,count,count);\r
+       }\r
+       \r
+       if(copy_from_user((char *)port->dpram.ptx,buffer,count))\r
+       {\r
+               printk("%s:copy_from_user err!\n",__FUNCTION__);\r
+               return -EFAULT;\r
+       }\r
+\r
+       port->dpram.write_dpram(&port->dpram, SPI_DPRAM_APWRITE_START, port->dpram.ptx, count);\r
+       port->dpram.apwrite_en = FALSE; //clear apwrite_en after wirte data to dpram\r
+       port->dpram.write_mailbox(&port->dpram, MAILBOX_APSEND_IRQ);    //send irq to bp after ap write data to dpram\r
+\r
+       return count;\r
+    \r
+}\r
+\r
+\r
+unsigned int dpr_poll(struct file *filp, struct poll_table_struct * wait)\r
+{\r
+       unsigned int mask = 0;\r
+       struct spi_fpga_port *port = filp->private_data;\r
+\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+\r
+       return mask;\r
+}\r
+\r
+\r
+static struct file_operations dpr_fops={\r
+       .owner=   THIS_MODULE,\r
+       .open=    dpr_open,\r
+       .release= dpr_close,\r
+       .read=    dpr_read,\r
+       .write=   dpr_write,\r
+       .poll =   dpr_poll,\r
+};\r
+\r
+int spi_dpram_register(struct spi_fpga_port *port)\r
+{\r
+       char b[28];\r
+       int ret;\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       port->dpram.prx = (char *)kzalloc(sizeof(char)*((SPI_DPRAM_BPWRITE_SIZE<<1)+6), GFP_KERNEL);\r
+       if(port->dpram.prx == NULL)\r
+       {\r
+           printk("port->dpram.prx kzalloc err!!!\n");\r
+           return -ENOMEM;\r
+       }\r
+\r
+       port->dpram.ptx = (char *)kzalloc(sizeof(char)*((SPI_DPRAM_APWRITE_SIZE<<1)+6), GFP_KERNEL);\r
+       if(port->dpram.ptx == NULL)\r
+       {\r
+           printk("port->dpram.ptx kzalloc err!!!\n");\r
+           return -ENOMEM;\r
+       }\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       sprintf(b, "spi_dpram_busy_workqueue");\r
+       port->dpram.spi_dpram_busy_workqueue = create_freezeable_workqueue(b);\r
+       if (!port->dpram.spi_dpram_busy_workqueue) {\r
+               printk("cannot create workqueue\n");\r
+               return -EBUSY;\r
+       }       \r
+       INIT_WORK(&port->dpram.spi_dpram_busy_work, spi_dpram_busy_work_handler);\r
+       \r
+#if SPI_DPRAM_TEST\r
+       sprintf(b, "spi_dpram_workqueue");\r
+       port->dpram.spi_dpram_workqueue = create_freezeable_workqueue(b);\r
+       if (!port->dpram.spi_dpram_workqueue) {\r
+               printk("cannot create workqueue\n");\r
+               return -EBUSY;\r
+       }\r
+       INIT_WORK(&port->dpram.spi_dpram_work, spi_dpram_work_handler);\r
+\r
+       setup_timer(&port->dpram.dpram_timer, spi_testdpram_timer, (unsigned long)port);\r
+       port->dpram.dpram_timer.expires  = jiffies+2000;//>1000ms\r
+       add_timer(&port->dpram.dpram_timer);\r
+#endif\r
+\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+\r
+       //init the struct spi_dpram\r
+       init_waitqueue_head(&port->dpram.recq);\r
+       init_waitqueue_head(&port->dpram.sendq);\r
+       port->dpram.rec_len = 0;\r
+       port->dpram.send_len = 0;\r
+       port->dpram.apwrite_en = TRUE;\r
+       port->dpram.max_rec_len = SPI_DPRAM_BPWRITE_SIZE;\r
+       port->dpram.max_send_len = SPI_DPRAM_APWRITE_SIZE;\r
+       port->dpram.miscdev.minor = MISC_DYNAMIC_MINOR;\r
+       port->dpram.miscdev.name = "spi_dpram";//spi_fpga\r
+       port->dpram.miscdev.fops = &dpr_fops;\r
+\r
+       ret = misc_register(&port->dpram.miscdev);\r
+       if(ret)\r
+       {\r
+           printk("misc_register err!!!\n");\r
+           goto err0;\r
+       }\r
+\r
+       port->dpram.write_dpram = spi_dpram_write_buf;\r
+       port->dpram.read_dpram = spi_dpram_read_buf;\r
+       port->dpram.write_ptr = spi_dpram_write_ptr;\r
+       port->dpram.read_ptr = spi_dpram_read_ptr;\r
+       port->dpram.write_mailbox = spi_dpram_write_mailbox;\r
+       port->dpram.read_mailbox = spi_dpram_read_mailbox;\r
+       \r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+\r
+       ret = gpio_request(SPI_DPRAM_BUSY_PIN, NULL);\r
+       if (ret) {\r
+               printk("%s:failed to request fpga busy gpio\n",__FUNCTION__);\r
+               goto err1;\r
+       }\r
+\r
+       gpio_pull_updown(SPI_DPRAM_BUSY_PIN,GPIOPullUp);\r
+       ret = request_irq(gpio_to_irq(SPI_DPRAM_BUSY_PIN),spi_dpram_busy_irq,IRQF_TRIGGER_RISING,NULL,port);\r
+       if(ret)\r
+       {\r
+               printk("unable to request fpga busy_gpio irq\n");\r
+               goto err2;\r
+       }       \r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       \r
+       return 0;\r
+       \r
+err2:\r
+       free_irq(gpio_to_irq(SPI_DPRAM_BUSY_PIN),NULL);\r
+err1:  \r
+       gpio_free(SPI_DPRAM_BUSY_PIN);\r
+err0:\r
+       kfree(port->dpram.prx);\r
+       kfree(port->dpram.ptx);\r
+\r
+       return ret;\r
+       \r
+}\r
+\r
+int spi_dpram_unregister(struct spi_fpga_port *port)\r
+{\r
+\r
+       return 0;\r
+}\r
+\r
+\r
diff --git a/drivers/fpga/spi_fpga.h b/drivers/fpga/spi_fpga.h
new file mode 100644 (file)
index 0000000..91b34d0
--- /dev/null
@@ -0,0 +1,495 @@
+/*\r
+defines of FPGA chip ICE65L08's register \r
+*/\r
+\r
+#ifndef SPI_UART_H\r
+#define SPI_UART_H\r
+\r
+#define SPI_FPGA_INT_PIN RK2818_PIN_PA4\r
+#define SPI_DPRAM_BUSY_PIN RK2818_PIN_PA2\r
+#define SPI_FPGA_STANDBY_PIN RK2818_PIN_PH7\r
+\r
+struct uart_icount {\r
+       __u32   cts;\r
+       __u32   dsr;\r
+       __u32   rng;\r
+       __u32   dcd;\r
+       __u32   rx;\r
+       __u32   tx;\r
+       __u32   frame;\r
+       __u32   overrun;\r
+       __u32   parity;\r
+       __u32   brk;\r
+};\r
+\r
+struct spi_uart\r
+{\r
+       struct workqueue_struct         *spi_uart_workqueue;\r
+       struct work_struct spi_uart_work;       \r
+       struct timer_list       uart_timer;\r
+       struct tty_struct       *tty;\r
+       struct kref             kref;\r
+       struct mutex            open_lock;\r
+       struct task_struct      *in_spi_uart_irq;       \r
+       struct circ_buf         xmit;\r
+       struct uart_icount      icount;\r
+       spinlock_t              write_lock;\r
+       spinlock_t              irq_lock;\r
+       unsigned int            index;\r
+       unsigned int            opened;\r
+       unsigned int            regs_offset;\r
+       unsigned int            uartclk;\r
+       unsigned int            mctrl;\r
+       unsigned int            read_status_mask;\r
+       unsigned int            ignore_status_mask;\r
+       unsigned char           x_char;\r
+       unsigned char       ier;\r
+       unsigned char       lcr;\r
+\r
+};\r
+\r
+struct spi_gpio\r
+{\r
+       struct workqueue_struct         *spi_gpio_workqueue;\r
+       struct work_struct      spi_gpio_work;\r
+       struct timer_list       gpio_timer;\r
+\r
+};\r
+\r
+struct spi_i2c\r
+{\r
+       struct workqueue_struct         *spi_i2c_workqueue;\r
+       struct work_struct      spi_i2c_work;\r
+       struct timer_list i2c_timer;\r
+       struct i2c_adapter *adapter;\r
+       struct i2c_client  *client;\r
+       spinlock_t i2c_lock ; \r
+       unsigned char interrupt;\r
+       unsigned char i2c_data_width[2];\r
+       unsigned int  speed[2];\r
+};\r
+\r
+struct spi_dpram\r
+{\r
+       struct workqueue_struct         *spi_dpram_workqueue;\r
+       struct work_struct      spi_dpram_work; \r
+       struct workqueue_struct         *spi_dpram_busy_workqueue;\r
+       struct work_struct      spi_dpram_busy_work;\r
+       struct timer_list       dpram_timer;\r
+       unsigned char           *prx;\r
+       unsigned char           *ptx;\r
+       unsigned int            rec_len;\r
+       unsigned int            send_len;\r
+       unsigned int            max_rec_len;\r
+       unsigned int            max_send_len;\r
+       volatile int            apwrite_en;\r
+       unsigned short int  dpram_addr;\r
+       struct semaphore        rec_sem;  \r
+       struct semaphore        send_sem; \r
+       wait_queue_head_t       recq, sendq;\r
+       struct miscdevice       miscdev;\r
+\r
+       int (*write_dpram)(struct spi_dpram *, unsigned short int addr, unsigned char *buf, unsigned int len);\r
+       int (*read_dpram)(struct spi_dpram *, unsigned short int addr, unsigned char *buf, unsigned int len);\r
+       int (*write_ptr)(struct spi_dpram *, unsigned short int addr, unsigned int size);\r
+       int (*read_ptr)(struct spi_dpram *, unsigned short int addr);\r
+       int (*write_mailbox)(struct spi_dpram *, unsigned int mailbox);\r
+       int (*read_mailbox)(struct spi_dpram *);\r
+\r
+};\r
+\r
+struct spi_fpga_port {\r
+       const char *name;\r
+       struct spi_device       *spi;\r
+       struct mutex            spi_lock;\r
+       struct workqueue_struct         *fpga_irq_workqueue;\r
+       struct work_struct      fpga_irq_work;  \r
+       struct timer_list       fpga_timer;\r
+       /*spi2uart*/\r
+#ifdef CONFIG_SPI_UART\r
+       struct spi_uart uart;\r
+#endif\r
+       /*spi2gpio*/\r
+#ifdef CONFIG_SPI_GPIO\r
+       struct spi_gpio gpio;\r
+#endif\r
+       /*spi2i2c*/\r
+#ifdef CONFIG_SPI_I2C\r
+       struct spi_i2c i2c;\r
+#endif\r
+       /*spi2dpram*/\r
+#ifdef CONFIG_SPI_DPRAM\r
+       struct spi_dpram dpram;\r
+#endif\r
+\r
+};\r
+\r
+\r
+#define ICE_CC72               0\r
+#define ICE_CC196              1\r
+#define FPGA_TYPE              ICE_CC196\r
+#define SEL_UART               0\r
+#define SEL_GPIO               1\r
+#define SEL_I2C                        2\r
+#define SEL_DPRAM              3\r
+\r
+/* CMD */\r
+#define ICE_SEL_UART                   (SEL_UART<<6)\r
+#define ICE_SEL_GPIO                   (SEL_GPIO<<6)\r
+#define ICE_SEL_I2C                    (SEL_I2C<<6)\r
+#define ICE_SEL_DPRAM                  (SEL_DPRAM<<6)\r
+\r
+#define ICE_SEL_WRITE                  (~(1<<5))\r
+#define ICE_SEL_READ                   (1<<5)\r
+\r
+#define ICE_SEL_UART_CH(ch)    ((ch&0x03)<<3)\r
+#define ICE_SEL_READ_INT_TYPE  (3<<3)\r
+\r
+/*read int type*/\r
+#define ICE_INT_TYPE_UART0             (~(1<<0))\r
+#define ICE_INT_TYPE_UART1             (~(1<<1))\r
+#define ICE_INT_TYPE_UART2             (~(1<<2))\r
+#define ICE_INT_TYPE_I2C2              (~(1<<3))\r
+#define ICE_INT_TYPE_I2C3              (~(1<<4))\r
+#define ICE_INT_TYPE_GPIO              (~(1<<5))\r
+#define ICE_INT_TYPE_DPRAM             (~(1<<6))\r
+\r
+#define ICE_INT_I2C_ACK                        (~(1<<0))\r
+#define ICE_INT_I2C_READ               (~(1<<1))\r
+#define ICE_INT_I2C_WRITE              (~(1<<2))\r
+\r
+/*spi to uart*/\r
+#define        ICE_RXFIFO_FULL                 (1<<8)\r
+#define        ICE_RXFIFO_NOT_FULL             (~(1<<8))\r
+#define        ICE_RXFIFO_EMPTY                (1<<9)\r
+#define        ICE_RXFIFO_NOT_EMPTY    (~(1<<9))\r
+#define        ICE_TXFIFO_FULL                 (1<<10)\r
+#define        ICE_TXFIFO_NOT_FULL             (~(1<<10))\r
+#define        ICE_TXFIFO_EMPTY                (1<<11)\r
+#define        ICE_TXFIFO_NOT_EMPTY    (~(1<<11))\r
+\r
+\r
+/*spi to gpio*/\r
+#define        ICE_SEL_GPIO0                           (0X00<<3)       //INT/GPIO0\r
+#define        ICE_SEL_GPIO1                           (0X02<<2)       //GPIO1\r
+#define        ICE_SEL_GPIO2                           (0X03<<2)\r
+#define        ICE_SEL_GPIO3                           (0X04<<2)\r
+#define        ICE_SEL_GPIO4                           (0X05<<2)\r
+#define        ICE_SEL_GPIO5                           (0X06<<2)\r
+\r
+#define ICE_SEL_GPIO0_TYPE                     (0X00)\r
+#define ICE_SEL_GPIO0_DIR                      (0X01)\r
+#define ICE_SEL_GPIO0_DATA                     (0X02)\r
+#define ICE_SEL_GPIO0_INT_EN           (0X03)\r
+#define ICE_SEL_GPIO0_INT_TRI          (0X04)\r
+#define ICE_SEL_GPIO0_INT_STATE                (0X05)\r
+\r
+#define        ICE_SEL_GPIO_DIR                        (0X01)\r
+#define        ICE_SEL_GPIO_DATA                       (0X02)\r
+\r
+/*spi to i2c*/\r
+\r
+typedef enum I2C_ch\r
+{\r
+       I2C_CH0,\r
+       I2C_CH1,\r
+       I2C_CH2,\r
+       I2C_CH3 \r
+}eI2C_ch_t;\r
+\r
+#define ICE_SEL_I2C_START            (0<<0)\r
+#define ICE_SEL_I2C_STOP              (1<<0)\r
+#define ICE_SEL_I2C_RESTART        (2<<0)\r
+#define ICE_SEL_I2C_TRANS           (3<<0)\r
+#define ICE_SEL_I2C_SMASK      (~(3<<0))\r
+#define ICE_SEL_I2C_CH2               (0<<2)\r
+#define ICE_SEL_I2C_CH3               (1<<2)\r
+#define ICE_SEL_I2C_DEFMODE      (0<<3)\r
+#define ICE_SEL_I2C_FIFO              (1<<3)\r
+#define ICE_SEL_I2C_SPEED            (2<<3)\r
+#define ICE_SEL_I2C_INT                 (3<<3)\r
+#define ICE_SEL_I2C_MMASK      (~(3<<3))\r
+\r
+#define ICE_I2C_SLAVE_WRITE           (0<<0)\r
+#define ICE_I2C_SLAVE_READ             (1<<0)\r
+\r
+\r
+\r
+#define ICE_SEL_I2C_W8BIT           (0<<2)\r
+#define ICE_SEL_I2C_W16BIT             (1<<2)\r
+#define ICE_SEL_I2C_DWIDTH     (2<<2)\r
+\r
+#define ICE_I2C_AD_ACK              (~(1<<0))\r
+#define ICE_I2C_WRITE_ACK        (~(1<<1))\r
+#define ICE_I2C_READ_ACK            (~(1<<2))\r
+\r
+#define ICE_SEL_I2C_CH2_8BIT          (0<<2)\r
+#define ICE_SEL_I2C_CH2_16BIT        (1<<2)\r
+#define ICE_SEL_I2C_CH2_MIX           (2<<2)\r
+\r
+#define ICE_SEL_I2C_CH3_8BIT         (4<<2)\r
+#define ICE_SEL_I2C_CH3_16BIT       (5<<2)\r
+#define ICE_SEL_I2C_CH3_MIX          (6<<2)\r
+#define ICE_SEL_I2C_RD_A               (7<<2)\r
+#define ICE_SEL_I2C_MASK               (7<<2)\r
+#define ICE_SEL_I2C_ACK3               (1<<1)\r
+#define ICE_SEL_I2C_ACK2               (0<<1)\r
+\r
+#define INT_I2C_WRITE_ACK              (2)\r
+#define INT_I2C_WRITE_NACK        (3)\r
+#define INT_I2C_READ_ACK              (4)      \r
+#define INT_I2C_READ_NACK          (5)\r
+#define INT_I2C_WRITE_MASK        (~(1<<1))\r
+#define INT_I2C_READ_MASK        (~(1<<2))\r
+\r
+#define ICE_SET_10K_I2C_SPEED         (0x01)\r
+#define ICE_SET_100K_I2C_SPEED        (0x02)     \r
+#define ICE_SET_200K_I2C_SPEED        (0x04)\r
+#define ICE_SET_300K_I2C_SPEED        (0x08)\r
+#define ICE_SET_400K_I2C_SPEED        (0x10)\r
+\r
+\r
+/*spi to dpram*/\r
+#define ICE_SEL_DPRAM_NOMAL            (~(1<<5))\r
+#define        ICE_SEL_DPRAM_SEM               (1<<5)\r
+#define        ICE_SEL_DPRAM_READ              (~(1<<4))\r
+#define        ICE_SEL_DPRAM_WRITE             (1<<4)\r
+#define ICE_SEL_DPRAM_BL1              (0)\r
+#define ICE_SEL_DPRAM_BL32             (1)\r
+#define ICE_SEL_DPRAM_BL64             (2)\r
+#define ICE_SEL_DPRAM_BL128            (3)\r
+#define ICE_SEL_DPRAM_FULL             (4)\r
+\r
+#define ICE_SEL_SEM_WRITE              (0x7F)\r
+#define ICE_SEL_SEM_READ               (0xBF)\r
+#define ICE_SEL_SEM_WRRD               (0x3F)\r
+\r
+typedef        void (*pSpiFunc)(void); //¶¨Ò庯ÊýÖ¸Õë, ÓÃÓÚµ÷Óþø¶ÔµØÖ·\r
+typedef        void (*pSpiFuncIntr)(int,void *);\r
+typedef struct\r
+{\r
+       pSpiFuncIntr gpio_vector;\r
+       void *gpio_devid;\r
+}SPI_GPIO_PDATA;\r
+\r
+\r
+typedef enum eSpiGpioTypeSel\r
+{\r
+       SPI_GPIO0_IS_GPIO = 0,\r
+       SPI_GPIO0_IS_INT,\r
+}eSpiGpioTypeSel_t;\r
+\r
+\r
+\r
+typedef enum eSpiGpioPinInt\r
+{\r
+       SPI_GPIO_INT_DISABLE = 0,\r
+       SPI_GPIO_INT_ENABLE,\r
+}eSpiGpioPinInt_t;\r
+\r
+\r
+typedef enum eSpiGpioIntType \r
+{\r
+       SPI_GPIO_EDGE_FALLING = 0,\r
+       SPI_GPIO_EDGE_RISING,\r
+}eSpiGpioIntType_t;\r
+\r
+typedef enum eSpiGpioPinDirection\r
+{\r
+       SPI_GPIO_IN = 0,\r
+       SPI_GPIO_OUT,\r
+}eSpiGpioPinDirection_t;\r
+\r
+\r
+typedef enum eSpiGpioPinLevel\r
+{\r
+       SPI_GPIO_LOW = 0,\r
+       SPI_GPIO_HIGH,\r
+       SPI_GPIO_LEVEL_ERR,\r
+}eSpiGpioPinLevel_t;\r
+\r
+#if (FPGA_TYPE == ICE_CC72)\r
+typedef enum eSpiGpioPinNum\r
+{\r
+       SPI_GPIO_P0_00 = 0,     //GPIO0[0]\r
+       SPI_GPIO_P0_01,\r
+       SPI_GPIO_P0_02,\r
+       SPI_GPIO_P0_03,\r
+       SPI_GPIO_P0_04,\r
+       SPI_GPIO_P0_05, \r
+       \r
+       SPI_GPIO_P2_00,         \r
+       SPI_GPIO_P2_01,\r
+       SPI_GPIO_P2_02,\r
+       SPI_GPIO_P2_03,\r
+       SPI_GPIO_P2_04,\r
+       SPI_GPIO_P2_05,\r
+       SPI_GPIO_P2_06,\r
+       SPI_GPIO_P2_07,\r
+       SPI_GPIO_P2_08, \r
+       SPI_GPIO_P2_09 = 15,    //GPIO0[15],the last interrupt/gpio pin \r
+       \r
+       SPI_GPIO_P3_00 = 16,    //GPIO1[0]\r
+       SPI_GPIO_P3_01,\r
+       SPI_GPIO_P3_02,\r
+       SPI_GPIO_P3_03,\r
+       SPI_GPIO_P3_04,\r
+       SPI_GPIO_P3_05,\r
+       SPI_GPIO_P3_06,\r
+       SPI_GPIO_P3_07,\r
+       SPI_GPIO_P3_08,\r
+       SPI_GPIO_P3_09,\r
+       SPI_GPIO_P0_06 = 26,    \r
+       SPI_GPIO_I2C3_SCL,\r
+       SPI_GPIO_I2C3_SDA,\r
+       SPI_GPIO_I2C4_SCL,\r
+       SPI_GPIO_I2C4_SDA,\r
+       \r
+}eSpiGpioPinNum_t;\r
+\r
+#elif (FPGA_TYPE == ICE_CC196)\r
+\r
+typedef enum eSpiGpioPinNum\r
+{\r
+       //GPIO0/INT\r
+       SPI_GPIO_P6_00 = 0,     //HS_DET input  \r
+       SPI_GPIO_P6_01,\r
+       SPI_GPIO_P6_02,\r
+       SPI_GPIO_P6_03,\r
+       SPI_GPIO_P6_04,         //CM3605_POUT_L_INT input\r
+       SPI_GPIO_P6_05,         \r
+       SPI_GPIO_P6_06,         //CHG_OK input\r
+       SPI_GPIO_P6_07,         //HP_HOOK input\r
+       SPI_GPIO_P6_08,\r
+       SPI_GPIO_P6_09,\r
+       SPI_GPIO_P6_10,         //DEFSEL input  \r
+       SPI_GPIO_P6_11,         //FLASH_WP_INT input\r
+       SPI_GPIO_P6_12,         //LOW_BATT_INT input\r
+       SPI_GPIO_P6_13,         //DC_DET input\r
+       SPI_GPIO_P3_08,         \r
+       SPI_GPIO_P3_09 = 15,\r
+\r
+       //GPIO1\r
+       SPI_GPIO_P1_00 = 16,    //LCD_ON output\r
+       SPI_GPIO_P1_01,         //LCD_PWR_CTRL output\r
+       SPI_GPIO_P1_02,         //SD_POW_ON output\r
+       SPI_GPIO_P1_03,         //WL_RST_N/WIFI_EN output\r
+       SPI_GPIO_P1_04,         //HARDO,input\r
+       SPI_GPIO_P1_05,         //SENSOR_PWDN output\r
+       SPI_GPIO_P1_06,         //BT_PWR_EN output\r
+       SPI_GPIO_P1_07,         //BT_RST output\r
+       SPI_GPIO_P1_08,         //BT_WAKE_B output\r
+       SPI_GPIO_P1_09,         //LCD_DISP_ON output\r
+       SPI_GPIO_P1_10,         //WM_PWR_EN output\r
+       SPI_GPIO_P1_11,         //HARD1,input\r
+       SPI_GPIO_P1_12,         //VIB_MOTO output\r
+       SPI_GPIO_P1_13,         //KEYLED_EN output\r
+       SPI_GPIO_P1_14,         //CAM_RST output\r
+       SPI_GPIO_P1_15 = 31,    //WL_WAKE_B output\r
+\r
+       //GPIO2\r
+       SPI_GPIO_P2_00 = 32,    //Y+YD input\r
+       SPI_GPIO_P2_01,         //Y-YU input\r
+       SPI_GPIO_P2_02,         //AP_TD_UNDIFED input\r
+       SPI_GPIO_P2_03,         //AP_PW_EN_TD output\r
+       SPI_GPIO_P2_04,         //AP_RESET_TD output\r
+       SPI_GPIO_P2_05,         //AP_SHUTDOWN_TD_PMU output\r
+       SPI_GPIO_P2_06,         //AP_RESET_CMMB output\r
+       SPI_GPIO_P2_07,         //AP_CHECK_TD_STATUS input\r
+       SPI_GPIO_P2_08,         //CHARGE_CURRENT_SEL output\r
+       SPI_GPIO_P2_09,         //AP_PWD_CMMB output\r
+       SPI_GPIO_P2_10,         //X-XL input\r
+       SPI_GPIO_P2_11,         //X+XR input\r
+       SPI_GPIO_P2_12,         //LCD_RESET output\r
+       SPI_GPIO_P2_13,         //USB_PWR_EN output\r
+       SPI_GPIO_P2_14,         //WL_HOST_WAKE_B output\r
+       SPI_GPIO_P2_15 = 47,    //TOUCH_SCREEN_RST output\r
+\r
+       //GPIO3\r
+       SPI_GPIO_P0_00 = 48,    //\r
+       SPI_GPIO_P0_01,\r
+       SPI_GPIO_P0_02,\r
+       SPI_GPIO_P0_03,\r
+       SPI_GPIO_P0_04,\r
+       SPI_GPIO_P0_05,\r
+       SPI_GPIO_P0_06,\r
+       SPI_GPIO_P0_07,\r
+       SPI_GPIO_P0_08,\r
+       SPI_GPIO_P0_09,         //FPGAС°å¸ÃÒý½ÅδÒý³ö C5\r
+       SPI_GPIO_P0_10,\r
+       SPI_GPIO_P0_11,\r
+       SPI_GPIO_P0_12,\r
+       SPI_GPIO_P0_13,\r
+       SPI_GPIO_P0_14,\r
+       SPI_GPIO_P0_15 = 63,\r
+\r
+       //GPIO4\r
+       SPI_GPIO_P4_00 = 64,    \r
+       SPI_GPIO_P4_01, \r
+       SPI_GPIO_P4_02,\r
+       SPI_GPIO_P4_03,\r
+       SPI_GPIO_P4_04,\r
+       SPI_GPIO_P4_05,\r
+       SPI_GPIO_P4_06,         //CHARGER_INT_END input\r
+       SPI_GPIO_P4_07,         //CM3605_PWD output\r
+       SPI_GPIO_P3_00,         \r
+       SPI_GPIO_P3_01,\r
+       SPI_GPIO_P3_02,\r
+       SPI_GPIO_P3_03,\r
+       SPI_GPIO_P3_04,\r
+       SPI_GPIO_P3_05,\r
+       SPI_GPIO_P3_06,\r
+       SPI_GPIO_P3_07 = 79,    \r
+\r
+       //GPIO5\r
+       SPI_GPIO_P4_08 = 80,    //CM3605_PS_SHUTDOWN\r
+       SPI_GPIO_P0_TXD2,               //temp\r
+\r
+}eSpiGpioPinNum_t;\r
+\r
+#endif\r
+\r
+\r
+typedef enum eSpiGpioPinIntIsr\r
+{\r
+       SPI_GPIO_IS_INT = 0,\r
+       SPI_GPIO_NO_INT,\r
+}eSpiGpioPinIntIsr_t;\r
+\r
+extern struct spi_fpga_port *pFpgaPort;\r
+extern unsigned int spi_in(struct spi_fpga_port *port, int reg, int type);\r
+extern void spi_out(struct spi_fpga_port *port, int reg, int value, int type);\r
+\r
+#if defined(CONFIG_SPI_UART)\r
+extern void spi_uart_handle_irq(struct spi_device *spi);\r
+extern int spi_uart_register(struct spi_fpga_port *port);\r
+extern int spi_uart_unregister(struct spi_fpga_port *port);\r
+#endif\r
+#if defined(CONFIG_SPI_GPIO)\r
+extern int spi_gpio_int_sel(eSpiGpioPinNum_t PinNum,eSpiGpioTypeSel_t type);\r
+extern int spi_gpio_set_pindirection(eSpiGpioPinNum_t PinNum,eSpiGpioPinDirection_t direction);\r
+extern int spi_gpio_set_pinlevel(eSpiGpioPinNum_t PinNum, eSpiGpioPinLevel_t PinLevel);\r
+extern eSpiGpioPinLevel_t spi_gpio_get_pinlevel(eSpiGpioPinNum_t PinNum);\r
+extern int spi_gpio_enable_int(eSpiGpioPinNum_t PinNum);\r
+extern int spi_gpio_disable_int(eSpiGpioPinNum_t PinNum);\r
+extern int spi_gpio_set_int_trigger(eSpiGpioPinNum_t PinNum,eSpiGpioIntType_t IntType);\r
+extern int spi_gpio_read_iir(void);\r
+extern int spi_request_gpio_irq(eSpiGpioPinNum_t PinNum, pSpiFunc Routine, eSpiGpioIntType_t IntType,void *dev_id);\r
+extern int spi_free_gpio_irq(eSpiGpioPinNum_t PinNum);\r
+extern int spi_gpio_handle_irq(struct spi_device *spi);\r
+extern int spi_gpio_init(void);\r
+extern int spi_gpio_register(struct spi_fpga_port *port);\r
+extern int spi_gpio_unregister(struct spi_fpga_port *port);\r
+#endif\r
+#if defined(CONFIG_SPI_I2C)\r
+extern int spi_i2c_handle_irq(struct spi_fpga_port *port,unsigned char channel);\r
+extern int spi_i2c_register(struct spi_fpga_port *port);\r
+extern int spi_i2c_unregister(struct spi_fpga_port *port);\r
+#endif\r
+#if defined(CONFIG_SPI_DPRAM)\r
+extern int spi_dpram_handle_irq(struct spi_device *spi);\r
+extern int spi_dpram_register(struct spi_fpga_port *port);\r
+extern int spi_dpram_unregister(struct spi_fpga_port *port);\r
+#endif\r
+\r
+#endif\r
diff --git a/drivers/fpga/spi_fpga_init.c b/drivers/fpga/spi_fpga_init.c
new file mode 100644 (file)
index 0000000..b5bea0a
--- /dev/null
@@ -0,0 +1,434 @@
+/*\r
+ * linux/drivers/fpga/spi_fpga_init.c - spi fpga init driver\r
+ *\r
+ * Copyright (C) 2010 ROCKCHIP, Inc.\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or (at\r
+ * your option) any later version.\r
+ */\r
+\r
+/*\r
+ * Note: fpga ice65l08xx is used for spi2uart,spi2gpio,spi2i2c and spi2dpram.\r
+ * this driver is the entry of all modules's drivers,should be run at first.\r
+ * the struct for fpga is build in the driver,and it is important.\r
+ */\r
+\r
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/mutex.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/gfp.h>\r
+#include <linux/tty.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/spi/spi.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/ioport.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/sched.h>\r
+#include <linux/kthread.h>\r
+#include <linux/jiffies.h>\r
+#include <linux/i2c.h>\r
+#include <mach/rk2818_iomap.h>\r
+\r
+#include "spi_fpga.h"\r
+\r
+#if defined(CONFIG_SPI_FPGA_INIT_DEBUG)\r
+#define DBG(x...)   printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+struct spi_fpga_port *pFpgaPort;\r
+\r
+/*------------------------spi¶ÁдµÄ»ù±¾º¯Êý-----------------------*/\r
+unsigned int spi_in(struct spi_fpga_port *port, int reg, int type)\r
+{\r
+       unsigned char index = 0;\r
+       unsigned char tx_buf[1], rx_buf[2], n_rx=2, stat=0;\r
+       unsigned int result=0;\r
+       //printk("index1=%d\n",index);\r
+\r
+       switch(type)\r
+       {\r
+#if defined(CONFIG_SPI_UART)\r
+               case SEL_UART:\r
+                       index = port->uart.index;\r
+                       reg = (((reg) | ICE_SEL_UART) | ICE_SEL_READ | ICE_SEL_UART_CH(index));\r
+                       tx_buf[0] = reg & 0xff;\r
+                       rx_buf[0] = 0;\r
+                       rx_buf[1] = 0;  \r
+                       stat = spi_write_then_read(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf), rx_buf, n_rx);\r
+                       result = rx_buf[1];\r
+                       DBG("%s,SEL_UART reg=0x%x,result=0x%x\n",__FUNCTION__,reg&0xff,result&0xff);\r
+                       break;\r
+#endif\r
+\r
+#if defined(CONFIG_SPI_GPIO)\r
+               case SEL_GPIO:\r
+                       reg = (((reg) | ICE_SEL_GPIO) | ICE_SEL_READ );\r
+                       tx_buf[0] = reg & 0xff;\r
+                       rx_buf[0] = 0;\r
+                       rx_buf[1] = 0;  \r
+                       stat = spi_write_then_read(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf), rx_buf, n_rx);\r
+                       result = (rx_buf[0] << 8) | rx_buf[1];\r
+                       DBG("%s,SEL_GPIO reg=0x%x,result=0x%x\n",__FUNCTION__,reg&0xff,result&0xffff);\r
+                       break;\r
+#endif\r
+\r
+#if defined(CONFIG_SPI_I2C)\r
+               case SEL_I2C:\r
+                       reg = (((reg) | ICE_SEL_I2C) & ICE_SEL_READ );\r
+                       tx_buf[0] = reg & 0xff;\r
+                       rx_buf[0] = 0;\r
+                       rx_buf[1] = 0;                          \r
+                       stat = spi_write_then_read(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf), rx_buf, n_rx);\r
+                       result = (rx_buf[0] << 8) | rx_buf[1];\r
+                       DBG("%s,SEL_I2C reg=0x%x,result=0x%x [0x%x] [0x%x]\n",__FUNCTION__,reg&0xff,result&0xffff,rx_buf[0],rx_buf[1]);                                 \r
+                       break;\r
+#endif\r
+\r
+#if defined(CONFIG_SPI_DPRAM)\r
+               case SEL_DPRAM:\r
+                       reg = (((reg) | ICE_SEL_DPRAM) & ICE_SEL_DPRAM_READ );\r
+                       tx_buf[0] = reg & 0xff;\r
+                       rx_buf[0] = 0;\r
+                       rx_buf[1] = 0;                          \r
+                       stat = spi_write_then_read(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf), rx_buf, n_rx);\r
+                       result = (rx_buf[0] << 8) | rx_buf[1];\r
+                       DBG("%s,SEL_GPIO reg=0x%x,result=0x%x\n",__FUNCTION__,reg&0xff,result&0xffff);  \r
+                       break;\r
+#endif\r
+               default:\r
+                       printk("Can not support this type!\n");\r
+                       break;\r
+       }\r
+\r
+       return result;\r
+}\r
+\r
+void spi_out(struct spi_fpga_port *port, int reg, int value, int type)\r
+{\r
+       unsigned char index = 0;\r
+       unsigned char tx_buf[3];\r
+       //printk("index2=%d,",index);\r
+       switch(type)\r
+       {\r
+#if defined(CONFIG_SPI_UART)\r
+               case SEL_UART:\r
+                       index = port->uart.index;\r
+                       reg = ((((reg) | ICE_SEL_UART) & ICE_SEL_WRITE) | ICE_SEL_UART_CH(index));\r
+                       tx_buf[0] = reg & 0xff;\r
+                       tx_buf[1] = (value>>8) & 0xff;\r
+                       tx_buf[2] = value & 0xff;\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
+#endif\r
+\r
+#if defined(CONFIG_SPI_GPIO)\r
+               case SEL_GPIO:\r
+                       reg = (((reg) | ICE_SEL_GPIO) & ICE_SEL_WRITE );\r
+                       tx_buf[0] = reg & 0xff;\r
+                       tx_buf[1] = (value>>8) & 0xff;\r
+                       tx_buf[2] = value & 0xff;\r
+                       spi_write(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf));\r
+                       DBG("%s,SEL_GPIO reg=0x%x,value=0x%x\n",__FUNCTION__,reg&0xff,value&0xffff);\r
+                       break;\r
+#endif\r
+\r
+#if defined(CONFIG_SPI_I2C)\r
+\r
+               case SEL_I2C:\r
+                       reg = (((reg) | ICE_SEL_I2C) & ICE_SEL_WRITE);\r
+                       tx_buf[0] = reg & 0xff;\r
+                       tx_buf[1] = (value>>8) & 0xff;\r
+                       tx_buf[2] = value & 0xff;\r
+                       spi_write(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf));\r
+                       DBG("%s,SEL_I2C reg=0x%x,value=0x%x\n",__FUNCTION__,reg&0xff,value&0xffff);     \r
+                       break;\r
+#endif\r
+                       \r
+#if defined(CONFIG_SPI_DPRAM)\r
+               case SEL_DPRAM:\r
+                       reg = (((reg) | ICE_SEL_DPRAM) | ICE_SEL_DPRAM_WRITE );\r
+                       tx_buf[0] = reg & 0xff;\r
+                       tx_buf[1] = (value>>8) & 0xff;\r
+                       tx_buf[2] = value & 0xff;\r
+                       spi_write(port->spi, (const u8 *)&tx_buf, sizeof(tx_buf));\r
+                       DBG("%s,SEL_DPRAM reg=0x%x,value=0x%x\n",__FUNCTION__,reg&0xff,value&0xffff);                           \r
+                       break;\r
+#endif\r
+\r
+               default:\r
+                       printk("Can not support this type!\n");\r
+                       break;\r
+       }\r
+\r
+}\r
+\r
+\r
+static void spi_fpga_irq_work_handler(struct work_struct *work)\r
+{\r
+       struct spi_fpga_port *port =\r
+               container_of(work, struct spi_fpga_port, fpga_irq_work);\r
+       struct spi_device       *spi = port->spi;\r
+       int ret,uart_ch,gpio_ch;\r
+\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       \r
+       ret = spi_in(port, ICE_SEL_READ_INT_TYPE, SEL_UART);\r
+       if((ret | ICE_INT_TYPE_UART0) == ICE_INT_TYPE_UART0)\r
+       {\r
+#if defined(CONFIG_SPI_UART)\r
+               uart_ch = 0;\r
+               printk("Enter::%s,LINE=%d,uart_ch=%d,uart.index=%d\n",__FUNCTION__,__LINE__,uart_ch,port->uart.index);\r
+               port->uart.index = uart_ch;\r
+               spi_uart_handle_irq(spi);\r
+#endif\r
+       }\r
+       else if((ret | ICE_INT_TYPE_GPIO) == ICE_INT_TYPE_GPIO)\r
+       {\r
+               gpio_ch = 0;\r
+               printk("Enter::%s,LINE=%d,gpio_ch=%d\n",__FUNCTION__,__LINE__,gpio_ch);\r
+#if defined(CONFIG_SPI_GPIO)\r
+               spi_gpio_handle_irq(spi);\r
+#endif\r
+       }\r
+       else if((ret | ICE_INT_TYPE_I2C2) == ICE_INT_TYPE_I2C2)\r
+       {\r
+#if defined(CONFIG_SPI_I2C)\r
+               spi_i2c_handle_irq(port,0);\r
+#endif\r
+       }\r
+       else if((ret | ICE_INT_TYPE_I2C3) == ICE_INT_TYPE_I2C3)\r
+       {\r
+#if defined(CONFIG_SPI_I2C)\r
+               spi_i2c_handle_irq(port,1);\r
+#endif\r
+       }\r
+       else if((ret | ICE_INT_TYPE_DPRAM) == ICE_INT_TYPE_DPRAM)\r
+       {\r
+#if defined(CONFIG_SPI_DPRAM)\r
+               spi_dpram_handle_irq(spi);\r
+#endif\r
+       }\r
+       else\r
+       {\r
+               printk("%s:NO such INT TYPE\n",__FUNCTION__);\r
+       }\r
+\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+}\r
+\r
+\r
+static irqreturn_t spi_fpga_irq(int irq, void *dev_id)\r
+{\r
+       struct spi_fpga_port *port = dev_id;\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       /*\r
+        * Can't do anything in interrupt context because we need to\r
+        * block (spi_sync() is blocking) so fire of the interrupt\r
+        * handling workqueue.\r
+        * Remember that we access ICE65LXX registers through SPI bus\r
+        * via spi_sync() call.\r
+        */\r
+        \r
+       //schedule_work(&port->fpga_irq_work);\r
+       queue_work(port->fpga_irq_workqueue, &port->fpga_irq_work);\r
+\r
+       return IRQ_HANDLED;\r
+}\r
+\r
+\r
+static int spi_open_sysclk(int set)\r
+{\r
+       int ret;\r
+       ret = gpio_request(SPI_FPGA_STANDBY_PIN, NULL);\r
+       if (ret) {\r
+               printk("%s:failed to request standby pin\n",__FUNCTION__);\r
+               return ret;\r
+       }\r
+       rk2818_mux_api_set(GPIOH7_HSADCCLK_SEL_NAME,IOMUXB_GPIO1_D7);   \r
+       gpio_direction_output(SPI_FPGA_STANDBY_PIN,set);\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+static int __devinit spi_fpga_probe(struct spi_device * spi)\r
+{\r
+       struct spi_fpga_port *port;\r
+       int ret;\r
+       char b[12];\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       /*\r
+        * bits_per_word cannot be configured in platform data\r
+       */\r
+       spi->bits_per_word = 8;\r
+\r
+       ret = spi_setup(spi);\r
+       if (ret < 0)\r
+               return ret;\r
+       \r
+       port = kzalloc(sizeof(struct spi_fpga_port), GFP_KERNEL);\r
+       if (!port)\r
+               return -ENOMEM;\r
+       DBG("port=0x%x\n",(int)port);\r
+\r
+       mutex_init(&port->spi_lock);\r
+\r
+       spi_open_sysclk(GPIO_HIGH);\r
+\r
+       sprintf(b, "fpga_irq_workqueue");\r
+       port->fpga_irq_workqueue = create_freezeable_workqueue(b);\r
+       if (!port->fpga_irq_workqueue) {\r
+               printk("cannot create workqueue\n");\r
+               return -EBUSY;\r
+       }\r
+       INIT_WORK(&port->fpga_irq_work, spi_fpga_irq_work_handler);\r
+       \r
+#if defined(CONFIG_SPI_UART)\r
+       ret = spi_uart_register(port);\r
+       if(ret)\r
+       {\r
+               spi_uart_unregister(port);\r
+               printk("%s:ret=%d,fail to spi_uart_register\n",__FUNCTION__,ret);\r
+               return ret;\r
+       }\r
+#endif\r
+#if defined(CONFIG_SPI_GPIO)\r
+       ret = spi_gpio_register(port);\r
+       if(ret)\r
+       {\r
+               spi_gpio_unregister(port);\r
+               printk("%s:ret=%d,fail to spi_gpio_register\n",__FUNCTION__,ret);\r
+               return ret;\r
+       }\r
+#endif\r
+#if 0 //defined(CONFIG_SPI_I2C)\r
+\r
+       printk("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       ret = spi_i2c_register(port);\r
+       printk("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       if(ret)\r
+       {\r
+               spi_i2c_unregister(port);\r
+               printk("%s:ret=%d,fail to spi_i2c_register\n",__FUNCTION__,ret);\r
+               return ret;\r
+       }\r
+#endif\r
+#if defined(CONFIG_SPI_DPRAM)\r
+       ret = spi_dpram_register(port);\r
+       if(ret)\r
+       {\r
+               spi_dpram_unregister(port);\r
+               printk("%s:ret=%d,fail to spi_dpram_register\n",__FUNCTION__,ret);\r
+               return ret;\r
+       }\r
+#endif\r
+       port->spi = spi;\r
+       spi_set_drvdata(spi, port);\r
+       \r
+       ret = gpio_request(SPI_FPGA_INT_PIN, NULL);\r
+       if (ret) {\r
+               printk("%s:failed to request fpga intterupt gpio\n",__FUNCTION__);\r
+               goto err1;\r
+       }\r
+\r
+       gpio_pull_updown(SPI_FPGA_INT_PIN,GPIOPullUp);\r
+       ret = request_irq(gpio_to_irq(SPI_FPGA_INT_PIN),spi_fpga_irq,IRQF_TRIGGER_RISING,NULL,port);\r
+       if(ret)\r
+       {\r
+               printk("unable to request spi_uart irq\n");\r
+               goto err2;\r
+       }       \r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       pFpgaPort = port;\r
+       \r
+#if defined(CONFIG_SPI_GPIO)\r
+       spi_gpio_init();\r
+#endif\r
+\r
+       return 0;\r
+\r
+err2:\r
+       free_irq(gpio_to_irq(SPI_FPGA_INT_PIN),NULL);\r
+err1:  \r
+       gpio_free(SPI_FPGA_INT_PIN);\r
+\r
+       return ret;\r
+       \r
+\r
+}\r
+\r
+static int __devexit spi_fpga_remove(struct spi_device *spi)\r
+{\r
+       //struct spi_fpga_port *port = dev_get_drvdata(&spi->dev);\r
+\r
+       \r
+       return 0;\r
+}\r
+\r
+#ifdef CONFIG_PM\r
+\r
+static int spi_fpga_suspend(struct spi_device *spi, pm_message_t state)\r
+{\r
+       //struct spi_fpga_port *port = dev_get_drvdata(&spi->dev);\r
+\r
+       return 0;\r
+}\r
+\r
+static int spi_fpga_resume(struct spi_device *spi)\r
+{\r
+       //struct spi_fpga_port *port = dev_get_drvdata(&spi->dev);\r
+\r
+       return 0;\r
+}\r
+\r
+#else\r
+#define spi_fpga_suspend NULL\r
+#define spi_fpga_resume  NULL\r
+#endif\r
+\r
+static struct spi_driver spi_fpga_driver = {\r
+       .driver = {\r
+               .name           = "spi_fpga",\r
+               .bus            = &spi_bus_type,\r
+               .owner          = THIS_MODULE,\r
+       },\r
+\r
+       .probe          = spi_fpga_probe,\r
+       .remove         = __devexit_p(spi_fpga_remove),\r
+       .suspend        = spi_fpga_suspend,\r
+       .resume         = spi_fpga_resume,\r
+};\r
+\r
+static int __init spi_fpga_init(void)\r
+{\r
+       return spi_register_driver(&spi_fpga_driver);\r
+}\r
+\r
+static void __exit spi_fpga_exit(void)\r
+{\r
+       spi_unregister_driver(&spi_fpga_driver);\r
+}\r
+\r
+module_init(spi_fpga_init);\r
+module_exit(spi_fpga_exit);\r
+\r
+MODULE_DESCRIPTION("Driver for spi2uart,spi2gpio,spi2i2c.");\r
+MODULE_AUTHOR("luowei <lw@rock-chips.com>");\r
+MODULE_LICENSE("GPL");\r
diff --git a/drivers/fpga/spi_gpio.c b/drivers/fpga/spi_gpio.c
new file mode 100644 (file)
index 0000000..5dc3dca
--- /dev/null
@@ -0,0 +1,740 @@
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/mutex.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/gfp.h>\r
+#include <linux/tty.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/spi/spi.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/ioport.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/sched.h>\r
+#include <linux/kthread.h>\r
+#include <linux/jiffies.h>\r
+#include <linux/i2c.h>\r
+#include <mach/rk2818_iomap.h>\r
+\r
+#include "spi_fpga.h"\r
+\r
+#if defined(CONFIG_SPI_GPIO_DEBUG)\r
+#define DBG(x...)   printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define SPI_GPIO_TEST 0\r
+#define HIGH_SPI_TEST 1\r
+spinlock_t             gpio_lock;\r
+spinlock_t             gpio_state_lock;\r
+spinlock_t             gpio_irq_lock;\r
+static unsigned short int gGpio0State = 0;             \r
+#define SPI_GPIO_IRQ_NUM 16\r
+static SPI_GPIO_PDATA g_spiGpioVectorTable[SPI_GPIO_IRQ_NUM] = \\r
+{{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; \r
+\r
+\r
+static void spi_gpio_write_reg(int reg, int PinNum, int set)\r
+{\r
+       unsigned int old_set;\r
+       unsigned int new_set;\r
+       struct spi_fpga_port *port = pFpgaPort;\r
+       PinNum = PinNum % 16;\r
+       //mutex_lock(&port->spi_lock);\r
+       old_set= spi_in(port, reg, SEL_GPIO);\r
+       if(1 == set)\r
+       new_set = old_set | (1 << PinNum );     \r
+       else\r
+       new_set = old_set & (~(1 << PinNum ));\r
+       spi_out(port, reg, new_set, SEL_GPIO);\r
+       //mutex_unlock(&port->spi_lock);\r
+       \r
+}\r
+\r
+static int spi_gpio_read_reg(int reg)\r
+{\r
+       int ret = 0;\r
+       struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       //mutex_lock(&port->spi_lock);\r
+       ret = spi_in(port, reg, SEL_GPIO);\r
+       //mutex_unlock(&port->spi_lock);\r
+\r
+       return ret;     \r
+}\r
+\r
+\r
+static int get_gpio_addr(eSpiGpioPinNum_t PinNum)\r
+{\r
+       int gpio = PinNum / 16;\r
+       int reg = -1;\r
+       switch(gpio)\r
+       {\r
+               case 0:\r
+               reg = ICE_SEL_GPIO0;\r
+               break;\r
+               case 1:\r
+               reg = ICE_SEL_GPIO1;\r
+               break;\r
+               case 2:\r
+               reg = ICE_SEL_GPIO2;\r
+               break;\r
+               case 3:\r
+               reg = ICE_SEL_GPIO3;\r
+               break;\r
+               case 4:\r
+               reg = ICE_SEL_GPIO4;\r
+               break;\r
+               case 5:\r
+               reg = ICE_SEL_GPIO5;\r
+               break;\r
+               default:\r
+               break;\r
+\r
+       }\r
+\r
+       return reg;\r
+\r
+}\r
+\r
+\r
+int spi_gpio_int_sel(eSpiGpioPinNum_t PinNum,eSpiGpioTypeSel_t type)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_TYPE;\r
+               spin_lock(&gpio_state_lock);\r
+               if(SPI_GPIO0_IS_INT == type)\r
+                       gGpio0State |= (1 << PinNum );\r
+               else\r
+                       gGpio0State &= (~(1 << PinNum ));\r
+               spin_unlock(&gpio_state_lock);\r
+               DBG("%s,PinNum=%d,GPIO[%d]:type=%d\n",__FUNCTION__,PinNum,PinNum/16,type);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, type);\r
+               //mutex_unlock(&port->spi_lock);\r
+               \r
+               return 0;\r
+       }\r
+       else\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+}\r
+\r
+       \r
+int spi_gpio_set_pindirection(eSpiGpioPinNum_t PinNum,eSpiGpioPinDirection_t direction)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(reg == -1)\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+\r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_DIR;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) != 0)\r
+               {\r
+                       printk("Fail to set direction because it is int pin!\n");\r
+                       return -1;\r
+               }\r
+               spin_unlock(&gpio_state_lock);  \r
+               DBG("%s,PinNum=%d,direction=%d,GPIO[%d]:PinNum/16=%d\n",__FUNCTION__,PinNum,direction,PinNum/16,PinNum%16);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, direction);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+       else\r
+       {\r
+               reg |= ICE_SEL_GPIO_DIR;\r
+               DBG("%s,PinNum=%d,direction=%d,GPIO[%d]:PinNum/16=%d\n",__FUNCTION__,PinNum,direction,PinNum/16,PinNum%16);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, direction);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+       return 0;\r
+}\r
+\r
+\r
+int spi_gpio_set_pinlevel(eSpiGpioPinNum_t PinNum, eSpiGpioPinLevel_t PinLevel)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(reg == -1)\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+       \r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_DATA;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) != 0)\r
+               {\r
+                       printk("Fail to set PinLevel because PinNum=%d is int pin!\n",PinNum);\r
+                       return -1;\r
+               }\r
+               spin_unlock(&gpio_state_lock);  \r
+               DBG("%s,PinNum=%d,GPIO[%d]:PinNum/16=%d,PinLevel=%d\n",__FUNCTION__,PinNum,PinNum/16,PinNum%16,PinLevel);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, PinLevel);\r
+               //mutex_unlock(&port->spi_lock);\r
+               \r
+       }\r
+       else\r
+       {\r
+               reg |= ICE_SEL_GPIO_DATA;\r
+               DBG("%s,PinNum=%d,GPIO[%d]:PinNum/16=%d,PinLevel=%d\n",__FUNCTION__,PinNum,PinNum/16,PinNum%16,PinLevel);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, PinLevel);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+\r
+       return 0;\r
+       \r
+}\r
+\r
+\r
+eSpiGpioPinLevel_t spi_gpio_get_pinlevel(eSpiGpioPinNum_t PinNum)\r
+{\r
+       int ret = 0;\r
+       int reg = get_gpio_addr(PinNum);\r
+       int level = 0;\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(reg == -1)\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return SPI_GPIO_LEVEL_ERR;\r
+       }\r
+\r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_DATA;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) != 0)\r
+               {\r
+                       printk("Fail to get PinLevel because it is int pin!\n");\r
+                       return SPI_GPIO_LEVEL_ERR;\r
+               }\r
+               spin_unlock(&gpio_state_lock);  \r
+               //mutex_lock(&port->spi_lock);\r
+               ret = spi_gpio_read_reg(reg);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+       else\r
+       {\r
+               reg |= ICE_SEL_GPIO_DATA;\r
+               //mutex_lock(&port->spi_lock);\r
+               ret = spi_gpio_read_reg(reg);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+\r
+       if((ret & (1 << (PinNum%16) )) == 0)\r
+               level = SPI_GPIO_LOW;\r
+       else\r
+               level = SPI_GPIO_HIGH;\r
+\r
+       DBG("%s,PinNum=%d,ret=0x%x,GPIO[%d]:PinNum/16=%d,PinLevel=%d\n\n",__FUNCTION__,PinNum,ret,PinNum/16,PinNum%16,level);\r
+\r
+       return level;\r
+       \r
+}\r
+\r
+\r
+int spi_gpio_enable_int(eSpiGpioPinNum_t PinNum)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_INT_EN;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) == 0)\r
+               {\r
+                       printk("Fail to enable int because it is gpio pin!\n");\r
+                       return -1;\r
+               }\r
+               spin_unlock(&gpio_state_lock);\r
+               DBG("%s,PinNum=%d,IntEn=%d\n",__FUNCTION__,PinNum,SPI_GPIO_INT_ENABLE); \r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, SPI_GPIO_INT_ENABLE);\r
+               //mutex_unlock(&port->spi_lock);        \r
+       }\r
+       else\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+int spi_gpio_disable_int(eSpiGpioPinNum_t PinNum)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_INT_EN;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) == 0)\r
+               {\r
+                       printk("Fail to enable int because it is gpio pin!\n");\r
+                       return -1;\r
+               }\r
+               spin_unlock(&gpio_state_lock);  \r
+               DBG("%s,PinNum=%d,IntEn=%d\n",__FUNCTION__,PinNum,SPI_GPIO_INT_DISABLE);\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, SPI_GPIO_INT_DISABLE);\r
+               //mutex_unlock(&port->spi_lock);        \r
+       }\r
+       else\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+int spi_gpio_set_int_trigger(eSpiGpioPinNum_t PinNum,eSpiGpioIntType_t IntType)\r
+{\r
+       int reg = get_gpio_addr(PinNum);\r
+       //struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       if(ICE_SEL_GPIO0 == reg)\r
+       {\r
+               reg |= ICE_SEL_GPIO0_INT_TRI;\r
+               spin_lock(&gpio_state_lock);\r
+               if((gGpio0State & (1 << PinNum )) == 0)\r
+               {\r
+                       printk("Fail to enable int because it is gpio pin!\n");\r
+                       return -1;\r
+               }\r
+               spin_unlock(&gpio_state_lock);  \r
+               DBG("%s,PinNum=%d,IntType=%d\n",__FUNCTION__,PinNum,IntType);   \r
+               //mutex_lock(&port->spi_lock);\r
+               spi_gpio_write_reg(reg, PinNum, IntType);\r
+               //mutex_unlock(&port->spi_lock);\r
+       }\r
+       else\r
+       {\r
+               printk("%s:error\n",__FUNCTION__);\r
+               return -1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+\r
+int spi_gpio_read_iir(void)\r
+{\r
+       int reg = ICE_SEL_GPIO0 | ICE_SEL_GPIO0_INT_STATE;\r
+       int ret = 0;\r
+\r
+       ret = spi_gpio_read_reg(reg);\r
+       DBG("%s,IntState=%d\n",__FUNCTION__,ret);\r
+       return ret;\r
+}\r
+\r
+int spi_request_gpio_irq(eSpiGpioPinNum_t PinNum, pSpiFunc Routine, eSpiGpioIntType_t IntType,void *dev_id)\r
+{                      \r
+       if(PinNum >= SPI_GPIO_IRQ_NUM)\r
+       return -1;\r
+       DBG("Enter::%s,LINE=%d,PinNum=%d\n",__FUNCTION__,__LINE__,PinNum);\r
+       if(spi_gpio_int_sel(PinNum,SPI_GPIO0_IS_INT))\r
+               return -1;\r
+       if(spi_gpio_set_int_trigger(PinNum,IntType))\r
+               return -1;\r
+       spin_lock(&gpio_irq_lock);\r
+       if(g_spiGpioVectorTable[PinNum].gpio_vector) \r
+       return -1;\r
+       g_spiGpioVectorTable[PinNum].gpio_vector = (pSpiFuncIntr)Routine;\r
+       g_spiGpioVectorTable[PinNum].gpio_devid= dev_id;\r
+       spin_unlock(&gpio_irq_lock);\r
+       if(spi_gpio_enable_int(PinNum))\r
+               return -1;\r
+       \r
+       return 0;\r
+}\r
+\r
+int spi_free_gpio_irq(eSpiGpioPinNum_t PinNum)\r
+{      \r
+       spi_gpio_disable_int(PinNum);\r
+       spin_lock(&gpio_irq_lock);\r
+       g_spiGpioVectorTable[PinNum].gpio_vector = NULL;\r
+       g_spiGpioVectorTable[PinNum].gpio_devid= NULL;\r
+       spin_unlock(&gpio_irq_lock);\r
+\r
+       return 0;\r
+}\r
+       \r
+\r
+int spi_gpio_handle_irq(struct spi_device *spi)\r
+{\r
+       int gpio_iir, i;\r
+\r
+#if 1\r
+       gpio_iir = spi_gpio_read_iir() & 0xffff;        \r
+       if(gpio_iir == 0xffff)\r
+               return -1;\r
+       //spin_lock(&gpio_state_lock);\r
+       DBG("gpio_iir=0x%x\n",gpio_iir);\r
+       for(i=0; i<SPI_GPIO_IRQ_NUM; i++)\r
+       {\r
+               if(((gpio_iir & (1 << i)) == 0) && ((gGpio0State & (1 << i)) != 0))\r
+               {\r
+                       if(g_spiGpioVectorTable[i].gpio_vector)\r
+                       {\r
+                       g_spiGpioVectorTable[i].gpio_vector(i,g_spiGpioVectorTable[i].gpio_devid);\r
+                       DBG("spi_gpio_irq=%d\n",i);\r
+                       }\r
+               }                       \r
+       }       \r
+       //spin_unlock(&gpio_state_lock);\r
+#endif\r
+\r
+       return  0;\r
+\r
+}\r
+\r
+int spi_gpio_init(void)\r
+{\r
+       int i,ret;\r
+       struct spi_fpga_port *port = pFpgaPort;\r
+#if HIGH_SPI_TEST      \r
+       printk("*************test spi communication now***************\n");\r
+       printk("%s:LINE=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       for(i=0;i<0xff;i++)\r
+       {\r
+               spi_out(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), i, SEL_GPIO);//all gpio is input\r
+               ret = spi_in(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+               if(i != ret)\r
+               printk("err:i=0x%x but ret=0x%x\n",i,ret);\r
+       }\r
+\r
+#endif\r
+#if (FPGA_TYPE == ICE_CC72)\r
+       for(i=0; i<16; i++)\r
+       {\r
+               DBG("i=%d\n\n",i);\r
+               spi_gpio_int_sel(i,SPI_GPIO0_IS_GPIO);\r
+               spi_gpio_set_pinlevel(i, SPI_GPIO_LOW);\r
+               spi_gpio_set_pindirection(i, SPI_GPIO_OUT);     \r
+       }\r
+/*     \r
+       for(i=6; i<16; i++)\r
+       {\r
+               DBG("i=%d\n\n",i);\r
+               spi_gpio_int_sel(i,SPI_GPIO0_IS_INT);\r
+               spi_gpio_set_int_trigger(i,SPI_GPIO_EDGE_FALLING);\r
+               spi_gpio_disable_int(i);        \r
+       }       \r
+*/     \r
+       for(i=16; i<32; i++)\r
+       {\r
+               spi_gpio_set_pinlevel(i, SPI_GPIO_LOW);\r
+               spi_gpio_set_pindirection(i, SPI_GPIO_OUT);\r
+       }\r
+       \r
+       //spi_out(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DATA), 0, SEL_GPIO);//all gpio is zero\r
+       //spi_out(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), 0, SEL_GPIO);//all gpio is input\r
+       \r
+#elif (FPGA_TYPE == ICE_CC196)\r
+\r
+#if 0\r
+       for(i=0;i<82;i++)\r
+       {\r
+               if(i<16)\r
+               spi_gpio_int_sel(i,SPI_GPIO0_IS_GPIO);          \r
+               spi_gpio_set_pindirection(i, SPI_GPIO_OUT);     \r
+       }\r
+       \r
+       while(1)\r
+       {\r
+               if(TestGpioPinLevel == 0)\r
+               TestGpioPinLevel = 1;\r
+               else\r
+               TestGpioPinLevel = 0;\r
+               for(i=0;i<82;i++)\r
+               {\r
+                       spi_gpio_set_pinlevel(i, TestGpioPinLevel);\r
+                       ret = spi_gpio_get_pinlevel(i);\r
+                       if(ret != TestGpioPinLevel)\r
+                       DBG("PinNum=%d,set_pinlevel=%d,get_pinlevel=%d\n\n",i,TestGpioPinLevel,ret);    \r
+               }\r
+               mdelay(10);\r
+\r
+               DBG("%s:LINE=%d\n",__FUNCTION__,__LINE__);\r
+       }\r
+\r
+#endif\r
+       \r
+#if 0\r
+       DBG("%s:LINE=%d\n",__FUNCTION__,__LINE__);\r
+       spi_out(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO0_TYPE), 0x0000, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO0_TYPE), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0000)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO_DATA), 0x0000, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0000)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO_DIR), 0xffff, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO0 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xffff)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+\r
+       spi_out(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DATA), 0x0224, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0224)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), 0xf7ef, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xf7ef)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO2 | ICE_SEL_GPIO_DATA), 0x2008, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO2 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x2008)\r
+       DBG("%s:Line=%d,set=0x2008,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO2 | ICE_SEL_GPIO_DIR), 0xf378, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO1 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xf378)\r
+       DBG("%s:Line=%d,set=0xf378,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+\r
+       spi_out(port, (ICE_SEL_GPIO3 | ICE_SEL_GPIO_DATA), 0x0000, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO3 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0000)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO3 | ICE_SEL_GPIO_DIR), 0xffff, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO3 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xffff)\r
+       DBG("%s:Line=%d,set=0xffff,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+\r
+       spi_out(port, (ICE_SEL_GPIO4 | ICE_SEL_GPIO_DATA), 0x0000, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO4 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0000)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO4 | ICE_SEL_GPIO_DIR), 0xffbf, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO4 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xffbf)\r
+       DBG("%s:Line=%d,set=0xffbf,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO5 | ICE_SEL_GPIO_DATA), 0x0000, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO5 | ICE_SEL_GPIO_DATA), SEL_GPIO) & 0xffff;\r
+       if(ret != 0x0000)\r
+       DBG("%s:Line=%d,set=0x0000,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       spi_out(port, (ICE_SEL_GPIO5 | ICE_SEL_GPIO_DIR), 0xffff, SEL_GPIO);\r
+       ret = spi_in(port, (ICE_SEL_GPIO5 | ICE_SEL_GPIO_DIR), SEL_GPIO) & 0xffff;\r
+       if(ret != 0xffff)\r
+       DBG("%s:Line=%d,set=0xffff,ret=0x%x\n",__FUNCTION__,__LINE__,ret);\r
+       \r
+       \r
+#else\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_00, SPI_GPIO_LOW);            //LCD_ON output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_00, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_01, SPI_GPIO_LOW);            //LCD_PWR_CTRL output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_01, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_02, SPI_GPIO_HIGH);           //SD_POW_ON output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_02, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_03, SPI_GPIO_LOW);            //WL_RST_N/WIFI_EN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_03, SPI_GPIO_OUT);\r
+       \r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_04, SPI_GPIO_IN);         //HARDO,input\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_05, SPI_GPIO_HIGH);           //SENSOR_PWDN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_05, SPI_GPIO_OUT);        \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_06, SPI_GPIO_LOW);            //BT_PWR_EN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_06, SPI_GPIO_OUT);        \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_07, SPI_GPIO_LOW);            //BT_RST output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_07, SPI_GPIO_OUT);\r
+       \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_08, SPI_GPIO_LOW);            //BT_WAKE_B output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_08, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_09, SPI_GPIO_HIGH);           //LCD_DISP_ON output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_09, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_10, SPI_GPIO_LOW);            //WM_PWR_EN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_10, SPI_GPIO_OUT);\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_11, SPI_GPIO_IN);         //HARD1,input\r
+       \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_12, SPI_GPIO_LOW);            //VIB_MOTO output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_12, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_13, SPI_GPIO_HIGH);           //KEYLED_EN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_13, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_14, SPI_GPIO_LOW);            //CAM_RST output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_14, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P1_15, SPI_GPIO_LOW);            //WL_WAKE_B output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P1_15, SPI_GPIO_OUT);\r
+\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_00, SPI_GPIO_IN);                 //Y+YD input\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_01, SPI_GPIO_IN);                 //Y-YU input\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_02, SPI_GPIO_IN);                 //AP_TD_UNDIFED input   \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_03, SPI_GPIO_HIGH);           //AP_PW_EN_TD output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_03, SPI_GPIO_OUT);\r
+       \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_04, SPI_GPIO_LOW);            //AP_RESET_TD output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_04, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_05, SPI_GPIO_LOW);            //AP_SHUTDOWN_TD_PMU output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_05, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_06, SPI_GPIO_LOW);            //AP_RESET_CMMB output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_06, SPI_GPIO_OUT);\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_07, SPI_GPIO_IN);         //AP_CHECK_TD_STATUS input\r
+       \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_08, SPI_GPIO_LOW);            //CHARGE_CURRENT_SEL output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_08, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_09, SPI_GPIO_LOW);            //AP_PWD_CMMB output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_09, SPI_GPIO_OUT);\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_10, SPI_GPIO_IN);         //X-XL input\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_11, SPI_GPIO_IN);         //X+XR input\r
+       \r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_12, SPI_GPIO_LOW);            //LCD_RESET output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_12, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_13, SPI_GPIO_HIGH);           //USB_PWR_EN output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_13, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_14, SPI_GPIO_LOW);            //WL_HOST_WAKE_B output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_14, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P2_15, SPI_GPIO_LOW);            //TOUCH_SCREEN_RST output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P2_15, SPI_GPIO_OUT);\r
+\r
+       spi_gpio_set_pindirection(SPI_GPIO_P4_06, SPI_GPIO_IN);         //CHARGER_INT_END input\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P4_07, SPI_GPIO_LOW);            //TOUCH_SCREEN_RST output\r
+       spi_gpio_set_pindirection(SPI_GPIO_P4_07, SPI_GPIO_OUT);\r
+       spi_gpio_set_pinlevel(SPI_GPIO_P4_08, SPI_GPIO_LOW);            //CM3605_PS_SHUTDOWN\r
+       spi_gpio_set_pindirection(SPI_GPIO_P4_08, SPI_GPIO_OUT);\r
+       \r
+#endif\r
+\r
+#endif\r
+       return 0;\r
+\r
+}\r
+\r
+\r
+#if SPI_GPIO_TEST\r
+volatile int TestGpioPinLevel = 0;\r
+void spi_gpio_work_handler(struct work_struct *work)\r
+{\r
+       struct spi_fpga_port *port =\r
+               container_of(work, struct spi_fpga_port, gpio.spi_gpio_work);\r
+       int i,ret;\r
+       printk("*************test spi_gpio now***************\n");\r
+       \r
+       if(TestGpioPinLevel == 0)\r
+               TestGpioPinLevel = 1;\r
+       else\r
+               TestGpioPinLevel = 0;\r
+\r
+#if (FPGA_TYPE == ICE_CC72)\r
+       for(i=0;i<32;i++)\r
+       {\r
+               spi_gpio_set_pinlevel(i, TestGpioPinLevel);\r
+               ret = spi_gpio_get_pinlevel(i);\r
+               if(ret != TestGpioPinLevel)\r
+               DBG("PinNum=%d,set_pinlevel=%d,get_pinlevel=%d\n",i,TestGpioPinLevel,ret);\r
+               //spi_gpio_set_pindirection(i, SPI_GPIO_OUT);   \r
+       }\r
+\r
+#elif (FPGA_TYPE == ICE_CC196)\r
+       for(i=0;i<16;i++)\r
+       {\r
+               if(i<16)\r
+               spi_gpio_int_sel(i,SPI_GPIO0_IS_GPIO);          \r
+               spi_gpio_set_pindirection(i, SPI_GPIO_OUT);     \r
+       }\r
+       \r
+       for(i=0;i<81;i++)\r
+       {\r
+               spi_gpio_set_pinlevel(i, TestGpioPinLevel);\r
+               ret = spi_gpio_get_pinlevel(i);\r
+               if(ret != TestGpioPinLevel)\r
+               printk("err:PinNum=%d,set_pinlevel=%d but get_pinlevel=%d\n\n",i,TestGpioPinLevel,ret); \r
+       }\r
+\r
+       DBG("%s:LINE=%d\n",__FUNCTION__,__LINE__);\r
+\r
+#endif\r
+\r
+}\r
+\r
+static void spi_testgpio_timer(unsigned long data)\r
+{\r
+       struct spi_fpga_port *port = (struct spi_fpga_port *)data;\r
+       port->gpio.gpio_timer.expires  = jiffies + msecs_to_jiffies(1000);\r
+       add_timer(&port->gpio.gpio_timer);\r
+       //schedule_work(&port->gpio.spi_gpio_work);\r
+       queue_work(port->gpio.spi_gpio_workqueue, &port->gpio.spi_gpio_work);\r
+}\r
+\r
+#endif\r
+\r
+\r
+\r
+int spi_gpio_register(struct spi_fpga_port *port)\r
+{\r
+#if SPI_GPIO_TEST\r
+       char b[20];\r
+       sprintf(b, "spi_gpio_workqueue");\r
+       port->gpio.spi_gpio_workqueue = create_freezeable_workqueue(b);\r
+       if (!port->gpio.spi_gpio_workqueue) {\r
+               printk("cannot create spi_gpio workqueue\n");\r
+               return -EBUSY;\r
+       }\r
+       INIT_WORK(&port->gpio.spi_gpio_work, spi_gpio_work_handler);\r
+       setup_timer(&port->gpio.gpio_timer, spi_testgpio_timer, (unsigned long)port);\r
+       port->gpio.gpio_timer.expires  = jiffies+2000;//>1000ms\r
+       add_timer(&port->gpio.gpio_timer);\r
+\r
+#endif \r
+\r
+       spin_lock_init(&gpio_lock);\r
+       spin_lock_init(&gpio_state_lock);\r
+       spin_lock_init(&gpio_irq_lock);\r
+       DBG("%s:line=%d,port=0x%x\n",__FUNCTION__,__LINE__,(int)port);\r
+       return 0;\r
+}\r
+int spi_gpio_unregister(struct spi_fpga_port *port)\r
+{      \r
+       return 0;\r
+}\r
+\r
+MODULE_DESCRIPTION("Driver for spi2gpio.");\r
+MODULE_AUTHOR("luowei <lw@rock-chips.com>");\r
+MODULE_LICENSE("GPL");\r
+\r
+\r
diff --git a/drivers/fpga/spi_i2c.c b/drivers/fpga/spi_i2c.c
new file mode 100644 (file)
index 0000000..9500583
--- /dev/null
@@ -0,0 +1,445 @@
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/mutex.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/gfp.h>\r
+#include <linux/tty.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/spi/spi.h>\r
+#include <linux/delay.h>\r
+#include <linux/ioport.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/sched.h>\r
+#include <linux/kthread.h>\r
+#include <linux/jiffies.h>\r
+#include <linux/i2c.h>\r
+#include <mach/board.h>\r
+#include <mach/rk2818_iomap.h>\r
+\r
+#include "spi_fpga.h"\r
+\r
+#if defined(CONFIG_SPI_I2C_DEBUG)\r
+#define DBG(x...)   printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define SPI_I2C_TEST 0\r
+\r
+#define MAXMSGLEN   16\r
+#define DRV_NAME    "fpga_i2c"\r
+\r
+\r
+struct spi_i2c_data {\r
+       struct device *dev;\r
+       struct i2c_adapter adapter;\r
+       unsigned long scl_rate;\r
+       spinlock_t i2c_lock;    \r
+};\r
+\r
+\r
+int spi_i2c_handle_irq(struct spi_fpga_port *port,unsigned char channel)\r
+{\r
+       int reg;\r
+       int ret;\r
+\r
+       if(channel == 0)\r
+               reg =  ICE_SEL_I2C_INT|ICE_SEL_I2C_CH2;\r
+       else\r
+               reg =  ICE_SEL_I2C_INT|ICE_SEL_I2C_CH3;\r
+       \r
+       port->i2c.interrupt = 0;\r
+       ret = spi_in(port,reg,SEL_I2C);\r
+       if(ret == INT_I2C_READ_ACK)\r
+               port->i2c.interrupt = INT_I2C_READ_ACK;         \r
+       else if(ret == INT_I2C_READ_NACK)\r
+       {\r
+               printk("Error::read no ack!!check the I2C slave device \n");\r
+       }\r
+       else if(ret == INT_I2C_WRITE_ACK)\r
+               port->i2c.interrupt = INT_I2C_WRITE_ACK;\r
+       else if(ret == INT_I2C_WRITE_NACK)\r
+       {\r
+               printk("Error::write no ack!!check the I2C slave device \n");\r
+       }\r
+       else\r
+               printk("Error:ack value error!!check the I2C slave device \n");\r
+       return port->i2c.interrupt;\r
+}\r
+\r
+int spi_i2c_select_speed(int speed)\r
+{\r
+       int result = 0; \r
+       switch(speed)\r
+       {\r
+               case 10:\r
+                       result = ICE_SET_10K_I2C_SPEED; \r
+                       break;                  \r
+               case 100:\r
+                       result = ICE_SET_100K_I2C_SPEED;                \r
+                       break;                  \r
+               case 200:\r
+                       result = ICE_SET_200K_I2C_SPEED;        \r
+                       break;                  \r
+               case 300:                       \r
+                      result = ICE_SET_300K_I2C_SPEED; \r
+                       break;                  \r
+               case 400:                       \r
+                       result = ICE_SET_400K_I2C_SPEED;        \r
+                       break;                  \r
+               default:                        \r
+                       break;          \r
+       }\r
+       return result;\r
+}\r
+\r
+int spi_i2c_readbuf(struct spi_fpga_port *port ,struct i2c_msg *pmsg)\r
+{\r
+       \r
+       unsigned int reg ;\r
+       unsigned int len,i;\r
+       unsigned int slaveaddr;\r
+       unsigned int speed;\r
+       unsigned int channel = 0 ;\r
+       unsigned int result;\r
+       \r
+       slaveaddr = pmsg->addr;\r
+       len = pmsg->len;        \r
+       speed = spi_i2c_select_speed(pmsg->scl_rate);\r
+       \r
+       if(pmsg->channel == I2C_CH2)\r
+               channel = ICE_SEL_I2C_CH2;\r
+       else if(pmsg->channel == I2C_CH3)\r
+               channel = ICE_SEL_I2C_CH3;\r
+       else\r
+       {\r
+               printk("Error:try to read form error i2c channel\n");\r
+               return 0;\r
+       }\r
+       \r
+       if(pmsg->read_type == 0)\r
+       {\r
+               //slaveaddr ;\r
+               slaveaddr = slaveaddr<<1;\r
+               reg = channel |ICE_SEL_I2C_START;\r
+               spi_out(port,reg,slaveaddr,SEL_I2C);\r
+               //speed;\r
+               reg = channel |ICE_SEL_I2C_SPEED|ICE_SEL_I2C_TRANS;\r
+               spi_out(port,reg,speed,SEL_I2C);\r
+               //len;\r
+               reg = channel |ICE_SEL_I2C_FIFO |ICE_SEL_I2C_TRANS;\r
+               spi_out(port,reg,len,SEL_I2C);\r
+               reg = channel  |ICE_SEL_I2C_TRANS;\r
+               //data;\r
+               for(i = 0 ;i < len;i++)\r
+               {\r
+                       if(i == len-1)\r
+                               reg = channel  |ICE_SEL_I2C_STOP;\r
+                       spi_out(port,reg,pmsg->buf[i],SEL_I2C);\r
+               }               \r
+               \r
+       }\r
+       //slaveaddr\r
+       slaveaddr = slaveaddr|ICE_I2C_SLAVE_READ;\r
+       if(pmsg->read_type == 0)\r
+               reg = channel |ICE_SEL_I2C_RESTART;\r
+       else\r
+               reg = channel |ICE_SEL_I2C_START;\r
+       spi_out(port,reg,slaveaddr,SEL_I2C);\r
+       //speed;\r
+       reg = channel |ICE_SEL_I2C_SPEED|ICE_SEL_I2C_TRANS;\r
+       spi_out(port,reg,speed,SEL_I2C);\r
+       //len;\r
+       reg = channel |ICE_SEL_I2C_FIFO |ICE_SEL_I2C_TRANS;\r
+       spi_out(port,reg,len,SEL_I2C);\r
+       \r
+       i=50;\r
+       while(i--)\r
+       {               \r
+               if(port->i2c.interrupt == INT_I2C_READ_ACK)\r
+               {                                               \r
+                       for(i = 0;i<len;i++)\r
+                       {\r
+                               result = spi_in(port,reg,SEL_I2C);\r
+                               pmsg->buf[i] = result & 0xFF;                           \r
+                       }\r
+                       spin_lock(&port->i2c.i2c_lock);\r
+                       port->i2c.interrupt &= INT_I2C_READ_MASK;\r
+                       spin_unlock(&port->i2c.i2c_lock);\r
+                       break;\r
+               }               \r
+       }\r
+       for(i = 0;i<len;i++)\r
+               DBG("pmsg->buf[%d] = 0x%x \n",i,pmsg->buf[i]);  \r
+       return pmsg->len;\r
+}\r
+int spi_i2c_writebuf(struct spi_fpga_port *port ,struct i2c_msg *pmsg)\r
+{\r
+       \r
+       unsigned int reg ;\r
+       unsigned int len,i;\r
+       unsigned int slaveaddr;\r
+       unsigned int speed;\r
+       unsigned int channel = 0;\r
+       \r
+       slaveaddr = pmsg->addr;\r
+       len = pmsg->len;        \r
+       speed = spi_i2c_select_speed(pmsg->scl_rate);\r
+       \r
+       if(pmsg->channel == I2C_CH2)\r
+               channel = ICE_SEL_I2C_CH2;\r
+       else if(pmsg->channel == I2C_CH3)\r
+               channel = ICE_SEL_I2C_CH3;\r
+       else\r
+       {\r
+               printk("Error: try to write the error i2c channel\n");\r
+               return 0;\r
+       }\r
+\r
+       //slaveaddr ;\r
+       slaveaddr = slaveaddr<<1;\r
+       reg = channel |ICE_SEL_I2C_START;\r
+       spi_out(port,reg,slaveaddr,SEL_I2C);\r
+       //speed;\r
+       reg = channel |ICE_SEL_I2C_SPEED|ICE_SEL_I2C_TRANS;\r
+       spi_out(port,reg,speed,SEL_I2C);\r
+       //len;\r
+       reg = channel |ICE_SEL_I2C_FIFO |ICE_SEL_I2C_TRANS;\r
+       spi_out(port,reg,len,SEL_I2C);\r
+       reg = channel  |ICE_SEL_I2C_TRANS;\r
+       //data;\r
+       for(i = 0 ;i < len;i++)\r
+       {\r
+               if(i == len-1)\r
+                       reg = channel|ICE_SEL_I2C_STOP;\r
+               spi_out(port,reg,pmsg->buf[i],SEL_I2C);\r
+       }\r
+       \r
+       i = 50;\r
+       while(i--)\r
+       {               \r
+               if(port->i2c.interrupt  == INT_I2C_WRITE_ACK)\r
+               {               \r
+                       spin_lock(&port->i2c.i2c_lock);\r
+                       port->i2c.interrupt &= INT_I2C_WRITE_MASK;\r
+                       spin_unlock(&port->i2c.i2c_lock);\r
+                       break;\r
+               }                       \r
+       }\r
+       DBG("wait num= %d,port->i2c.interrupt = 0x%x\n",i,port->i2c.interrupt);\r
+       return pmsg->len;\r
+       \r
+       \r
+}\r
+#if defined(CONFIG_SPI_I2C_DEBUG)\r
+unsigned short rda5400[][2] = \r
+{\r
+{0x3f,0x0000},//page 0\r
+{0x0B,0x3200},// pll_cal_eachtime\r
+{0x0E,0x5200},// rxfilter_op_cal_bit_dr rxfilter_sys_cal_bit_dr\r
+{0x13,0x016D},// fts_cap=01, for high nak rate at high temperature¡£\r
+{0x16,0x9C23},// Load8.5pf  crystal,2.2pf cap\r
+{0x17,0xBB12},// xtal_cpuclk_en,*\r
+{0x19,0xEE18},// rxfilter_bp_mode rxfilter_tuning_cap_for die\r
+{0x1A,0x59EE},// rmx_lo_reg=1011, tmx_iqswap\r
+{0x1C,0x008F},//\r
+{0x30,0x002B},//\r
+{0x3B,0x33EA},// rxfilter_imgrej_lo\r
+{0x3E,0x0040},// tmx_lo_reg set to1\r
+{0x3f,0x0001},//page 1\r
+{0x02,0x0001},// rxfilter_sys_cal_polarity\r
+{0x04,0xE41E},// ldo_ictrl<5bit> set to 1\r
+{0x05,0xBC00},//  ldo_ictrl<5bit> set to 1\r
+{0x06,0x262D},// \r
+{0x0B,0x001F},// vco_bit=111\r
+{0x10,0x0100},// thermo power setting\r
+{0x13,0x001C},// pre_sca=1100\r
+{0x19,0x001C},// lo_buff=1100, improve RF per formance at high temp\r
+{0x1a,0x1404},\r
+{0x1E,0x2A48},// resetn_ex_selfgen_enable=0, for 32K is no need when poweron\r
+{0x27,0x0070},// power table setting, maxpower\r
+{0x26,0x3254},// power table setting\r
+{0x25,0x2180},// power table settings\r
+{0x24,0x0000},// power table setting\r
+{0x23,0x0000},// power table setting\r
+{0x22,0x0000},// power table setting\r
+{0x21,0x0000},// power table setting\r
+{0x20,0x0000},// power table setting\r
+{0x37,0x0600},// padrv_cal_bypass\r
+{0x3A,0x06E0},// dcdc setting\r
+{0x3f,0x0000},//page 0\r
+};\r
+\r
+int spi_i2c_16bit_test(struct spi_fpga_port *port)\r
+{\r
+       u8 i2c_buf[8];\r
+       int len = 2;\r
+       int i ;\r
+       struct i2c_msg msg[1] = \r
+       {\r
+               {0x16,0,len+2,i2c_buf,200,3,0}\r
+       };\r
+       \r
+       for(i = 0;i < (sizeof(rda5400)/sizeof(rda5400[0]));i++)\r
+       {       \r
+               i2c_buf[0] = 0x22;\r
+               i2c_buf[1] = rda5400[i][0];\r
+               i2c_buf[1] = rda5400[i][1]>>8;\r
+               i2c_buf[2] = rda5400[i][1]&0xFF;\r
+               spi_i2c_writebuf(port, msg);\r
+               msg[0].len = 2;\r
+               spi_i2c_readbuf(port, msg);\r
+       }\r
+       return 0;\r
+       \r
+}\r
+\r
+int spi_i2c_8bit_test(struct spi_fpga_port *port)\r
+{\r
+       u8 i2c_buf[8];\r
+       int len = 2;\r
+       int i ;\r
+       struct i2c_msg msg[1] = \r
+       {\r
+               {0x16,0,len+1,i2c_buf,200,2,0}\r
+       };\r
+       \r
+       for(i = 0;i < (sizeof(rda5400)/sizeof(rda5400[0]));i++)\r
+       {       \r
+               i2c_buf[0] = rda5400[i][0];\r
+               i2c_buf[1] = rda5400[i][1]>>8;\r
+               i2c_buf[2] = rda5400[i][1]&0xFF;\r
+               spi_i2c_writebuf(port, msg);\r
+               msg[0].len = 1;\r
+               spi_i2c_readbuf(port, msg);\r
+       }\r
+       return 0;\r
+       \r
+}\r
+ int spi_i2c_test(void )\r
+{\r
+       struct spi_fpga_port *port = pFpgaPort;\r
+       printk("IN::************spi_i2c_test********\r\n");     \r
+       spi_i2c_8bit_test(port);\r
+       spi_i2c_16bit_test(port);\r
+       \r
+       printk("OUT::************spi_i2c_test********\r\n");\r
+       return 0;\r
+       \r
+}\r
+\r
+#endif\r
+\r
+\r
+ int spi_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *pmsg, int num)\r
+{\r
+       \r
+       struct spi_fpga_port *port = pFpgaPort;\r
+       \r
+       printk("%s:line=%d,channel = %d\n",__FUNCTION__,__LINE__,adapter->nr);\r
+       if(pmsg->len > MAXMSGLEN)\r
+               return 0;\r
+       if(pmsg->flags) \r
+               spi_i2c_readbuf(port,pmsg);\r
+       else\r
+               spi_i2c_writebuf(port,pmsg);\r
+\r
+       return pmsg->len;       \r
+\r
+       return 0;\r
+}\r
+\r
+static unsigned int spi_i2c_func(struct i2c_adapter *adapter)\r
+{\r
+       return (I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL);\r
+}\r
+                       \r
+static const struct i2c_algorithm spi_i2c_algorithm = {\r
+       .master_xfer            = spi_i2c_xfer,\r
+       .functionality          = spi_i2c_func,\r
+};\r
+\r
+static int spi_i2c_probe(struct platform_device *pdev)\r
+{\r
+       int ret;\r
+       struct spi_i2c_data *i2c;\r
+       struct rk2818_i2c_platform_data *pdata;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       pdata = pdev->dev.platform_data;\r
+       if(!pdata)\r
+       {\r
+               dev_err(&pdev->dev,"no platform data\n");\r
+               return -EINVAL; \r
+       }\r
+       i2c = kzalloc(sizeof(struct spi_i2c_data),GFP_KERNEL);\r
+       if(!i2c)\r
+       {\r
+               dev_err(&pdev->dev,"no memory for state\n");\r
+               return -ENOMEM;         \r
+       }\r
+       strlcpy(i2c->adapter.name,DRV_NAME,sizeof(i2c->adapter.name));\r
+       i2c->adapter.owner = THIS_MODULE;\r
+       i2c->adapter.algo  = &spi_i2c_algorithm;\r
+       i2c->adapter.class = I2C_CLASS_HWMON;   \r
+       \r
+       i2c->dev = &pdev->dev;\r
+       i2c->adapter.algo_data = i2c;\r
+       i2c->adapter.dev.parent = &pdev->dev;\r
+       i2c->adapter.nr = pdata->bus_num;\r
+       ret = i2c_add_numbered_adapter(&i2c->adapter);\r
+       if(ret < 0){\r
+               dev_err(&pdev->dev,"fail to add bus to i2c core fpga\n");\r
+               kfree(i2c);\r
+               return ret;\r
+       }\r
+       platform_set_drvdata(pdev,i2c);\r
+       printk("Enter::%s,LINE=%d i2c->adap.nr = %d ************************\n",__FUNCTION__,__LINE__,i2c->adapter.nr);\r
+       #if defined(CONFIG_SPI_I2C_DEBUG)\r
+       \r
+       #endif\r
+       return 0;       \r
+}\r
+\r
+static int spi_i2c_remove(struct platform_device *pdev)\r
+{\r
+       return 0;       \r
+}\r
+\r
+static struct platform_driver spi_i2c_driver = {\r
+       .probe   = spi_i2c_probe,\r
+       .remove  = spi_i2c_remove,      \r
+       .driver  = {\r
+               .owner = THIS_MODULE,\r
+               .name  = DRV_NAME,\r
+       },\r
+};\r
+\r
+static int __init spi_i2c_adap_init(void)\r
+{\r
+       printk(" *************Enter::%s,LINE=%d ************\n",__FUNCTION__,__LINE__);\r
+       return platform_driver_register(&spi_i2c_driver);       \r
+}\r
+static void __exit spi_i2c_adap_exit(void)\r
+{\r
+       platform_driver_unregister(&spi_i2c_driver);    \r
+}\r
+\r
+subsys_initcall(spi_i2c_adap_init);\r
+module_exit(spi_i2c_adap_exit);\r
+\r
+MODULE_DESCRIPTION("Driver for spi2i2c.");\r
+MODULE_AUTHOR("swj <swj@rock-chips.com>");\r
+MODULE_LICENSE("GPL");\r
+\r
+\r
diff --git a/drivers/fpga/spi_uart.c b/drivers/fpga/spi_uart.c
new file mode 100644 (file)
index 0000000..b6b6072
--- /dev/null
@@ -0,0 +1,1184 @@
+#include <linux/module.h>\r
+#include <linux/init.h>\r
+#include <linux/kernel.h>\r
+#include <linux/mutex.h>\r
+#include <linux/serial_reg.h>\r
+#include <linux/circ_buf.h>\r
+#include <linux/gfp.h>\r
+#include <linux/tty.h>\r
+#include <linux/tty_flip.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/spi/spi.h>\r
+#include <linux/delay.h>\r
+#include <linux/module.h>\r
+#include <linux/ioport.h>\r
+#include <linux/console.h>\r
+#include <linux/sysrq.h>\r
+#include <mach/gpio.h>\r
+#include <mach/iomux.h>\r
+#include <asm/io.h>\r
+#include <asm/irq.h>\r
+#include <linux/miscdevice.h>\r
+#include <linux/poll.h>\r
+#include <linux/sched.h>\r
+#include <linux/kthread.h>\r
+#include <linux/jiffies.h>\r
+#include <linux/i2c.h>\r
+#include <mach/rk2818_iomap.h>\r
+\r
+#include "spi_fpga.h"\r
+\r
+#if defined(CONFIG_SPI_UART_DEBUG)\r
+#define DBG(x...)   printk(x)\r
+#else\r
+#define DBG(x...)\r
+#endif\r
+\r
+#define SPI_UART_TEST 0\r
+\r
+static struct tty_driver *spi_uart_tty_driver;\r
+/*------------------------ÒÔÏÂÊÇspi2uart±äÁ¿-----------------------*/\r
+\r
+#define UART_NR                1       /* Number of UARTs this driver can handle */\r
+\r
+#define UART_XMIT_SIZE PAGE_SIZE\r
+#define WAKEUP_CHARS   1024\r
+\r
+#define circ_empty(circ)       ((circ)->head == (circ)->tail)\r
+#define circ_clear(circ)       ((circ)->head = (circ)->tail = 0)\r
+\r
+#define circ_chars_pending(circ) \\r
+               (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))\r
+\r
+#define circ_chars_free(circ) \\r
+               (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))\r
+\r
+\r
+\r
+\r
+static struct spi_uart *spi_uart_table[UART_NR];\r
+static DEFINE_SPINLOCK(spi_uart_table_lock);\r
+\r
+\r
+static int spi_uart_add_port(struct spi_uart *uart)\r
+{\r
+       int index, ret = -EBUSY;\r
+\r
+       kref_init(&uart->kref);\r
+       mutex_init(&uart->open_lock);\r
+       spin_lock_init(&uart->write_lock);\r
+       spin_lock_init(&uart->irq_lock);\r
+       \r
+       spin_lock(&spi_uart_table_lock);\r
+       for (index = 0; index < UART_NR; index++) \r
+       {\r
+               if (!spi_uart_table[index]) {\r
+                       uart->index = index;\r
+                       //printk("index=%d\n\n",index);\r
+                       spi_uart_table[index] = uart;\r
+                       ret = 0;\r
+                       break;\r
+               }\r
+       }\r
+       spin_unlock(&spi_uart_table_lock);\r
+\r
+       return ret;\r
+}\r
+\r
+static struct spi_uart *spi_uart_port_get(unsigned index)\r
+{\r
+       struct spi_uart *uart;\r
+\r
+       if (index >= UART_NR)\r
+               return NULL;\r
+\r
+       spin_lock(&spi_uart_table_lock);\r
+       uart = spi_uart_table[index];\r
+       uart->index = index;\r
+       printk("uart->index=%d\n",uart->index);\r
+       if (uart)\r
+               kref_get(&uart->kref);\r
+       spin_unlock(&spi_uart_table_lock);\r
+\r
+       return uart;\r
+}\r
+\r
+static void spi_uart_port_destroy(struct kref *kref)\r
+{\r
+       struct spi_uart *uart =\r
+               container_of(kref, struct spi_uart, kref);\r
+       kfree(uart);\r
+}\r
+\r
+static void spi_uart_port_put(struct spi_uart *uart)\r
+{\r
+       kref_put(&uart->kref, spi_uart_port_destroy);\r
+}\r
+\r
+static void spi_uart_port_remove(struct spi_uart *uart)\r
+{\r
+       struct spi_device *spi;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       BUG_ON(spi_uart_table[uart->index] != uart);\r
+\r
+       spin_lock(&spi_uart_table_lock);\r
+       spi_uart_table[uart->index] = NULL;\r
+       spin_unlock(&spi_uart_table_lock);\r
+\r
+       /*\r
+        * We're killing a port that potentially still is in use by\r
+        * the tty layer. Be careful to arrange for the tty layer to\r
+        * give up on that port ASAP.\r
+        * Beware: the lock ordering is critical.\r
+        */\r
+       mutex_lock(&uart->open_lock);\r
+       //mutex_lock(&port->spi_lock);\r
+       spi = port->spi;\r
+\r
+       port->spi = NULL;\r
+       //mutex_unlock(&port->spi_lock);\r
+       if (uart->opened)\r
+               tty_hangup(uart->tty);\r
+       mutex_unlock(&uart->open_lock);\r
+\r
+       spi_uart_port_put(uart);\r
+}\r
+\r
+static unsigned int spi_uart_get_mctrl(struct spi_uart *uart)\r
+{\r
+       unsigned char status;\r
+       unsigned int ret;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       status = spi_in(port, UART_MSR, SEL_UART);//\r
+       ret = 0;\r
+#if 0\r
+       if (status & UART_MSR_DCD)\r
+               ret |= TIOCM_CAR;\r
+       if (status & UART_MSR_RI)\r
+               ret |= TIOCM_RNG;\r
+       if (status & UART_MSR_DSR)\r
+               ret |= TIOCM_DSR;       \r
+       if (status & UART_MSR_CTS)\r
+               ret |= TIOCM_CTS;\r
+#endif\r
+       if (status & UART_MSR_CTS)\r
+               ret = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;\r
+       DBG("Enter::%s,LINE=%d,ret=0x%x************************\n",__FUNCTION__,__LINE__,ret);\r
+       return ret;\r
+}\r
+\r
+static void spi_uart_write_mctrl(struct spi_uart *uart, unsigned int mctrl)\r
+{\r
+       unsigned char mcr = 0;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+#if 1\r
+       if (mctrl & TIOCM_RTS)\r
+       {\r
+               mcr |= UART_MCR_RTS;\r
+               mcr |= UART_MCR_AFE;\r
+       }\r
+       //if (mctrl & TIOCM_DTR)\r
+       //      mcr |= UART_MCR_DTR;\r
+       //if (mctrl & TIOCM_OUT1)\r
+       //      mcr |= UART_MCR_OUT1;\r
+       //if (mctrl & TIOCM_OUT2)\r
+       //      mcr |= UART_MCR_OUT2;\r
+       //if (mctrl & TIOCM_LOOP)\r
+       //      mcr |= UART_MCR_LOOP;\r
+       \r
+#endif\r
+       \r
+       DBG("Enter::%s,LINE=%d,mcr=0x%x\n",__FUNCTION__,__LINE__,mcr);\r
+       spi_out(port, UART_MCR, mcr, SEL_UART);\r
+}\r
+\r
+static inline void spi_uart_update_mctrl(struct spi_uart *uart,\r
+                                         unsigned int set, unsigned int clear)\r
+{\r
+       unsigned int old;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       old = uart->mctrl;\r
+       uart->mctrl = (old & ~clear) | set;\r
+       if (old != uart->mctrl)\r
+               spi_uart_write_mctrl(uart, uart->mctrl);\r
+}\r
+\r
+#define spi_uart_set_mctrl(uart, x)    spi_uart_update_mctrl(uart, x, 0)\r
+#define spi_uart_clear_mctrl(uart, x)  spi_uart_update_mctrl(uart, 0, x)\r
+\r
+static void spi_uart_change_speed(struct spi_uart *uart,\r
+                                  struct ktermios *termios,\r
+                                  struct ktermios *old)\r
+{\r
+       unsigned char cval, fcr = 0;\r
+       unsigned int baud, quot;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       switch (termios->c_cflag & CSIZE) {\r
+       case CS5:\r
+               cval = UART_LCR_WLEN5;\r
+               break;\r
+       case CS6:\r
+               cval = UART_LCR_WLEN6;\r
+               break;\r
+       case CS7:\r
+               cval = UART_LCR_WLEN7;\r
+               break;\r
+       default:\r
+       case CS8:\r
+               cval = UART_LCR_WLEN8;\r
+               break;\r
+       }\r
+\r
+       if (termios->c_cflag & CSTOPB)\r
+               cval |= UART_LCR_STOP;\r
+       if (termios->c_cflag & PARENB)\r
+               cval |= UART_LCR_PARITY;\r
+       if (!(termios->c_cflag & PARODD))\r
+               cval |= UART_LCR_EPAR;\r
+\r
+       for (;;) {\r
+               baud = tty_termios_baud_rate(termios);\r
+               if (baud == 0)\r
+                       baud = 115200;  /* Special case: B0 rate. */\r
+               if (baud <= uart->uartclk)\r
+                       break;\r
+               /*\r
+                * Oops, the quotient was zero.  Try again with the old\r
+                * baud rate if possible, otherwise default to 115200.\r
+                */\r
+               termios->c_cflag &= ~CBAUD;\r
+               if (old) {\r
+                       termios->c_cflag |= old->c_cflag & CBAUD;\r
+                       old = NULL;\r
+               } else\r
+                       termios->c_cflag |= B115200;\r
+       }\r
+       //quot = (2 * uart->uartclk + baud) / (2 * baud);\r
+       quot = (uart->uartclk / baud);\r
+       printk("baud=%d,quot=0x%x\n",baud,quot);\r
+       if (baud < 2400)\r
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;\r
+       else\r
+               fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;\r
+\r
+       uart->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;\r
+       if (termios->c_iflag & INPCK)\r
+               uart->read_status_mask |= UART_LSR_FE | UART_LSR_PE;\r
+       if (termios->c_iflag & (BRKINT | PARMRK))\r
+               uart->read_status_mask |= UART_LSR_BI;\r
+\r
+       /*\r
+        * Characters to ignore\r
+        */\r
+       uart->ignore_status_mask = 0;\r
+       if (termios->c_iflag & IGNPAR)\r
+               uart->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;\r
+       if (termios->c_iflag & IGNBRK) {\r
+               uart->ignore_status_mask |= UART_LSR_BI;\r
+               /*\r
+                * If we're ignoring parity and break indicators,\r
+                * ignore overruns too (for real raw support).\r
+                */\r
+               if (termios->c_iflag & IGNPAR)\r
+                       uart->ignore_status_mask |= UART_LSR_OE;\r
+       }\r
+\r
+       /*\r
+        * ignore all characters if CREAD is not set\r
+        */\r
+       if ((termios->c_cflag & CREAD) == 0)\r
+               uart->ignore_status_mask |= UART_LSR_DR;\r
+\r
+       /*\r
+        * CTS flow control flag and modem status interrupts\r
+        */\r
+       uart->ier &= ~UART_IER_MSI;\r
+       if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))\r
+       {\r
+               //uart->ier |= UART_IER_MSI;\r
+               //uart->mcr = UART_MCR_RTS;//mcr = UART_MCR_RTS while start RTSCTS\r
+       }\r
+\r
+       uart->lcr = cval;\r
+\r
+       spi_out(port, UART_IER, uart->ier, SEL_UART);\r
+       spi_out(port, UART_LCR, cval | UART_LCR_DLAB, SEL_UART);\r
+       spi_out(port, UART_DLL, quot & 0xff, SEL_UART);\r
+       spi_out(port, UART_DLM, quot >> 8, SEL_UART);\r
+       spi_out(port, UART_LCR, cval, SEL_UART);\r
+       spi_out(port, UART_FCR, fcr, SEL_UART);\r
+       DBG("Enter::%s,LINE=%d,baud=%d,uart->ier=0x%x,cval=0x%x,fcr=0x%x,quot=0x%x\n",\r
+               __FUNCTION__,__LINE__,baud,uart->ier,cval,fcr,quot);\r
+       spi_uart_write_mctrl(uart, uart->mctrl);\r
+}\r
+\r
+static void spi_uart_start_tx(struct spi_uart *uart)\r
+{\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+#if 1\r
+       //unsigned long flags;\r
+       if (!(uart->ier & UART_IER_THRI)) {\r
+               //spin_lock_irqsave(&uart->write_lock, flags);\r
+               uart->ier |= UART_IER_THRI;\r
+               spi_out(port, UART_IER, uart->ier, SEL_UART);\r
+               //spin_unlock_irqrestore(&uart->write_lock, flags);     \r
+               printk("t,");\r
+       }       \r
+       \r
+       DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+#endif\r
+}\r
+\r
+static void spi_uart_stop_tx(struct spi_uart *uart)\r
+{\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       //unsigned long flags;\r
+       if (uart->ier & UART_IER_THRI) {\r
+               //spin_lock_irqsave(&uart->write_lock, flags);\r
+               uart->ier &= ~UART_IER_THRI;\r
+               spi_out(port, UART_IER, uart->ier, SEL_UART);\r
+               //spin_unlock_irqrestore(&uart->write_lock, flags);     \r
+               //printk("p");\r
+       }\r
+       DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+}\r
+\r
+static void spi_uart_stop_rx(struct spi_uart *uart)\r
+{\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       uart->ier &= ~UART_IER_RLSI;\r
+       uart->read_status_mask &= ~UART_LSR_DR;\r
+       spi_out(port, UART_IER, uart->ier, SEL_UART);\r
+}\r
+\r
+static void spi_uart_receive_chars(struct spi_uart *uart, unsigned int *status)\r
+{\r
+       struct tty_struct *tty = uart->tty;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       unsigned int ch, flag;\r
+       int max_count = 1024;   \r
+       //printk("rx:");\r
+       while (--max_count >0 )\r
+       {\r
+               ch = spi_in(port, UART_RX, SEL_UART);//\r
+               //printk("0x%x,",ch&0xff);\r
+               flag = TTY_NORMAL;\r
+               uart->icount.rx++;\r
+               //--max_count;\r
+#if 1\r
+               if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |\r
+                                       UART_LSR_FE | UART_LSR_OE))) {\r
+                       /*\r
+                        * For statistics only\r
+                        */\r
+                       if (*status & UART_LSR_BI) {\r
+                               *status &= ~(UART_LSR_FE | UART_LSR_PE);\r
+                               uart->icount.brk++;\r
+                       } else if (*status & UART_LSR_PE)\r
+                               uart->icount.parity++;\r
+                       else if (*status & UART_LSR_FE)\r
+                               uart->icount.frame++;\r
+                       if (*status & UART_LSR_OE)\r
+                               uart->icount.overrun++;\r
+\r
+                       /*\r
+                        * Mask off conditions which should be ignored.\r
+                        */\r
+                       *status &= uart->read_status_mask;\r
+                       if (*status & UART_LSR_BI) {\r
+                               flag = TTY_BREAK;\r
+                       } else if (*status & UART_LSR_PE)\r
+                               flag = TTY_PARITY;\r
+                       else if (*status & UART_LSR_FE)\r
+                               flag = TTY_FRAME;\r
+               }\r
+#endif\r
+               if ((*status & uart->ignore_status_mask & ~UART_LSR_OE) == 0)\r
+                       tty_insert_flip_char(tty, ch, flag);\r
+\r
+               /*\r
+                * Overrun is special.  Since it's reported immediately,\r
+                * it doesn't affect the current character.\r
+                */\r
+               if (*status & ~uart->ignore_status_mask & UART_LSR_OE)\r
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);\r
+               *status = spi_in(port, UART_LSR, SEL_UART);\r
+               if(!(*status & UART_LSR_DR))\r
+                       break;\r
+       } \r
+       //printk("\n");\r
+       DBG("Enter::%s,LINE=%d,rx_count=%d********\n",__FUNCTION__,__LINE__,(1024-max_count));\r
+       printk("r%d\n",1024-max_count);\r
+       tty_flip_buffer_push(tty);\r
+       \r
+}\r
+\r
+static void spi_uart_transmit_chars(struct spi_uart *uart)\r
+{\r
+       struct circ_buf *xmit = &uart->xmit;\r
+       int count;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       if (uart->x_char) {\r
+               spi_out(port, UART_TX, uart->x_char, SEL_UART);\r
+               uart->icount.tx++;\r
+               uart->x_char = 0;\r
+               printk("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+               return;\r
+       }\r
+       if (circ_empty(xmit) || uart->tty->stopped || uart->tty->hw_stopped) {\r
+               spi_uart_stop_tx(uart);\r
+               DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+               //printk("circ_empty()\n");\r
+               return;\r
+       }\r
+       //printk("tx:");\r
+       count = 32;//\r
+       while(count > 0)\r
+       {\r
+               spi_out(port, UART_TX, xmit->buf[xmit->tail], SEL_UART);\r
+               //printk("0x%x,",xmit->buf[xmit->tail]);\r
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);\r
+               uart->icount.tx++;\r
+               --count;\r
+               if (circ_empty(xmit))\r
+               break;  \r
+       }\r
+\r
+       //printk("\n");\r
+       DBG("Enter::%s,LINE=%d,tx_count=%d\n",__FUNCTION__,__LINE__,(32-count));\r
+       if (circ_chars_pending(xmit) < WAKEUP_CHARS)\r
+       {       \r
+               tty_wakeup(uart->tty);\r
+               printk("k,");\r
+       }\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       if (circ_empty(xmit))\r
+       {\r
+               DBG("circ_empty(xmit)\n");\r
+               spi_uart_stop_tx(uart);\r
+               printk("e,");\r
+       }\r
+       \r
+       printk("t%d\n",32-count);\r
+\r
+       DBG("uart->tty->hw_stopped = %d\n",uart->tty->hw_stopped);\r
+}\r
+\r
+#if 0\r
+static void spi_uart_check_modem_status(struct spi_uart *uart)\r
+{\r
+       int status;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       status = spi_in(port, UART_MSR, SEL_UART);//\r
+       DBG("Enter::%s,LINE=%d,status=0x%x*******\n",__FUNCTION__,__LINE__,status);\r
+       if ((status & UART_MSR_ANY_DELTA) == 0)\r
+               return;\r
+\r
+       if (status & UART_MSR_TERI)\r
+               uart->icount.rng++;\r
+       if (status & UART_MSR_DDSR)\r
+               uart->icount.dsr++;\r
+       if (status & UART_MSR_DDCD)\r
+               uart->icount.dcd++;\r
+       if (status & UART_MSR_DCTS) {\r
+               uart->icount.cts++;\r
+               if (uart->tty->termios->c_cflag & CRTSCTS) {\r
+                       int cts = (status & UART_MSR_CTS);\r
+                       if (uart->tty->hw_stopped) {\r
+                               if (cts) {\r
+                                       uart->tty->hw_stopped = 0;\r
+                                       spi_uart_start_tx(uart);\r
+                                       DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+                                       tty_wakeup(uart->tty);\r
+                               }\r
+                       } else {\r
+                               if (!cts) {\r
+                                       uart->tty->hw_stopped = 1;\r
+                                       DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+                                       spi_uart_stop_tx(uart);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       DBG("Enter::%s,LINE=%d,status=0x%x*******\n",__FUNCTION__,__LINE__,status);\r
+}\r
+#endif\r
+\r
+\r
+#if SPI_UART_TEST\r
+#define UART_TEST_LEN 16       //8bit\r
+unsigned char buf_test_uart[UART_TEST_LEN];\r
+unsigned int ice65l08_init_para[]=\r
+{\r
+       0x030083,                                       \r
+       0x010000,\r
+       0x000034,                                       // (0100XYH) ÉèÖ÷ÖƵϵÊý£ºXY =  MCLK / (4*²¨ÌØÂÊ)£»\r
+       0x030003,                                       // ÉèÖÃ×Ö½ÚÓÐЧ³¤¶È£º 8 bits£»\r
+       0x01000f,                                       // TX RX ÖжÏ\r
+       0x020080,                                       // ÉèÖô¥·¢µÈ¼¶   ½ÓÊÜFIFOΪ 16bytes ²úÉúÖжϣ»\r
+};\r
+\r
+void spi_uart_work_handler(struct work_struct *work)\r
+{\r
+       int i;\r
+       int ret,count;\r
+       int offset,value;\r
+       struct spi_fpga_port *port =\r
+               container_of(work, struct spi_fpga_port, uart.spi_uart_work);\r
+       printk("*************test spi_uart now***************\n");\r
+\r
+       for(i=0;i<UART_TEST_LEN;i++)\r
+       buf_test_uart[i] = '0'+i;       \r
+\r
+       for(i =0; i<sizeof(ice65l08_init_para)/sizeof(ice65l08_init_para[0]); i++)\r
+       {\r
+               offset = (ice65l08_init_para[i] >> 16) & 0xff;\r
+               value = ice65l08_init_para[i] & 0xffff;\r
+               spi_out(port, offset, value, SEL_UART);\r
+       }       \r
+       \r
+       count = UART_TEST_LEN;\r
+       while(count > 0)\r
+       {\r
+               spi_out(port, UART_TX, buf_test_uart[UART_TEST_LEN-count], SEL_UART);\r
+               --count;\r
+       }\r
+}\r
+\r
+static void spi_testuart_timer(unsigned long data)\r
+{\r
+       struct spi_fpga_port *port = (struct spi_fpga_port *)data;\r
+       port->uart.uart_timer.expires  = jiffies + msecs_to_jiffies(1000);\r
+       add_timer(&port->uart.uart_timer);\r
+       //schedule_work(&port->gpio.spi_gpio_work);\r
+       queue_work(port->uart.spi_uart_workqueue, &port->uart.spi_uart_work);\r
+}\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+/*\r
+ * This handles the interrupt from one port.\r
+ */\r
+void spi_uart_handle_irq(struct spi_device *spi)\r
+{\r
+       struct spi_fpga_port *port = spi_get_drvdata(spi);\r
+       struct spi_uart *uart = &port->uart;\r
+       unsigned int uart_iir, lsr;\r
+\r
+       if (unlikely(uart->in_spi_uart_irq == current))\r
+               return;\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+\r
+       /*\r
+        * In a few places spi_uart_handle_irq() is called directly instead of\r
+        * waiting for the actual interrupt to be raised and the SPI IRQ\r
+        * thread scheduled in order to reduce latency.  However, some\r
+        * interaction with the tty core may end up calling us back\r
+        * (serial echo, flow control, etc.) through those same places\r
+        * causing undesirable effects.  Let's stop the recursion here.\r
+        */\r
+        \r
+       uart_iir = spi_in(port, UART_IIR, SEL_UART);//  \r
+       if (uart_iir & UART_IIR_NO_INT)\r
+               return;\r
+       \r
+       DBG("iir=0x%x\n",uart_iir);\r
+               \r
+       uart->in_spi_uart_irq = current;\r
+       lsr = spi_in(port, UART_LSR, SEL_UART);//\r
+       DBG("lsr=0x%x\n",lsr);\r
+\r
+       if (lsr & UART_LSR_DR)\r
+       //if (((uart_iir & UART_IIR_RDI) | (uart_iir & UART_IIR_RLSI)) &&  (lsr & UART_LSR_DR))\r
+       {\r
+               DBG("Enter::%s,LINE=%d,lsr & UART_LSR_DR************\n",__FUNCTION__,__LINE__);\r
+               spi_uart_receive_chars(uart, &lsr);     \r
+       }\r
+\r
+       //spi_uart_check_modem_status(uart);\r
+       \r
+       \r
+       if (lsr & UART_LSR_THRE)\r
+       //if ((uart_iir & UART_IIR_THRI)&&(lsr & UART_LSR_THRE))\r
+       {\r
+               DBG("Enter::%s,LINE=%d,ICE_STATUS_TXF == 0************\n",__FUNCTION__,__LINE__);\r
+               spi_uart_transmit_chars(uart);\r
+       }\r
+\r
+       uart->in_spi_uart_irq = NULL;\r
+\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       \r
+}\r
+\r
+static int spi_uart_startup(struct spi_uart *uart)\r
+{\r
+       unsigned long page;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       \r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       /*\r
+        * Set the TTY IO error marker - we will only clear this\r
+        * once we have successfully opened the port.\r
+        */\r
+       set_bit(TTY_IO_ERROR, &uart->tty->flags);\r
+\r
+       /* Initialise and allocate the transmit buffer. */\r
+       page = __get_free_page(GFP_KERNEL);\r
+       if (!page)\r
+               return -ENOMEM;\r
+\r
+       uart->xmit.buf = (unsigned char *)page;\r
+       circ_clear(&uart->xmit);\r
+\r
+       //mutex_lock(&port->spi_lock);\r
+\r
+       /*\r
+        * Clear the FIFO buffers and disable them.\r
+        * (they will be reenabled in spi_change_speed())\r
+        */\r
+       spi_out(port, UART_FCR, UART_FCR_ENABLE_FIFO, SEL_UART);\r
+       spi_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |\r
+                       UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, SEL_UART);\r
+       spi_out(port, UART_FCR, 0, SEL_UART);\r
+\r
+       /*\r
+        * Clear the interrupt registers.\r
+        */\r
+       (void) spi_in(port, UART_LSR, SEL_UART);//\r
+       (void) spi_in(port, UART_RX, SEL_UART);//\r
+       (void) spi_in(port, UART_IIR, SEL_UART);//\r
+       (void) spi_in(port, UART_MSR, SEL_UART);//\r
+\r
+       /*\r
+        * Now, initialize the UART\r
+        */\r
+       spi_out(port, UART_LCR, UART_LCR_WLEN8, SEL_UART);\r
+\r
+       uart->ier = UART_IER_RLSI | UART_IER_RDI;\r
+       //uart->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;\r
+       uart->mctrl = TIOCM_OUT2;\r
+\r
+       spi_uart_change_speed(uart, uart->tty->termios, NULL);\r
+\r
+       if (uart->tty->termios->c_cflag & CBAUD)\r
+               spi_uart_set_mctrl(uart, TIOCM_RTS | TIOCM_DTR);\r
+\r
+       if (uart->tty->termios->c_cflag & CRTSCTS)\r
+               if (!(spi_uart_get_mctrl(uart) & TIOCM_CTS))\r
+                       uart->tty->hw_stopped = 1;\r
+\r
+       clear_bit(TTY_IO_ERROR, &uart->tty->flags);\r
+       DBG("Enter::%s,LINE=%d,uart->ier=0x%x\n",__FUNCTION__,__LINE__,uart->ier);\r
+       /* Kick the IRQ handler once while we're still holding the host lock */\r
+       //spi_uart_handle_irq(port->spi);\r
+       //mutex_unlock(&port->spi_lock);\r
+       return 0;\r
+\r
+//err1:\r
+       //free_page((unsigned long)uart->xmit.buf);\r
+       //return ret;\r
+}\r
+\r
+static void spi_uart_shutdown(struct spi_uart *uart)\r
+{\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       //mutex_lock(&port->spi_lock);\r
+       spi_uart_stop_rx(uart);\r
+\r
+       /* TODO: wait here for TX FIFO to drain */\r
+\r
+       /* Turn off DTR and RTS early. */\r
+       if (uart->tty->termios->c_cflag & HUPCL)\r
+               spi_uart_clear_mctrl(uart, TIOCM_DTR | TIOCM_RTS);\r
+\r
+        /* Disable interrupts from this port */\r
+\r
+       uart->ier = 0;\r
+       spi_out(port, UART_IER, 0, SEL_UART);\r
+\r
+       spi_uart_clear_mctrl(uart, TIOCM_OUT2);\r
+\r
+       /* Disable break condition and FIFOs. */\r
+       uart->lcr &= ~UART_LCR_SBC;\r
+       spi_out(port, UART_LCR, uart->lcr, SEL_UART);\r
+       spi_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |\r
+                                UART_FCR_CLEAR_RCVR |\r
+                                UART_FCR_CLEAR_XMIT, SEL_UART);\r
+       spi_out(port, UART_FCR, 0, SEL_UART);\r
+\r
+       //mutex_unlock(&port->spi_lock);\r
+\r
+//skip:\r
+       /* Free the transmit buffer page. */\r
+       free_page((unsigned long)uart->xmit.buf);\r
+}\r
+\r
+static int spi_uart_open (struct tty_struct *tty, struct file * filp)\r
+{\r
+       struct spi_uart *uart;\r
+       int ret;\r
+       \r
+       uart = spi_uart_port_get(tty->index);\r
+       if (!uart)\r
+       {\r
+               DBG("Enter::%s,LINE=%d,!port\n",__FUNCTION__,__LINE__);\r
+               return -ENODEV;\r
+       }\r
+       DBG("Enter::%s,LINE=%d,tty->index=%d\n",__FUNCTION__,__LINE__,tty->index);\r
+       mutex_lock(&uart->open_lock);\r
+\r
+       /*\r
+        * Make sure not to mess up with a dead port\r
+        * which has not been closed yet.\r
+        */\r
+       if (tty->driver_data && tty->driver_data != uart) {\r
+               mutex_unlock(&uart->open_lock);\r
+               spi_uart_port_put(uart);\r
+               DBG("Enter::%s,LINE=%d,!= uart\n",__FUNCTION__,__LINE__);\r
+               return -EBUSY;\r
+       }\r
+\r
+       if (!uart->opened) {\r
+               tty->driver_data = uart;\r
+               uart->tty = tty;\r
+               ret = spi_uart_startup(uart);\r
+               if (ret) {\r
+                       tty->driver_data = NULL;\r
+                       uart->tty = NULL;\r
+                       mutex_unlock(&uart->open_lock);\r
+                       spi_uart_port_put(uart);\r
+                       DBG("Enter::%s,LINE=%d,ret=%d\n",__FUNCTION__,__LINE__,ret);\r
+                       return ret;\r
+               }\r
+       }\r
+       uart->opened++;\r
+       DBG("Enter::%s,uart->opened++=%d\n",__FUNCTION__,uart->opened);\r
+       mutex_unlock(&uart->open_lock);\r
+       return 0;\r
+}\r
+\r
+static void spi_uart_close(struct tty_struct *tty, struct file * filp)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       printk("Enter::%s,LINE=%d,tty->hw_stopped=%d\n",__FUNCTION__,__LINE__,tty->hw_stopped);\r
+       if (!uart)\r
+               return;\r
+\r
+       mutex_lock(&uart->open_lock);\r
+       BUG_ON(!uart->opened);\r
+\r
+       /*\r
+        * This is messy.  The tty layer calls us even when open()\r
+        * returned an error.  Ignore this close request if tty->count\r
+        * is larger than uart->count.\r
+        */\r
+       if (tty->count > uart->opened) {\r
+               mutex_unlock(&uart->open_lock);\r
+               return;\r
+       }\r
+\r
+       if (--uart->opened == 0) {\r
+               DBG("Enter::%s,opened=%d\n",__FUNCTION__,uart->opened);\r
+               tty->closing = 1;\r
+               spi_uart_shutdown(uart);\r
+               tty_ldisc_flush(tty);\r
+               uart->tty = NULL;\r
+               tty->driver_data = NULL;\r
+               tty->closing = 0;\r
+       }\r
+       spi_uart_port_put(uart);\r
+       mutex_unlock(&uart->open_lock);\r
+\r
+}\r
+\r
+static int spi_uart_write(struct tty_struct * tty, const unsigned char *buf,\r
+                          int count)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       struct circ_buf *circ = &uart->xmit;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       int c, ret = 0;\r
+\r
+       if (!port->spi)\r
+       {\r
+               printk("spi error!!!!\n");\r
+               return -ENODEV;\r
+       }\r
+\r
+       \r
+       DBG("spi_uart_write 1 circ->head=%d,circ->tail=%d\n",circ->head,circ->tail);\r
+\r
+       spin_lock(&uart->write_lock);\r
+       while (1) {\r
+               c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);\r
+               if (count < c)\r
+                       c = count;\r
+               if (c <= 0)\r
+                       break;\r
+               memcpy(circ->buf + circ->head, buf, c);\r
+               circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);\r
+               buf += c;\r
+               count -= c;\r
+               ret += c;\r
+       }\r
+       spin_unlock(&uart->write_lock);\r
+       \r
+#if 1\r
+       if ( !(uart->ier & UART_IER_THRI)) {\r
+               //mutex_lock(&port->spi_lock);\r
+                       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+                       /*Note:ICE65L08 output a 'Transmitter holding register interrupt' after 1us*/\r
+                       //printk("s,");\r
+                       spi_uart_start_tx(uart);\r
+                       spi_uart_handle_irq(port->spi);\r
+               //mutex_unlock(&port->spi_lock);        \r
+       }       \r
+#endif \r
+\r
+       //printk("w%d\n",ret);\r
+       return ret;\r
+}\r
+\r
+static int spi_uart_write_room(struct tty_struct *tty)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       DBG("Enter::%s,LINE=%d\n",__FUNCTION__,__LINE__);\r
+       return uart ? circ_chars_free(&uart->xmit) : 0;\r
+}\r
+\r
+static int spi_uart_chars_in_buffer(struct tty_struct *tty)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       printk("Enter::%s,LINE=%d,circ=%ld****\n",__FUNCTION__,__LINE__,circ_chars_pending(&uart->xmit));       \r
+       return uart ? circ_chars_pending(&uart->xmit) : 0;\r
+}\r
+\r
+static void spi_uart_send_xchar(struct tty_struct *tty, char ch)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       printk("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       uart->x_char = ch;\r
+       if (ch && !(uart->ier & UART_IER_THRI)) {\r
+               //mutex_lock(&port->spi_lock);\r
+               spi_uart_start_tx(uart);\r
+               printk("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+               spi_uart_handle_irq(port->spi);\r
+               //mutex_unlock(&port->spi_lock);                \r
+       }\r
+}\r
+\r
+static void spi_uart_throttle(struct tty_struct *tty)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       printk("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))\r
+               return;\r
+       printk("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       //mutex_lock(&port->spi_lock);\r
+       if (I_IXOFF(tty)) {\r
+               uart->x_char = STOP_CHAR(tty);\r
+               spi_uart_start_tx(uart);\r
+               DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+       }\r
+\r
+       if (tty->termios->c_cflag & CRTSCTS)\r
+               spi_uart_clear_mctrl(uart, TIOCM_RTS);\r
+\r
+       spi_uart_handle_irq(port->spi);\r
+       //mutex_unlock(&port->spi_lock);\r
+}\r
+\r
+static void spi_uart_unthrottle(struct tty_struct *tty)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart);\r
+       printk("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))\r
+               return;\r
+       //mutex_lock(&port->spi_lock);\r
+       if (I_IXOFF(tty)) {\r
+               if (uart->x_char) {\r
+                       uart->x_char = 0;\r
+               } else {\r
+                       uart->x_char = START_CHAR(tty);\r
+                       spi_uart_start_tx(uart);\r
+                       DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+               }\r
+       }\r
+\r
+       if (tty->termios->c_cflag & CRTSCTS)\r
+               spi_uart_set_mctrl(uart, TIOCM_RTS);\r
+\r
+       spi_uart_handle_irq(port->spi);\r
+       //mutex_unlock(&port->spi_lock);\r
+}\r
+\r
+static void spi_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       unsigned int cflag = tty->termios->c_cflag;\r
+       unsigned int mask = TIOCM_DTR;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       \r
+#define RELEVANT_IFLAG(iflag)   ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))\r
+\r
+       if ((cflag ^ old_termios->c_cflag) == 0 &&\r
+           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)\r
+               return;\r
+\r
+       //mutex_lock(&port->spi_lock);\r
+       spi_uart_change_speed(uart, tty->termios, old_termios);\r
+\r
+       /* Handle transition to B0 status */\r
+       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)){\r
+               DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+               spi_uart_clear_mctrl(uart, TIOCM_RTS | TIOCM_DTR);\r
+               //spi_uart_clear_mctrl(uart, TIOCM_RTS);\r
+               }\r
+       \r
+       /* Handle transition away from B0 status */\r
+       if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {\r
+               DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+               if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))\r
+                       mask |= TIOCM_RTS;\r
+               spi_uart_set_mctrl(uart, mask);\r
+       }\r
+\r
+       /* Handle turning off CRTSCTS */\r
+       if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {\r
+               DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+               tty->hw_stopped = 0;\r
+               spi_uart_start_tx(uart);\r
+               DBG("Enter::%s,UART_IER=0x%x\n",__FUNCTION__,uart->ier);\r
+       }\r
+\r
+       /* Handle turning on CRTSCTS */\r
+       if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {\r
+               DBG("Enter::%s,LINE=%d,status=0x%x,Handle turning on CRTSCTS*****************\n",__FUNCTION__,__LINE__,spi_uart_get_mctrl(uart));\r
+               //spi_uart_set_mctrl(uart, TIOCM_RTS);\r
+               if (!(spi_uart_get_mctrl(uart) & TIOCM_CTS)) {\r
+                       DBG("Enter::%s,LINE=%d,tty->hw_stopped = 1********\n",__FUNCTION__,__LINE__);\r
+                       tty->hw_stopped = 1;\r
+                       spi_uart_stop_tx(uart);\r
+               }\r
+       }\r
+       //mutex_unlock(&port->spi_lock);\r
+\r
+}\r
+\r
+static int spi_uart_break_ctl(struct tty_struct *tty, int break_state)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       struct spi_fpga_port *port = container_of(uart, struct spi_fpga_port, uart); \r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       //mutex_lock(&port->spi_lock);\r
+       if (break_state == -1)\r
+               uart->lcr |= UART_LCR_SBC;\r
+       else\r
+               uart->lcr &= ~UART_LCR_SBC;\r
+       spi_out(port, UART_LCR, uart->lcr, SEL_UART);\r
+       //mutex_unlock(&port->spi_lock);\r
+       return 0;\r
+}\r
+\r
+static int spi_uart_tiocmget(struct tty_struct *tty, struct file *file)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       int result;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       //mutex_lock(&port->spi_lock);\r
+       result = uart->mctrl | spi_uart_get_mctrl(uart);\r
+       //mutex_unlock(&port->spi_lock);\r
+       return result;\r
+}\r
+\r
+static int spi_uart_tiocmset(struct tty_struct *tty, struct file *file,\r
+                             unsigned int set, unsigned int clear)\r
+{\r
+       struct spi_uart *uart = tty->driver_data;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       //mutex_lock(&port->spi_lock);\r
+       spi_uart_update_mctrl(uart, set, clear);\r
+       //mutex_unlock(&port->spi_lock);\r
+\r
+       return 0;\r
+}\r
+\r
+#if 0\r
+static int spi_uart_read_proc(char *page, char **start, off_t off,\r
+                              int count, int *eof, void *data)\r
+{\r
+       int i, len = 0;\r
+       off_t begin = 0;\r
+       DBG("Enter::%s,LINE=%d************************\n",__FUNCTION__,__LINE__);\r
+       len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",\r
+                      "", "", "");\r
+       for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {\r
+               struct spi_uart *uart = spi_uart_port_get(i);\r
+               if (uart) {\r
+                       len += sprintf(page+len, "%d: uart:SPI", i);\r
+                       if(capable(CAP_SYS_ADMIN)) {\r
+                               len += sprintf(page + len, " tx:%d rx:%d",\r
+                                              uart->icount.tx, uart->icount.rx);\r
+                               if (uart->icount.frame)\r
+                                       len += sprintf(page + len, " fe:%d",\r
+                                                      uart->icount.frame);\r
+                               if (uart->icount.parity)\r
+                                       len += sprintf(page + len, " pe:%d",\r
+                                                      uart->icount.parity);\r
+                               if (uart->icount.brk)\r
+                                       len += sprintf(page + len, " brk:%d",\r
+                                                      uart->icount.brk);\r
+                               if (uart->icount.overrun)\r
+                                       len += sprintf(page + len, " oe:%d",\r
+                                                      uart->icount.overrun);\r
+                               if (uart->icount.cts)\r
+                                       len += sprintf(page + len, " cts:%d",\r
+                                                      uart->icount.cts);\r
+                               if (uart->icount.dsr)\r
+                                       len += sprintf(page + len, " dsr:%d",\r
+                                                      uart->icount.dsr);\r
+                               if (uart->icount.rng)\r
+                                       len += sprintf(page + len, " rng:%d",\r
+                                                      uart->icount.rng);\r
+                               if (uart->icount.dcd)\r
+                                       len += sprintf(page + len, " dcd:%d",\r
+                                                      uart->icount.dcd);\r
+                       }\r
+                       strcat(page, "\n");\r
+                       len++;\r
+                       spi_uart_port_put(uart);\r
+               }\r
+\r
+               if (len + begin > off + count)\r
+                       goto done;\r
+               if (len + begin < off) {\r
+                       begin += len;\r
+                       len = 0;\r
+               }\r
+       }\r
+       *eof = 1;\r
+\r
+done:\r
+       if (off >= len + begin)\r
+               return 0;\r
+       *start = page + (off - begin);\r
+       return (count < begin + len - off) ? count : (begin + len - off);\r
+}\r
+#endif\r
+\r
+static const struct tty_operations spi_uart_ops = {\r
+       .open                   = spi_uart_open,\r
+       .close                  = spi_uart_close,\r
+       .write                  = spi_uart_write,\r
+       .write_room             = spi_uart_write_room,\r
+       .chars_in_buffer        = spi_uart_chars_in_buffer,\r
+       .send_xchar             = spi_uart_send_xchar,\r
+       .throttle               = spi_uart_throttle,\r
+       .unthrottle             = spi_uart_unthrottle,\r
+       .set_termios            = spi_uart_set_termios,\r
+       .break_ctl              = spi_uart_break_ctl,\r
+       .tiocmget               = spi_uart_tiocmget,\r
+       .tiocmset               = spi_uart_tiocmset,\r
+       //.read_proc            = spi_uart_read_proc,\r
+};\r
+\r
+\r
+static struct tty_driver *spi_uart_tty_driver;\r
+\r
+int spi_uart_register(struct spi_fpga_port *port)\r
+{\r
+       int i,ret;\r
+       struct tty_driver *tty_drv;\r
+       spi_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);\r
+       if (!tty_drv)\r
+               return -ENOMEM;\r
+       tty_drv->owner = THIS_MODULE;\r
+       tty_drv->driver_name = "spi_uart";\r
+       tty_drv->name =   "ttySPI";\r
+       tty_drv->major = 0;  /* dynamically allocated */\r
+       tty_drv->minor_start = 0;\r
+       //tty_drv->num = UART_NR;\r
+       tty_drv->type = TTY_DRIVER_TYPE_SERIAL;\r
+       tty_drv->subtype = SERIAL_TYPE_NORMAL;\r
+       tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;\r
+       tty_drv->init_termios = tty_std_termios;\r
+       tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;\r
+       tty_drv->init_termios.c_ispeed = 115200;\r
+       tty_drv->init_termios.c_ospeed = 115200;\r
+       tty_set_operations(tty_drv, &spi_uart_ops);\r
+\r
+       ret = tty_register_driver(tty_drv);\r
+       if (ret)\r
+       goto err1;\r
+\r
+       //port->uart.uartclk = 64*115200;       //MCLK/4\r
+       port->uart.uartclk = 60*100000; //MCLK/4\r
+\r
+       for(i=0; i<UART_NR; i++)\r
+       {\r
+               ret = spi_uart_add_port(&port->uart);\r
+               if (ret) {\r
+                       goto err2;\r
+               } else {\r
+                       struct device *dev;\r
+                       dev = tty_register_device(spi_uart_tty_driver, port->uart.index, &port->spi->dev);\r
+                       if (IS_ERR(dev)) {\r
+                               spi_uart_port_remove(&port->uart);\r
+                               ret = PTR_ERR(dev);\r
+                               goto err2;\r
+                       }\r
+               }\r
+       }\r
+\r
+#if SPI_UART_TEST\r
+       char b[20];\r
+       sprintf(b, "spi_uart_workqueue");\r
+       port->uart.spi_uart_workqueue = create_freezeable_workqueue(b);\r
+       if (!port->uart.spi_uart_workqueue) {\r
+               printk("cannot create workqueue\n");\r
+               return -EBUSY;\r
+       }\r
+       INIT_WORK(&port->uart.spi_uart_work, spi_uart_work_handler);\r
+\r
+       setup_timer(&port->uart.uart_timer, spi_testuart_timer, (unsigned long)port);\r
+       port->uart.uart_timer.expires  = jiffies+2000;\r
+       add_timer(&port->uart.uart_timer);\r
+\r
+#endif\r
+\r
+\r
+       return 0;\r
+\r
+err2:\r
+       tty_unregister_driver(tty_drv);\r
+err1:\r
+       put_tty_driver(tty_drv);\r
+       \r
+       return ret;\r
+       \r
+       \r
+}\r
+int spi_uart_unregister(struct spi_fpga_port *port)\r
+{\r
+\r
+       return 0;\r
+}\r
+\r
+MODULE_DESCRIPTION("Driver for spi2uart.");\r
+MODULE_AUTHOR("luowei <lw@rock-chips.com>");\r
+MODULE_LICENSE("GPL");\r
index 12aa6e625ea5cba281b1491cdd3501aca2f5a326..a31b2ee471030ffb9313cd6c2d68536fe0119d74 100644 (file)
@@ -512,6 +512,8 @@ struct i2c_msg {
        __u16 len;              /* msg length                           */
        __u8 *buf;              /* pointer to msg data                  */
        __u32 scl_rate;
+       __u16 channel;
+       __u16 read_type;
 };
 
 /* To determine what functionality is present */