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