summaryrefslogtreecommitdiff
path: root/drivers/misc/sdiodev
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/sdiodev')
-rw-r--r--drivers/misc/sdiodev/Kconfig23
-rw-r--r--drivers/misc/sdiodev/Makefile20
-rw-r--r--drivers/misc/sdiodev/sdio_dev.c1734
-rwxr-xr-xdrivers/misc/sdiodev/sdio_dev.h207
-rw-r--r--drivers/misc/sdiodev/sdio_dev_test.c1219
-rw-r--r--drivers/misc/sdiodev/sdio_dev_test.h47
6 files changed, 3250 insertions, 0 deletions
diff --git a/drivers/misc/sdiodev/Kconfig b/drivers/misc/sdiodev/Kconfig
new file mode 100644
index 00000000..caf7eddb
--- /dev/null
+++ b/drivers/misc/sdiodev/Kconfig
@@ -0,0 +1,23 @@
+
+menu "SDIODEV modules"
+
+config SDIODEV
+ tristate "SPRD SDIO DEV SUPPORT"
+ ---help---
+ PLEASE INSMOD THIS MODULE BEFORE OTHER SDIO DEV MODULES
+
+config SDIODEV_TEST
+ bool "SDIO DEV TEST"
+ default n
+ depends on SDIODEV
+ help
+ FOR RUN SDIODEV TEST CASE,DO NOT OPEN IT IN NORMAL MODE
+
+config WCN_EXTENSION
+ bool "WCN EXTENSION"
+ default n
+ depends on SDIODEV
+ help
+ FOR SUPPORTING MARLIN SS BRANCH
+
+endmenu
diff --git a/drivers/misc/sdiodev/Makefile b/drivers/misc/sdiodev/Makefile
new file mode 100644
index 00000000..3aa092ef
--- /dev/null
+++ b/drivers/misc/sdiodev/Makefile
@@ -0,0 +1,20 @@
+#sdiodevhal
+obj-$(CONFIG_SDIODEV) := sdiodevhal.o
+
+sdiodevhal-c-objs += sdio_dev.o
+
+ifeq ($(CONFIG_SDIODEV_TEST),y)
+ccflags-y += -DSDIO_TEST_CASE6
+#SDIO_TEST_CASE1
+#SDIO_TEST_CASE2
+#SDIO_TEST_CASE4
+#SDIO_TEST_CASE5
+#SDIO_TEST_CASE6
+#SDIO_TEST_CASE7
+#SDIO_TEST_CASE8
+#SDIO_TEST_CASE9
+sdiodevhal-c-objs += sdio_dev_test.o
+endif
+
+sdiodevhal-objs += $(sdiodevhal-c-objs)
+
diff --git a/drivers/misc/sdiodev/sdio_dev.c b/drivers/misc/sdiodev/sdio_dev.c
new file mode 100644
index 00000000..b79a2bdf
--- /dev/null
+++ b/drivers/misc/sdiodev/sdio_dev.c
@@ -0,0 +1,1734 @@
+/*
+ * Copyright (C) 2013 Spreadtrum Communications Inc.
+ *
+ * Filename : sdio_dev.c
+ * Abstract : This file is a implementation for itm sipc command/event function
+ *
+ * Authors : gaole.zhang
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "sdio_dev.h"
+
+#if defined(CONFIG_SDIODEV_TEST)
+
+#include "sdio_dev_test.h"
+
+#endif
+
+static struct mutex g_sdio_func_lock;
+static struct timeval ack_irq_time = {0};
+static int ack_gpio_status = 0;
+
+static int marlin_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id);
+static void marlin_sdio_remove(struct sdio_func *func);
+static int marlin_sdio_suspend(struct device *dev);
+static int marlin_sdio_resume(struct device *dev);
+
+extern void set_bt_pm_func(void *wakeup,void *sleep);
+
+struct sdio_func *sprd_sdio_func[SDIODEV_MAX_FUNCS];
+struct sdio_func sdio_func_0;
+SDIO_CHN_HANDLER sdio_tran_handle[17] = {0};
+
+static struct sdio_data *sdio_data=NULL;
+static int sdio_irq_num;
+static int marlinwake_irq_num;
+
+static int marlin_sdio_ready_irq_num;
+
+
+static struct wake_lock marlin_wakelock;
+static struct wake_lock BT_AP_wakelock;
+
+static struct wake_lock marlinpub_wakelock;
+
+
+static struct work_struct marlin_wq;
+static struct work_struct marlinwake_wq;
+
+static bool ap_sdio_ready = 0;
+static bool have_card = 0;
+static MARLIN_SDIO_READY_T marlin_sdio_ready = {0};
+
+
+
+static const struct sdio_device_id marlin_sdio_ids[] = {
+ {SDIO_DEVICE(MARLIN_VENDOR_ID, MARLIN_DEVICE_ID)},
+ {},
+};
+
+static const struct dev_pm_ops marlin_sdio_pm_ops = {
+ .suspend = marlin_sdio_suspend,
+ .resume = marlin_sdio_resume,
+};
+
+static struct sdio_driver marlin_sdio_driver = {
+ .probe = marlin_sdio_probe,
+ .remove = marlin_sdio_remove,
+ .name = "marlin_sdio",
+ .id_table = marlin_sdio_ids,
+ .drv = {
+ .pm = &marlin_sdio_pm_ops,
+ },
+};
+
+static struct mmc_host *sdio_dev_host = NULL;
+char *sync_data_ptr = NULL;
+static int gpio_marlin_req_tag = 0;
+static int gpio_marlinwake_tag = 0;
+
+static bool sdio_w_flag = 0;
+//static bool req_marlin_wait_tag = 0; //0: don't wait 1: wait
+//atomic_t req_marlin_wait_tag;
+atomic_t gpioreq_need_pulldown;
+static bool bt_wake_flag = 0;
+
+static bool marlin_bt_wake_flag = 0;
+
+
+static struct completion marlin_ack = {0};
+
+static SLEEP_POLICY_T sleep_para = {0};
+spinlock_t sleep_spinlock ;
+MARLIN_PM_RESUME_WAIT_INIT(marlin_sdio_wait);
+
+/************************************************************************/
+typedef struct
+{
+ struct mutex func_lock;
+ struct early_suspend early_suspend;
+ atomic_t in_early_suspend;
+ atomic_t refcnt;
+}mgr_suspend_t;
+
+#define SDIO_OS_LOCK() do{\
+ if(1 == atomic_read(&g_mgr_suspend.in_early_suspend)) \
+ {\
+ mutex_lock(&(g_mgr_suspend.func_lock));\
+ lock_flag = 1;\
+ }else{\
+ lock_flag = 0;\
+ atomic_inc(&(g_mgr_suspend.refcnt));\
+ }\
+}while(0)
+
+#define SDIO_OS_UNLOCK() do{\
+ if(lock_flag){\
+ mutex_unlock(&(g_mgr_suspend.func_lock));\
+ }else{\
+ atomic_dec(&(g_mgr_suspend.refcnt));}\
+}while(0)
+
+
+mgr_suspend_t g_mgr_suspend = {0};
+
+static void sdio_early_suspend(struct early_suspend *es)
+{
+ unsigned long timeout;
+ SDIOTRAN_ERR("[%s]enter\n", __func__);
+ timeout = jiffies + msecs_to_jiffies(3000);
+ atomic_set(&g_mgr_suspend.in_early_suspend, 1);
+ while(0 != atomic_read(&(g_mgr_suspend.refcnt)) )
+ {
+ usleep_range(50, 100);
+ if (time_after(jiffies, timeout))
+ {
+ SDIOTRAN_ERR("[%s][timeout 3000ms][EEROR]\n", __func__);
+ return;
+ }
+ }
+ SDIOTRAN_ERR("[%s]ok\n", __func__);
+ return;
+}
+
+static void sdio_late_resume(struct early_suspend *es)
+{
+ atomic_set(&g_mgr_suspend.in_early_suspend, 0);
+ SDIOTRAN_ERR("[%s]ok\n", __func__);
+ return;
+}
+
+int mgr_suspend_init(void )
+{
+ int ret;
+ atomic_set(&g_mgr_suspend.refcnt, 0);
+ atomic_set(&g_mgr_suspend.in_early_suspend, 0);
+ mutex_init(&g_mgr_suspend.func_lock);
+ g_mgr_suspend.early_suspend.suspend = sdio_early_suspend;
+ g_mgr_suspend.early_suspend.resume = sdio_late_resume;
+ register_early_suspend(&g_mgr_suspend.early_suspend);
+ return 0;
+}
+
+void mgr_suspend_defint(void )
+{
+ unregister_early_suspend(&g_mgr_suspend.early_suspend);
+ return;
+}
+
+/************************************************************************/
+
+static int get_sdio_dev_func(struct sdio_func *func)
+{
+ if(SDIODEV_MAX_FUNCS <= func->num)
+ {
+ SDIOTRAN_ERR("func num err!!! func num is %d!!!",func->num);
+ return -1;
+ }
+ SDIOTRAN_DEBUG("func num is %d!!!",func->num);
+
+ if (func->num == 1)
+ {
+ sdio_func_0.num = 0;
+ sdio_func_0.card = func->card;
+ sprd_sdio_func[0] = &sdio_func_0;
+ }
+
+ sprd_sdio_func[func->num] = func;
+
+ return 0;
+}
+
+static int free_sdio_dev_func(struct sdio_func *func)
+{
+ if(SDIODEV_MAX_FUNCS <= func->num)
+ {
+ SDIOTRAN_ERR("func num err!!! func num is %d!!!",func->num);
+ return -1;
+ }
+
+ sprd_sdio_func[0] = NULL;
+ sprd_sdio_func[func->num] = NULL;
+ sdio_func_0.num = 0;
+ sdio_func_0.card = NULL;
+
+ return 0;
+
+}
+
+static int wakeup_slave_pin_init(void)
+{
+ int ret;
+ ret = gpio_request(sdio_data->wake_out,"marlin_wakeup");
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("req gpio sdio_data->wake_out = %d fail!!!",\
+ sdio_data->wake_out);
+ return ret;
+ }
+
+ ret = gpio_direction_output(sdio_data->wake_out,0);
+ if (ret)
+ {
+ SDIOTRAN_ERR("sdio_data->wake_out = %d input set fail!!!",\
+ sdio_data->wake_out);
+ return ret;
+ }
+
+ SDIOTRAN_ERR("req sdio_data->wake_out = %d succ!!!",\
+ sdio_data->wake_out);
+
+ return ret;
+}
+void gpio_timer_handler(unsigned long data)
+{
+ if(gpio_get_value(sdio_data->wake_ack))
+ {
+ sleep_para.gpio_opt_tag = 1;
+ mod_timer(&(sleep_para.gpio_timer),\
+ jiffies + msecs_to_jiffies(sleep_para.ack_high_time));// 250<300<2000-1500
+ SDIOTRAN_ERR("ack high");
+ }
+ else
+ {
+ sleep_para.gpio_opt_tag = 0;
+ SDIOTRAN_ERR("gpio_opt_tag=0\n" );
+ }
+}
+
+int fwdownload_fin = 0;
+
+int get_sprd_download_fin(void)
+{
+ return fwdownload_fin;
+}
+EXPORT_SYMBOL_GPL(get_sprd_download_fin);
+
+void set_sprd_download_fin(int dl_tag)
+{
+ marlin_sdio_ready.marlin_sdio_init_end_tag = 1;
+ return fwdownload_fin = dl_tag;
+}
+EXPORT_SYMBOL_GPL(set_sprd_download_fin);
+
+unsigned int irq_count_change = 0;
+unsigned int irq_count_change_last = 0;
+bool get_sprd_marlin_status(void)
+{
+ printk(KERN_INFO "irq_count_change:%d\n",irq_count_change);
+ printk(KERN_INFO "irq_count_change_last:%d\n",irq_count_change_last);
+
+ if((irq_count_change == 0)&&(irq_count_change_last == 0))
+ return 1;
+ else if(irq_count_change != irq_count_change_last)
+ {
+ irq_count_change_last = irq_count_change;
+ return 1;
+ }
+ else
+ return 0;
+}
+EXPORT_SYMBOL_GPL(get_sprd_marlin_status);
+
+atomic_t is_wlan_open; //0: wlan close, 1: wlan open
+atomic_t set_marlin_cmplete; //0: not complete, 1: complete
+int set_wlan_status(int status)
+{
+ atomic_set(&(is_wlan_open), status);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_wlan_status);
+
+/*add start by sam.sun, 20150108, for get the screen status (on or off)
+ return: 1 screen on
+ 0 screen off
+*/
+#define BRIGHTNESS_PATH "/sys/class/backlight/sprd_backlight/brightness"
+int get_screen_status(void)
+{
+ struct file *file = NULL;
+ int is_screen_on = 1;
+ char * buf; //0~255
+ mm_segment_t old_fs;
+ int size =0;
+ loff_t pos = 0;
+
+ file=filp_open(BRIGHTNESS_PATH, O_RDONLY, 0);
+ if (IS_ERR(file))
+ SDIOTRAN_ERR("Open file %s failed /n",BRIGHTNESS_PATH);
+
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+
+ buf = (int *)kzalloc(4,GFP_KERNEL);
+
+ vfs_read(file, buf, 3, &pos);
+
+ size = strlen(buf);
+
+ if( strncmp(buf,"0",(size-1))==0 )
+ is_screen_on = 0; //screen off 224
+ else
+ is_screen_on = 1;
+
+ //SDIOTRAN_ERR("*brightness is %s, is_screen_on is %d\r",buf, is_screen_on);
+ kfree(buf);
+ filp_close(file, NULL);
+ set_fs(old_fs);
+ return is_screen_on;
+}
+/*add end by sam.sun, for get the screen status (on or off)*/
+
+extern bool get_bt_state(void); // 1: bt open , 0: bt close
+int set_marlin_wakeup(uint32 chn,uint32 user_id)
+{
+ //user_id: wifi=0x1;bt=0x2
+#if !defined(CONFIG_MARLIN_NO_SLEEP)
+
+ int ret;
+ int flags;
+ int screen_status = 1;
+ int bt_state ;
+ SDIOTRAN_DEBUG("entry");
+
+ if(get_sprd_download_fin() != 1)
+ {
+ SDIOTRAN_ERR("marlin unready");
+ return -1;
+ }
+
+ /* when bt only, marlin will don't stay 2s wakeup;
+ so add for avoid bt ack 250ms high, then in below cases ap don't req cp and send data directly;
+ case1: first open wlan, then user_id = 1;
+ case2: send AT cmd or loop check, then user_id = 3; mdbg module has done re-try action
+ */
+ if((1 == atomic_read(&(is_wlan_open))) && (1 == user_id) )
+ {
+ if((gpio_get_value(sdio_data->wake_ack)) && (0 == sleep_para.gpio_opt_tag) )
+ msleep(sleep_para.ack_high_time);
+ if(gpio_get_value(sdio_data->wake_ack))
+ SDIOTRAN_ERR("err:bt req delay 300ms\n");
+ atomic_set(&is_wlan_open, 0); // avoid repeat into this func
+ }
+
+ //screen_status = get_screen_status(); // for wifi screen download
+ //bt_state = get_bt_state();
+
+ spin_lock_irqsave(&sleep_spinlock, flags);
+ //if((0 == sleep_para.gpio_opt_tag) ||((!screen_status) && (1 == user_id) && (!bt_state)) )
+ if(0 == sleep_para.gpio_opt_tag)
+ {
+ if(gpio_get_value(sdio_data->wake_ack)) //bt ack 250ms
+ {
+ spin_unlock_irqrestore(&sleep_spinlock, flags);
+ SDIOTRAN_ERR("%d-high,user_id-%d \n", sdio_data->wake_ack,user_id);
+ return -2;
+ }
+ if(0 != ack_gpio_status) //bt ack low,then lose the marlinwake irq
+ {
+ spin_unlock_irqrestore(&sleep_spinlock, flags);
+ SDIOTRAN_ERR("ack_gpio_status-%d\n", ack_gpio_status);
+ return -2;
+ }
+ if(0 == atomic_read(&(set_marlin_cmplete))) //last wakeup don't complete
+ {
+ spin_unlock_irqrestore(&sleep_spinlock, flags);
+ SDIOTRAN_ERR("set_marlin_complete -%d\n", set_marlin_cmplete);
+ return -3;
+ }
+
+ atomic_set(&(set_marlin_cmplete), 0); //invoid re-entry this func.
+ if((0x1 == user_id) ||(0x3 == user_id))
+ {
+ sdio_w_flag = 1;
+ }
+
+ if(0x2 == user_id)
+ {
+ bt_wake_flag = 1;
+ }
+ atomic_set(&gpioreq_need_pulldown, 1);//sleep_para.gpioreq_need_pulldown = 1;
+
+ gpio_direction_output(sdio_data->wake_out,1);
+ spin_unlock_irqrestore(&sleep_spinlock, flags);
+
+ SDIOTRAN_ERR("%d-1\n", sdio_data->wake_out );
+
+ if((0x1 == user_id) ||(0x3 == user_id))
+ {
+ ret = wait_for_completion_timeout( &marlin_ack, msecs_to_jiffies(100) );
+ if (ret == 0){
+ atomic_set(&(set_marlin_cmplete), 1);
+ SDIOTRAN_ERR("marlin chn %d ack timeout, user_id-%d!!!",chn, user_id);
+ return -ETIMEDOUT;//timeout
+ }
+ }
+ }
+ else
+ {
+ spin_unlock_irqrestore(&sleep_spinlock, flags);
+ }
+
+ atomic_set(&(set_marlin_cmplete), 1);
+#endif
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_marlin_wakeup);
+
+
+int set_marlin_sleep(uint32 chn,uint32 user_id)
+{
+ //user_id: wifi=0x1;bt=0x2
+#if !defined(CONFIG_MARLIN_NO_SLEEP)
+ SDIOTRAN_DEBUG("entry");
+ if( atomic_read(&gpioreq_need_pulldown) )//if(sleep_para.gpioreq_need_pulldown)
+ {
+ gpio_direction_output(sdio_data->wake_out,0);
+ if((user_id == 0x1) ||(user_id == 0x3))
+ {
+ sdio_w_flag = 0;
+ }
+ if(user_id == 0x2)
+ {
+ bt_wake_flag = 0;
+ }
+ atomic_set(&gpioreq_need_pulldown, 0);//sleep_para.gpioreq_need_pulldown = 0;
+ SDIOTRAN_ERR("gpio%d-0,user_id-%d\n", sdio_data->wake_out, user_id);
+ }
+#endif
+ return 0;
+}
+EXPORT_SYMBOL_GPL(set_marlin_sleep);
+
+
+/*only idle chn can be used for ap write*/
+int sdio_dev_chn_idle(uint32 chn)
+{
+ uint32 active_status;
+ uint8 status0,status1;
+ int err_ret;
+
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_0])
+ {
+ SDIOTRAN_ERR("func uninit!!!");
+ return -1;
+ }
+
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ status0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x840,&err_ret);
+
+ status1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ active_status = (uint32)(status0) + ((uint32)(status1) << 8);
+
+ if( BIT_0 & ( active_status >> chn )){
+ SDIOTRAN_DEBUG("SDIO channel num = %x is active!!",chn);
+ return 0; //active
+ }
+ else{
+ SDIOTRAN_DEBUG("SDIO channel num = %x is idle!!",chn);
+ return 1; //idle
+ }
+}
+EXPORT_SYMBOL_GPL(sdio_dev_chn_idle);
+
+#if defined(CONFIG_SDIODEV_TEST)
+
+/*only active chn can be readed*/
+int sdio_dev_get_read_chn(void)
+{
+ uint8 rw_flag0,rw_flag1;
+ uint8 status0,status1;
+ uint32 chn_status;
+ uint32 chn_rw_flag;
+ uint32 tmp;
+ int err_ret,read_chn;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ status0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x840,&err_ret);
+
+ status1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+
+ rw_flag0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x842,&err_ret);
+
+ rw_flag1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x843,&err_ret);
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ chn_status = (uint32)(status0) + ((uint32)(status1) << 8);
+ chn_rw_flag = (uint32)(rw_flag0) + ((uint32)(rw_flag1) << 8);
+
+ SDIOTRAN_DEBUG("ap recv: chn_status is 0x%x!!!",chn_status);
+ SDIOTRAN_DEBUG("ap read: chn_rw_flag is 0x%x!!!",chn_rw_flag);
+
+ tmp = (chn_status&(~chn_rw_flag))&(0x0000ffff);
+
+ for(read_chn=0;read_chn<16;read_chn++)
+ {
+ if(BIT_0 & (tmp>>read_chn))
+ {
+ return read_chn;
+ }
+ }
+ return -1;
+
+}
+
+
+
+#else
+
+int sdio_dev_get_read_chn(void)
+{
+ uint8 chn_status;
+ int err_ret;
+ int lock_flag;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+ SDIO_OS_LOCK();//mutex_lock(&g_sdio_func_lock);
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ chn_status = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+
+ while( chn_status == 0 ){
+ chn_status = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+ }
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+ SDIO_OS_UNLOCK();//mutex_unlock(&g_sdio_func_lock);
+ SDIOTRAN_DEBUG("ap read: chn_status is 0x%x!!!",chn_status);
+
+ if(chn_status == 0xff)
+ {
+ SDIOTRAN_ERR("Sdio Err!!!chn status 0x%x!!!",chn_status);
+ return -1;
+ }
+ else if(chn_status & SDIO_CHN_8)
+ return 8;
+ else if(chn_status & SDIO_CHN_9)
+ return 9;
+ else if(chn_status & SDIO_CHN_11)
+ return 11;
+ else if(chn_status & SDIO_CHN_12)
+ return 12;
+ else if(chn_status & SDIO_CHN_13)
+ return 13;
+ else if(chn_status & SDIO_CHN_14)
+ return 14;
+ else if(chn_status & SDIO_CHN_15)
+ return 15;
+ else
+ {
+ SDIOTRAN_ERR("Invalid sdio read chn!!!chn status 0x%x!!!",chn_status);
+ return -1;
+ }
+}
+
+#endif
+EXPORT_SYMBOL_GPL(sdio_dev_get_read_chn);
+
+
+/*ONLY WIFI WILL USE THIS FUNC*/
+int sdio_chn_status(unsigned short chn, unsigned short *status)
+{
+ unsigned char status0 = 0;
+ unsigned char status1 = 0;
+ int err_ret;
+ int ret = 0;
+ int lock_flag;
+ SDIOTRAN_DEBUG("ENTRY");
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_0])
+ {
+ SDIOTRAN_ERR("func err");
+ return -1;
+ }
+ SDIO_OS_LOCK();//mutex_lock(&g_sdio_func_lock);
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ if (0x00FF & chn) {
+ status0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x840,&err_ret);
+ if (status0 == 0xFF){
+ SDIOTRAN_ERR("sdio chn reg0 err");
+ ret = -1;
+ }
+ }
+
+ if (0xFF00 & chn) {
+ status1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+ if (status1 == 0xFF){
+ SDIOTRAN_ERR("sdio chn reg1 err");
+ ret = -1;
+ }
+ }
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+ SDIO_OS_UNLOCK();//mutex_unlock(&g_sdio_func_lock);
+ *status = ( (status0+(status1 << 8)) & chn );
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_chn_status);
+
+int sdio_dev_get_chn_datalen(uint32 chn)
+{
+ uint32 usedata;
+ uint8 status0,status1,status2;
+ int err_ret;
+ int lock_flag;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_0])
+ {
+ SDIOTRAN_ERR("func uninit!!!");
+ return -1;
+ }
+ SDIO_OS_LOCK();//mutex_lock(&g_sdio_func_lock);
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ status0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],(0x800+ 4*chn),&err_ret);
+
+ status1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],(0x801+ 4*chn),&err_ret);
+
+ status2 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],(0x802+ 4*chn),&err_ret);
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+ SDIO_OS_UNLOCK();//mutex_unlock(&g_sdio_func_lock);
+ usedata = ((uint32)(status0) ) + ((uint32)(status1) << 8) + ((uint32)(status2) << 16);
+
+ if(status0 == 0xff || status1 == 0xff || status2 == 0xff)
+ {
+ SDIOTRAN_ERR("read err!!!");
+ return -1;
+ }
+
+ return usedata;
+
+}
+EXPORT_SYMBOL_GPL(sdio_dev_get_chn_datalen);
+
+
+int sdio_dev_write(uint32 chn,void* data_buf,uint32 count)
+{
+ int ret,data_len;
+ int lock_flag;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_1])
+ {
+ SDIOTRAN_ERR("func uninit!!!");
+ return -1;
+ }
+
+ if(chn != 0 && chn != 1)
+ {
+ data_len = sdio_dev_get_chn_datalen(chn);
+ if(data_len < count || data_len <= 0)
+ {
+ SDIOTRAN_ERR("chn %d, len %d, cnt %d, err!!!",chn,data_len,count);
+ return -1;
+ }
+ }
+ SDIO_OS_LOCK();//mutex_lock(&g_sdio_func_lock);
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+
+ ret = sdio_memcpy_toio(sprd_sdio_func[SDIODEV_FUNC_1],chn,data_buf,count);
+ SDIOTRAN_DEBUG("chn %d send ok!!!",chn);
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+ SDIO_OS_UNLOCK();//mutex_unlock(&g_sdio_func_lock);
+ return ret;
+
+}
+EXPORT_SYMBOL_GPL(sdio_dev_write);
+
+
+int sdio_dev_read(uint32 chn,void* read_buf,uint32 *count)
+{
+ int err_ret,data_len;
+ int lock_flag;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_1])
+ {
+ SDIOTRAN_ERR("func uninit!!!");
+ return -1;
+ }
+
+ data_len = sdio_dev_get_chn_datalen(chn);
+ if(data_len <= 0)
+ {
+ SDIOTRAN_ERR("chn %d,datelen %d err!!!",chn,data_len);
+ return -1;
+ }
+ SDIOTRAN_DEBUG("ap recv chn %d: read_datalen is 0x%x!!!",chn,data_len);
+
+ SDIO_OS_LOCK();//mutex_lock(&g_sdio_func_lock);
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+ err_ret = sdio_memcpy_fromio(sprd_sdio_func[SDIODEV_FUNC_1],read_buf,chn,data_len);
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+ SDIO_OS_UNLOCK();//mutex_unlock(&g_sdio_func_lock);
+ if(NULL != count)
+ *count = data_len;
+
+ return err_ret;
+
+}
+
+EXPORT_SYMBOL_GPL(sdio_dev_read);
+
+int sdio_read_wlan(uint32 chn,void* read_buf,uint32 *count)
+{
+ int err_ret,data_len;
+ data_len = 16384;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+ if(NULL == sprd_sdio_func[SDIODEV_FUNC_1])
+ {
+ SDIOTRAN_ERR("func uninit!!!");
+ return -1;
+ }
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+ err_ret = sdio_memcpy_fromio(sprd_sdio_func[SDIODEV_FUNC_1],read_buf,chn,data_len);
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_1]);
+ if(NULL != count)
+ *count = data_len;
+ return err_ret;
+
+}
+
+EXPORT_SYMBOL_GPL(sdio_read_wlan);
+
+int sdiodev_readchn_init(uint32 chn,void* callback,bool with_para)
+{
+ SDIOTRAN_DEBUG("Param, chn = %d, callback = %p",chn,callback);
+ if(chn >= INVALID_SDIO_CHN)
+ {
+ SDIOTRAN_ERR("err input chn %d",chn);
+ return -1;
+ }
+ sdio_tran_handle[chn].chn = chn;
+
+ if(with_para == 1)
+ {
+ sdio_tran_handle[chn].tran_callback_para = callback;
+ SDIOTRAN_DEBUG("sdio_tran_handle, chn = %d, callback = %p",sdio_tran_handle[chn].chn,sdio_tran_handle[chn].tran_callback_para);
+ }
+ else
+ {
+ sdio_tran_handle[chn].tran_callback = callback;
+ SDIOTRAN_DEBUG("sdio_tran_handle, chn = %d, callback = %p",sdio_tran_handle[chn].chn,sdio_tran_handle[chn].tran_callback);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdiodev_readchn_init);
+
+int sdiodev_readchn_uninit(uint32 chn)
+{
+ if(chn >= INVALID_SDIO_CHN)
+ {
+ SDIOTRAN_ERR("err input chn %d",chn);
+ return -1;
+ }
+
+ sdio_tran_handle[chn].chn = INVALID_SDIO_CHN;
+ sdio_tran_handle[chn].tran_callback = NULL;
+ sdio_tran_handle[chn].tran_callback_para = NULL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sdiodev_readchn_uninit);
+
+void invalid_recv_flush(uint32 chn)
+{
+ int len ;
+ char* pbuff = NULL;
+
+ if(chn < 0 || chn > 15)
+ {
+ SDIOTRAN_ERR("err chn");
+ return;
+ }
+
+ len = sdio_dev_get_chn_datalen(chn);
+ if(len <= 0){
+ SDIOTRAN_ERR("chn %d, len err %d!!",chn,len);
+ return;
+ }
+ SDIOTRAN_ERR("NO VALID DATA! CHN %d FLUSH! DATALEN %d!",chn,len);
+ pbuff = kmalloc(len,GFP_KERNEL);
+ if(pbuff){
+ SDIOTRAN_DEBUG("Read to Flush,chn=%d,pbuff=%p,len=%d",chn, pbuff, len);
+ sdio_dev_read(chn, pbuff, NULL);
+ kfree(pbuff);
+ }else{
+ SDIOTRAN_ERR("Kmalloc %d failed!",len);
+ }
+}
+EXPORT_SYMBOL_GPL(invalid_recv_flush);
+
+void flush_blkchn(void)
+{
+ uint8 rw_flag0,rw_flag1;
+ uint8 status0,status1;
+ uint32 chn_status;
+ uint32 chn_rw_flag;
+ uint32 tmp;
+ int err_ret,read_chn;
+ MARLIN_PM_RESUME_WAIT(marlin_sdio_wait);
+ MARLIN_PM_RESUME_RETURN_ERROR(-1);
+
+ sdio_claim_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ status0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x840,&err_ret);
+ if (status0 == 0xFF){
+ SDIOTRAN_ERR("sdio chn reg0 err");
+ return;
+ }
+
+ status1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x841,&err_ret);
+ if (status1 == 0xFF){
+ SDIOTRAN_ERR("sdio chn reg1 err");
+ return;
+ }
+
+ rw_flag0 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x842,&err_ret);
+ if (rw_flag0 == 0xFF){
+ SDIOTRAN_ERR("sdio RW reg0 err");
+ return;
+ }
+
+ rw_flag1 = sdio_readb(sprd_sdio_func[SDIODEV_FUNC_0],0x843,&err_ret);
+ if (rw_flag1 == 0xFF){
+ SDIOTRAN_ERR("sdio RW reg1 err");
+ return;
+ }
+
+ sdio_release_host(sprd_sdio_func[SDIODEV_FUNC_0]);
+
+ chn_status = (uint32)(status0) + ((uint32)(status1) << 8);
+ chn_rw_flag = (uint32)(rw_flag0) + ((uint32)(rw_flag1) << 8);
+
+ SDIOTRAN_ERR("chn_status is 0x%x!!!",chn_status);
+ SDIOTRAN_ERR("chn_rw_flag is 0x%x!!!",chn_rw_flag);
+
+ tmp = (chn_status&(~chn_rw_flag))&(0x0000ffff);
+
+ for(read_chn=0;read_chn<16;read_chn++)
+ {
+ if(BIT_0 & (tmp>>read_chn))
+ {
+ SDIOTRAN_ERR("BLK CHN is 0x%x!!!",read_chn);
+ invalid_recv_flush(read_chn);
+ return;
+ }
+ }
+
+ SDIOTRAN_ERR("NO BLK CHN!!!");
+ return;
+
+}
+EXPORT_SYMBOL_GPL(flush_blkchn);
+
+
+int sdiolog_handler(void)
+{
+ if(NULL != sdio_tran_handle[SDIOLOG_CHN].tran_callback)
+ {
+ SDIOTRAN_DEBUG("SDIOLOG_CHN tran_callback=%p",sdio_tran_handle[SDIOLOG_CHN].tran_callback);
+ sdio_tran_handle[SDIOLOG_CHN].tran_callback();
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int sdio_download_handler(void)
+{
+ if(NULL != sdio_tran_handle[DOWNLOAD_CHANNEL_READ].tran_callback)
+ {
+ SDIOTRAN_DEBUG("DOWNLOAD_CHN tran_callback=%p",sdio_tran_handle[DOWNLOAD_CHANNEL_READ].tran_callback);
+ sdio_tran_handle[DOWNLOAD_CHANNEL_READ].tran_callback();
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int sdio_pseudo_atc_handler(void)
+{
+ SDIOTRAN_ERR("ENTRY");
+
+ if(NULL != sdio_tran_handle[PSEUDO_ATC_CHANNEL_READ].tran_callback)
+ {
+ SDIOTRAN_ERR("tran_callback=%p",sdio_tran_handle[PSEUDO_ATC_CHANNEL_READ].tran_callback);
+ sdio_tran_handle[PSEUDO_ATC_CHANNEL_READ].tran_callback();
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int sdio_pseudo_loopcheck_handler(void)
+{
+ SDIOTRAN_ERR("ENTRY");
+
+ if(NULL != sdio_tran_handle[PSEUDO_ATC_CHANNEL_LOOPCHECK].tran_callback)
+ {
+ SDIOTRAN_ERR("tran_callback=%p",sdio_tran_handle[PSEUDO_ATC_CHANNEL_LOOPCHECK].tran_callback);
+ sdio_tran_handle[PSEUDO_ATC_CHANNEL_LOOPCHECK].tran_callback();
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+int sdio_wifi_handler(uint32 chn)
+{
+ if(NULL != sdio_tran_handle[chn].tran_callback_para)
+ {
+ SDIOTRAN_DEBUG("wifi_handle_chn %d tran_callback=%p",chn,sdio_tran_handle[chn].tran_callback_para);
+ sdio_tran_handle[chn].tran_callback_para(chn);
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int sdio_assertinfo_handler(void)
+{
+ SDIOTRAN_ERR("ENTRY");
+
+ if(NULL != sdio_tran_handle[MARLIN_ASSERTINFO_CHN].tran_callback)
+ {
+ SDIOTRAN_ERR("tran_callback=%p",sdio_tran_handle[MARLIN_ASSERTINFO_CHN].tran_callback);
+ sdio_tran_handle[MARLIN_ASSERTINFO_CHN].tran_callback();
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+
+static void marlin_workq(void)
+{
+ int read_chn;
+ int ret = 0;
+
+ SDIOTRAN_DEBUG("ENTRY");
+
+#if !defined(CONFIG_SDIODEV_TEST)
+
+ read_chn = sdio_dev_get_read_chn();
+ switch(read_chn)
+ {
+ case SDIOLOG_CHN:
+ ret = sdiolog_handler();
+ break;
+ case DOWNLOAD_CHANNEL_READ:
+ ret = sdio_download_handler();
+ break;
+ case PSEUDO_ATC_CHANNEL_READ:
+ ret = sdio_pseudo_atc_handler();
+ break;
+ case PSEUDO_ATC_CHANNEL_LOOPCHECK:
+ ret = sdio_pseudo_loopcheck_handler();
+ break;
+ case MARLIN_ASSERTINFO_CHN:
+ ret = sdio_assertinfo_handler();
+ break;
+ case WIFI_CHN_8:
+ case WIFI_CHN_9:
+ ret = sdio_wifi_handler(read_chn);
+ break;
+ default:
+ SDIOTRAN_ERR("no handler for this chn",read_chn);
+ invalid_recv_flush(read_chn);
+ }
+
+ if(-1 == ret)
+ invalid_recv_flush(read_chn);
+
+#else
+
+#if defined(SDIO_TEST_CASE4)
+ case4_workq_handler();
+#endif
+
+#if defined(SDIO_TEST_CASE5)
+ case5_workq_handler();
+#endif
+
+#if defined(SDIO_TEST_CASE6)
+ case6_workq_handler();
+#endif
+
+#if defined(SDIO_TEST_CASE9)
+ case9_workq_handler();
+#endif
+
+#endif//CONFIG_SDIODEV_TEST
+
+ wake_unlock(&marlin_wakelock);
+
+}
+
+
+
+
+static irqreturn_t marlin_irq_handler(int irq, void * para)
+{
+ wake_lock(&marlin_wakelock);
+ irq_set_irq_type(irq,IRQF_TRIGGER_RISING);
+
+ if(get_sprd_download_fin() != 1)
+ {
+ schedule_work(&marlin_wq);
+ }
+ else if(NULL != sdio_tran_handle[WIFI_CHN_8].tran_callback_para)
+ {
+ sdio_tran_handle[WIFI_CHN_8].tran_callback_para(WIFI_CHN_8);
+ wake_unlock(&marlin_wakelock);
+ }
+ else
+ schedule_work(&marlin_wq);
+
+ return IRQ_HANDLED;
+}
+
+static int sdio_dev_intr_init(void)
+{
+ int ret;
+
+
+ wake_lock_init(&marlin_wakelock, WAKE_LOCK_SUSPEND, "marlin_wakelock");
+
+ INIT_WORK(&marlin_wq, marlin_workq);
+
+ ret = gpio_request(sdio_data->data_irq,"marlin_irq");
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("req gpio sdio_data->data_irq = %d fail!!!",\
+ sdio_data->data_irq);
+ return ret;
+ }
+
+ ret = gpio_direction_input(sdio_data->data_irq);
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("sdio_data->data_irq = %d input set fail!!!",\
+ sdio_data->data_irq);
+ return ret;
+
+ }
+
+ sdio_irq_num = gpio_to_irq(sdio_data->data_irq);
+
+ ret = request_irq(sdio_irq_num, marlin_irq_handler,IRQF_TRIGGER_RISING |IRQF_NO_SUSPEND, "sdio_dev_intr", NULL );
+ //ret = request_irq(sdio_irq_num, marlin_irq_handler,IRQF_TRIGGER_HIGH | IRQF_ONESHOT |IRQF_NO_SUSPEND, "sdio_dev_intr", NULL );
+ if (ret != 0) {
+ SDIOTRAN_ERR("request irq err!!!gpio is %d!!!",sdio_data->data_irq);
+ return ret;
+ }
+
+ SDIOTRAN_ERR("ok!!!irq is %d!!!",sdio_irq_num);
+
+ return 0;
+}
+
+static void sdio_dev_intr_uninit(void)
+{
+ disable_irq_nosync(sdio_irq_num);
+ free_irq(sdio_irq_num,NULL);
+ gpio_free(sdio_data->data_irq);
+ gpio_free(sdio_data->wake_out);
+
+ cancel_work_sync(&marlin_wq);
+ //flush_workqueue(&marlin_wq);
+ //destroy_workqueue(&marlin_wq);
+
+ wake_lock_destroy(&marlin_wakelock);
+
+ SDIOTRAN_ERR("ok!!!");
+
+}
+static void set_apsdiohal_ready(void)
+{
+ ap_sdio_ready = 1;
+}
+
+static void set_apsdiohal_unready(void)
+{
+ ap_sdio_ready = 0;
+}
+
+//return 1 means ap sdiohal ready
+bool get_apsdiohal_status(void)
+{
+ return ap_sdio_ready;
+}
+EXPORT_SYMBOL_GPL(get_apsdiohal_status);
+
+//return 1 means marlin sdiohal ready
+bool get_sdiohal_status(void)
+{
+ return marlin_sdio_ready.marlin_sdio_init_end_tag;
+}
+EXPORT_SYMBOL_GPL(get_sdiohal_status);
+
+static void clear_sdiohal_status(void)
+{
+ marlin_sdio_ready.marlin_sdio_init_start_tag = 0;
+ marlin_sdio_ready.marlin_sdio_init_end_tag = 0;
+}
+
+static irqreturn_t marlinsdio_ready_irq_handler(int irq, void * para)
+{
+ disable_irq_nosync(irq);
+
+
+ SDIOTRAN_ERR("entry");
+
+ if(!marlin_sdio_ready.marlin_sdio_init_start_tag){
+ SDIOTRAN_ERR("start");
+ irq_set_irq_type(irq,IRQF_TRIGGER_LOW);
+ marlin_sdio_ready.marlin_sdio_init_start_tag = 1;}
+ else{
+ SDIOTRAN_ERR("end");
+ irq_set_irq_type(irq,IRQF_TRIGGER_HIGH);
+ marlin_sdio_ready.marlin_sdio_init_end_tag = 1;}
+
+ if(!marlin_sdio_ready.marlin_sdio_init_end_tag)
+ enable_irq(irq);
+
+
+ return IRQ_HANDLED;
+
+}
+
+static int marlin_sdio_sync_init(void)
+{
+#if !(defined CONFIG_MACH_SP8730SEEA || defined CONFIG_MACH_SP8730SEEA_QHD)
+ int ret;
+
+ SDIOTRAN_ERR("entry");
+
+ sci_glb_clr(SPRD_PIN_BASE + sdio_data->rfctl_off,(BIT(3)|BIT(7)|0));
+ sci_glb_set(SPRD_PIN_BASE + sdio_data->rfctl_off,(BIT(4)|BIT(5)|BIT(2)|BIT(6)));
+
+ ret = gpio_request(sdio_data->io_ready,"marlin_sdio_ready_irq");
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("req gpio sdio_data->io_ready = %d fail!!!",\
+ sdio_data->io_ready);
+ return ret;
+ }
+
+ ret = gpio_direction_input(sdio_data->io_ready);
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("sdio_data->io_ready = %d input set fail!!!",\
+ sdio_data->io_ready);
+ return ret;
+
+ }
+
+ marlin_sdio_ready_irq_num = gpio_to_irq(sdio_data->io_ready);
+ SDIOTRAN_ERR("req irq");
+ ret = request_irq(marlin_sdio_ready_irq_num, marlinsdio_ready_irq_handler,IRQF_TRIGGER_RISING |IRQF_NO_SUSPEND, "m_sdio_ready_intr", NULL );
+ if (ret != 0) {
+ SDIOTRAN_ERR("request irq err!!!gpio is %d!!!",sdio_data->io_ready);
+ return ret;
+ }
+
+ SDIOTRAN_ERR("ok!!!irq is %d!!!",marlin_sdio_ready_irq_num);
+#endif
+ return 0;
+}
+
+void marlin_sdio_sync_uninit(void)
+{
+ free_irq(marlin_sdio_ready_irq_num,NULL);
+ gpio_free(sdio_data->io_ready);
+#if !(defined CONFIG_MACH_SP8730SEEA || defined CONFIG_MACH_SP8730SEEA_QHD)
+ sci_glb_clr(SPRD_PIN_BASE + sdio_data->rfctl_off,(BIT(4)|BIT(5)|0));
+ sci_glb_set(SPRD_PIN_BASE + sdio_data->rfctl_off,(BIT(4)));
+#endif
+ SDIOTRAN_ERR("ok!!!");
+}
+EXPORT_SYMBOL_GPL(marlin_sdio_sync_uninit);
+
+
+static void marlinack_workq(void)
+{
+ int read_chn;
+ int ret = 0;
+
+ SDIOTRAN_ERR("ENTRY");
+ if(sdio_w_flag == 1)
+ complete(&marlin_ack);
+
+}
+
+int time_d_value(struct timeval *start, struct timeval *end)
+{
+ return (end->tv_sec - start->tv_sec)*1000000 + (end->tv_usec - start->tv_usec);
+}
+
+static irqreturn_t marlinwake_irq_handler(int irq, void * para)
+{
+ struct timeval cur_time;
+ uint32 gpio_wake_status = 0, usec;
+ //irq_set_irq_type(irq,IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING);
+ gpio_wake_status = gpio_get_value(sdio_data->wake_ack);
+
+ if(get_sprd_download_fin() != 1)
+ {
+ if(!marlin_sdio_ready.marlin_sdio_init_start_tag && gpio_wake_status){
+ SDIOTRAN_ERR("start,g_val=%d",gpio_wake_status);
+ irq_set_irq_type(irq,IRQF_TRIGGER_LOW);
+ marlin_sdio_ready.marlin_sdio_init_start_tag = 1;
+ }
+ else if(!marlin_sdio_ready.marlin_sdio_init_end_tag && (!gpio_wake_status)){
+ SDIOTRAN_ERR("end,g_val=%d",gpio_wake_status);
+ irq_set_irq_type(irq,IRQF_TRIGGER_RISING);
+ marlin_sdio_ready.marlin_sdio_init_end_tag = 1;
+ }
+ else
+ {
+ SDIOTRAN_ERR("marlin gpio0 err interupt,g_val=%d",gpio_wake_status);
+ }
+ }
+ else
+ {
+ /*add count irq for loopcheck*/
+ irq_count_change++;
+
+ /* avoid gpio jump , so need check the last and cur gpio value.*/
+ do_gettimeofday(&cur_time);
+ if(ack_gpio_status == gpio_wake_status)
+ {
+ // usec = time_d_value(&ack_irq_time, &cur_time);
+ // if(usec < 200) //means invalid gpio value, so discard
+ {
+ SDIOTRAN_ERR("discard gpio%d irq\n", sdio_data->wake_ack);
+ return IRQ_HANDLED;
+ }
+ // SDIOTRAN_ERR("gpio%d %d-->%d\n",sdio_data->wake_ack, gpio_wake_status, 1 - gpio_wake_status );
+ // gpio_wake_status = 1 - gpio_wake_status;
+
+ }
+ ack_irq_time = cur_time;
+ ack_gpio_status = gpio_wake_status;
+ SDIOTRAN_ERR("%d-%d\n",sdio_data->wake_ack, gpio_wake_status );
+
+ if(gpio_wake_status)
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+ else
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_RISING);
+
+ if(gpio_wake_status)
+ {
+ wake_lock(&marlinpub_wakelock);
+ sleep_para.gpio_up_time = jiffies;
+ }
+ else
+ {
+ wake_unlock(&marlinpub_wakelock);
+ sleep_para.gpio_down_time = jiffies;
+ }
+
+ if((!gpio_wake_status) && time_after(sleep_para.gpio_down_time,sleep_para.gpio_up_time))
+ {
+ if(jiffies_to_msecs(sleep_para.gpio_down_time -\
+ sleep_para.gpio_up_time)> sleep_para.bt_req_time)
+ {
+ SDIOTRAN_ERR("BT REQ!!!");
+ marlin_bt_wake_flag = 1;
+ wake_lock_timeout(&BT_AP_wakelock, sleep_para.wake_lock_time); //wsh
+ }
+
+ }
+
+ //schedule_work(&marlinack_wq);
+ if(gpio_wake_status)
+ {
+ if( atomic_read(&gpioreq_need_pulldown) )//if(sleep_para.gpioreq_need_pulldown)
+ {
+ sleep_para.gpio_opt_tag = 1;
+ SDIOTRAN_ERR("gpio_opt_tag-1\n");
+ mod_timer(&(sleep_para.gpio_timer), jiffies + msecs_to_jiffies(sleep_para.marlin_waketime) );
+ if(sdio_w_flag == 1)
+ {
+ complete(&marlin_ack);
+ SDIOTRAN_ERR("ack-sem\n");
+ set_marlin_sleep(0xff,0x1);
+ }
+ else
+ {
+ SDIOTRAN_ERR("sdio_w_flag:%d\n", sdio_w_flag);
+ set_marlin_sleep(0xff,0x2);
+ }
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+
+static int marlin_wake_intr_init(void)
+{
+ int ret;
+ sdio_w_flag = 0;
+ bt_wake_flag = 0;
+
+ INIT_WORK(&marlinwake_wq, marlinack_workq);
+
+ init_completion (&marlin_ack);
+
+
+ wake_lock_init(&BT_AP_wakelock, WAKE_LOCK_SUSPEND, "marlinbtup_wakelock");
+
+ wake_lock_init(&marlinpub_wakelock, WAKE_LOCK_SUSPEND, "marlinpub_wakelock");
+
+ ret = gpio_request(sdio_data->wake_ack,"marlinwake_irq");
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("req gpio sdio_data->wake_ack = %d fail!!!",\
+ sdio_data->wake_ack);
+ return ret;
+ }
+
+ ret = gpio_direction_input(sdio_data->wake_ack);
+ if (ret<0)
+ {
+ SDIOTRAN_ERR("sdio_data->wake_ack = %d input set fail!!!",\
+ sdio_data->wake_ack);
+ return ret;
+
+ }
+
+ marlinwake_irq_num = gpio_to_irq(sdio_data->wake_ack);
+
+ ret = request_irq(marlinwake_irq_num, marlinwake_irq_handler,IRQF_TRIGGER_RISING |IRQF_NO_SUSPEND, "marlin_wake_intr", NULL );
+ //ret = request_irq(marlinwake_irq_num, marlinwake_irq_handler,IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, "marlin_wake_intr", NULL );
+ if (ret != 0) {
+ SDIOTRAN_ERR("request irq err!!!gpio is %d!!!",sdio_data->wake_ack);
+ return ret;
+ }
+
+ SDIOTRAN_ERR("ok!!!irq is %d!!!",marlinwake_irq_num);
+
+ return 0;
+}
+
+static void marlin_wake_intr_uninit(void)
+{
+ disable_irq_nosync(marlinwake_irq_num);
+ free_irq(marlinwake_irq_num,NULL);
+ gpio_free(sdio_data->wake_ack);
+
+
+ cancel_work_sync(&marlinwake_wq);
+ //flush_workqueue(&marlinwake_wq);
+ //destroy_workqueue(&marlinwake_wq);
+
+
+ wake_lock_destroy(&BT_AP_wakelock);
+ wake_lock_destroy(&marlinpub_wakelock);
+
+ SDIOTRAN_ERR("ok!!!");
+
+}
+
+
+
+static void sdio_tran_sync(void)
+{
+
+ int datalen,i,j;
+
+ SDIOTRAN_ERR("entry");
+
+ set_blklen(4);
+
+ while(!sdio_dev_chn_idle(SDIO_SYNC_CHN))
+ {
+ SDIOTRAN_ERR("sync chn is active!!!");
+ //return;
+ }
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(SDIO_SYNC_CHN);
+ if(datalen > 0)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!!",SDIO_SYNC_CHN,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!!",SDIO_SYNC_CHN,datalen);
+
+ }
+
+ sync_data_ptr = kmalloc(4,GFP_KERNEL);
+ if (NULL == sync_data_ptr)
+ {
+ SDIOTRAN_ERR("kmalloc sync buf err!!!");
+ return -1;
+ }
+
+ SDIOTRAN_ERR("kmalloc sync buf ok!!!");
+
+ for(i=0;i<4;i++)
+ *(sync_data_ptr+i) = i;
+
+ sdio_dev_write(SDIO_SYNC_CHN,sync_data_ptr,\
+ ((datalen > 4) ? 4: datalen));
+
+ kfree(sync_data_ptr);
+
+ set_blklen(512);
+}
+
+
+void set_blklen(int blklen)
+{
+ sdio_claim_host(sprd_sdio_func[1]);
+ sdio_set_block_size(sprd_sdio_func[1], blklen);
+ sdio_release_host(sprd_sdio_func[1]);
+
+ SDIOTRAN_ERR("set blklen = %d!!!",blklen);
+
+}
+
+static void sdio_init_timer(void)
+{
+ init_timer(&sleep_para.gpio_timer);
+ sleep_para.gpio_timer.function = gpio_timer_handler;
+
+#if defined(CONFIG_WCN_EXTENSION)
+ sleep_para.marlin_waketime = 350;
+ sleep_para.bt_req_time = 100;
+ sleep_para.ack_high_time = 200;
+ sleep_para.wake_lock_time = HZ/2;
+#else
+ sleep_para.marlin_waketime = 1500;
+ sleep_para.bt_req_time = 200;
+ sleep_para.ack_high_time = 300;
+ sleep_para.wake_lock_time = HZ*2;
+#endif
+
+ sleep_para.gpio_opt_tag = 0;
+ atomic_set(&gpioreq_need_pulldown, 1);//sleep_para.gpioreq_need_pulldown = 1;
+}
+
+
+static void sdio_uninit_timer(void)
+{
+ del_timer(&sleep_para.gpio_timer);
+ sleep_para.marlin_waketime = 0;
+ sleep_para.bt_req_time = 0;
+ sleep_para.ack_high_time = 0;
+ sleep_para.wake_lock_time = 0;
+ sleep_para.gpio_opt_tag = 0;
+ atomic_set(&gpioreq_need_pulldown, 1);//sleep_para.gpioreq_need_pulldown = 1;
+}
+
+static int marlin_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret;
+
+ SDIOTRAN_ERR("sdio drv and dev match!!!");
+ mutex_init(&g_sdio_func_lock);
+ ret = get_sdio_dev_func(func);
+ if(ret < 0)
+ {
+ SDIOTRAN_ERR("get func err!!!\n");
+ return ret;
+ }
+ SDIOTRAN_ERR("get func ok!!!\n");
+
+ /* Enable Function 1 */
+ sdio_claim_host(sprd_sdio_func[1]);
+ ret = sdio_enable_func(sprd_sdio_func[1]);
+ sdio_set_block_size(sprd_sdio_func[1], 512);
+ sdio_release_host(sprd_sdio_func[1]);
+ if (ret < 0) {
+ SDIOTRAN_ERR("enable func1 err!!! ret is %d",ret);
+ return ret;
+ }
+ SDIOTRAN_ERR("enable func1 ok!!!");
+
+ spin_lock_init(&sleep_spinlock);
+ sdio_init_timer();
+ clear_sdiohal_status();
+ wakeup_slave_pin_init();
+ marlin_wake_intr_init();
+ //marlin_sdio_sync_init();
+//case6
+#if defined(CONFIG_SDIODEV_TEST)
+ gaole_creat_test();
+#endif
+
+ sdio_dev_intr_init();
+
+#if defined(CONFIG_SDIODEV_TEST)
+ sdio_tran_sync();
+#endif
+
+/*case1
+#if defined(CONFIG_SDIODEV_TEST)
+ gaole_creat_test();
+#endif
+*/
+ //set_bt_pm_func(set_marlin_wakeup,set_marlin_sleep);
+
+ set_apsdiohal_ready();
+ have_card = 1;
+ return 0;
+}
+
+static void marlin_sdio_remove(struct sdio_func *func)
+{
+ SDIOTRAN_DEBUG("entry");
+ sdio_uninit_timer();
+ free_sdio_dev_func(func);
+ sdio_dev_intr_uninit();
+ marlin_wake_intr_uninit();
+ //marlin_sdio_sync_uninit();
+ set_apsdiohal_unready();
+ clear_sdiohal_status();
+
+ SDIOTRAN_DEBUG("ok");
+
+}
+
+static int marlin_sdio_suspend(struct device *dev)
+{
+ mutex_lock(&g_mgr_suspend.func_lock);
+ SDIOTRAN_ERR("[%s]enter\n", __func__);
+
+ gpio_marlin_req_tag = gpio_get_value(sdio_data->data_irq);
+
+ if(gpio_marlin_req_tag)
+ SDIOTRAN_ERR("err marlin_req!!!");
+ else
+ irq_set_irq_type(sdio_irq_num,IRQF_TRIGGER_HIGH);
+
+ gpio_marlinwake_tag = gpio_get_value(sdio_data->wake_ack);
+
+ if(gpio_marlinwake_tag)
+ SDIOTRAN_ERR("err marlinwake!!!");
+ else
+ irq_set_irq_type(marlinwake_irq_num,IRQF_TRIGGER_HIGH);
+
+
+
+ smp_mb();
+ SDIOTRAN_ERR("[%s]ok\n", __func__);
+ return 0;
+}
+static int marlin_sdio_resume(struct device *dev)
+{
+ SDIOTRAN_ERR("[%s]enter\n", __func__);
+ /****************/
+ mutex_unlock(&g_mgr_suspend.func_lock);
+ sleep_para.gpio_opt_tag = 0;
+ set_marlin_wakeup(0, 1);
+ mod_timer(&(sleep_para.gpio_timer),jiffies + msecs_to_jiffies(sleep_para.marlin_waketime));
+ /***************/
+ smp_mb();
+ SDIOTRAN_ERR("[%s]ok\n", __func__);
+ return 0;
+}
+
+static void* sdio_dev_get_host(void)
+{
+ struct device *dev;
+
+ struct sdhci_host *host;
+
+ struct platform_device *pdev;
+
+ dev = bus_find_device_by_name(&platform_bus_type, NULL, sdio_data->sdhci);
+ if(dev == NULL)
+ {
+ SDIOTRAN_ERR("sdio find dev by name failed!!!");
+ return NULL;
+ }
+
+ pdev = to_platform_device(dev);
+ if(pdev == NULL)
+ {
+ SDIOTRAN_ERR("sdio dev get platform device failed!!!");
+ return NULL;
+ }
+
+ host = platform_get_drvdata(pdev);
+ return container_of(host, struct mmc_host, private);
+
+
+}
+
+void marlin_sdio_uninit(void)
+{
+ set_sprd_download_fin(0);
+ sdio_unregister_driver(&marlin_sdio_driver);
+ mgr_suspend_defint();
+ sdio_dev_host = NULL;
+ have_card = 0;
+
+ kfree(sdio_data);
+ sdio_data = NULL;
+ SDIOTRAN_ERR("ok");
+}
+
+int marlin_sdio_init(void)
+{
+ int ret;
+ struct device_node *np;
+ SDIOTRAN_ERR("entry");
+ if(have_card == 1){
+ marlin_sdio_uninit();
+ }
+ mgr_suspend_init();
+ //atomic_set(&req_marlin_wait_tag, 0);
+ atomic_set(&gpioreq_need_pulldown, 1);
+ atomic_set(&is_wlan_open, 0);
+ atomic_set(&set_marlin_cmplete, 1);
+
+ sdio_data = kzalloc(sizeof(*sdio_data), GFP_KERNEL);
+ if (!sdio_data)
+ return -ENOMEM;
+ np = of_find_node_by_name(NULL, "sprd-marlin");
+ if (!np) {
+ SDIOTRAN_ERR("sprd-marlin not found");
+ return -1;
+ }
+
+ sdio_data->wake_ack = of_get_gpio(np, 0);
+ sdio_data->data_irq = of_get_gpio(np, 1);
+ sdio_data->wake_out = of_get_gpio(np, 2);
+ sdio_data->io_ready = of_get_gpio(np, 3);
+
+ of_property_read_u32(np, "cp-rfctl-offset", &(sdio_data->rfctl_off));
+
+ ret = of_property_read_string(np, "sdhci-name", &(sdio_data->sdhci));
+ if (ret) {
+ SDIOTRAN_ERR("get sdhci-name failed");
+ return -1;
+ }
+
+ sdio_dev_host = sdio_dev_get_host();
+ if(NULL == sdio_dev_host)
+ {
+ SDIOTRAN_ERR("get host failed!!!");
+ return -1;
+ }
+ SDIOTRAN_ERR("sdio get host ok!!!");
+
+ ret = sdio_register_driver(&marlin_sdio_driver);
+ if(0 != ret)
+ {
+ SDIOTRAN_ERR("sdio register drv err!!!ret is %d!!!",ret);
+ return -1;
+ }
+
+ SDIOTRAN_ERR("sdio register drv succ!!!");
+
+ flush_delayed_work(&sdio_dev_host->detect);
+ mmc_detect_change(sdio_dev_host, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(marlin_sdio_init);
+
+
diff --git a/drivers/misc/sdiodev/sdio_dev.h b/drivers/misc/sdiodev/sdio_dev.h
new file mode 100755
index 00000000..3e950770
--- /dev/null
+++ b/drivers/misc/sdiodev/sdio_dev.h
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2013 Spreadtrum Communications Inc.
+ *
+ * Filename : sdio_dev.h
+ * Abstract : This file is a implementation for itm sipc command/event function
+ *
+ * Authors : gaole.zhang
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __SDIO_DEV_H__
+#define __SDIO_DEV_H__
+
+#include <linux/module.h>
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <soc/sprd/regulator.h>
+#include <linux/platform_device.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <soc/sprd/gpio.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/irq.h>
+#include <linux/suspend.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/board.h>
+#include <linux/sprd_iommu.h>
+#include <linux/spinlock.h>
+//#include <asm/system.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/syscalls.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+
+typedef unsigned int uint32;
+typedef unsigned char uint8;
+typedef irqreturn_t (*sdiodev_handler_t)(int, void *);
+typedef void (*SDIO_TRAN_CALLBACK)(void);
+typedef void (*SDIO_TRAN_CALLBACK_PARA)(int);
+typedef struct _sdio_chn_handler
+{
+ uint32 chn;
+ SDIO_TRAN_CALLBACK tran_callback;
+ SDIO_TRAN_CALLBACK_PARA tran_callback_para;
+}SDIO_CHN_HANDLER;
+
+typedef struct _sleep_policy
+{
+ struct timer_list gpio_timer;
+ uint32 marlin_waketime;
+ uint32 bt_req_time;
+ uint32 ack_high_time;
+ uint32 wake_lock_time;
+ uint32 gpio_opt_tag; // 1:dont't pull gpio 0:pull gpio
+ unsigned long gpioreq_up_time;
+ unsigned long gpioreq_need_pulldown;
+ unsigned long gpio_up_time;
+ unsigned long gpio_down_time;
+}SLEEP_POLICY_T;
+
+
+typedef struct _marlin_sdio_ready
+{
+ bool marlin_sdio_init_start_tag;
+ bool marlin_sdio_init_end_tag;
+
+}MARLIN_SDIO_READY_T;
+
+struct sdio_data {
+ u32 wake_ack;
+ u32 data_irq;
+ u32 wake_out;
+ u32 io_ready;
+ u32 rfctl_off;
+ const char *sdhci;
+};
+
+#define MARLIN_SDIO_VERSION "1.0"
+#define INVALID_SDIO_CHN 16
+#define INVALID_SDIO_WCHN 8
+
+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
+#define LINUX_VERSION_CODE KERNEL_VERSION(3, 10, 0)
+#define BIT_0 0x01
+#define SDIODEV_MAX_FUNCS 2
+#define SDIODEV_FUNC_0 0
+#define SDIODEV_FUNC_1 1
+#define MARLIN_VENDOR_ID 0x00
+#define MARLIN_DEVICE_ID 0x2331
+#define SDIO_CHN_8 0x1
+#define SDIO_CHN_9 0x2
+#define SDIO_CHN_11 0x8
+#define SDIO_CHN_12 0x10
+#define SDIO_CHN_13 0x20
+
+#define SDIO_CHN_14 0x40
+#define SDIO_CHN_15 0x80
+
+#define SDIOLOG_CHN 14
+#define SDIO_SYNC_CHN 10
+#define DOWNLOAD_CHANNEL_READ 12
+#define PSEUDO_ATC_CHANNEL_READ 11
+#define PSEUDO_ATC_CHANNEL_LOOPCHECK (15)
+#define MARLIN_ASSERTINFO_CHN (13)
+
+
+#define WIFI_CHN_8 8
+#define WIFI_CHN_9 9
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
+#define SMP_BARRIER(x) smp_read_barrier_depends(x)
+#else
+#define SMP_BARRIER(x) smp_rmb(x)
+#endif
+
+
+
+#define SDIOTRAN_HEADER "[SDIOTRAN]"
+
+#define SDIOTRAN_ERR(fmt,args...) \
+ pr_err(SDIOTRAN_HEADER "%s:" fmt "\n", __func__, ## args)
+
+#define SDIOTRAN_DEBUG(fmt,args...) \
+ pr_debug(SDIOTRAN_HEADER "%s:" fmt "\n", __func__, ## args)
+
+int set_wlan_status(int status);
+
+int set_marlin_wakeup(uint32 chn,uint32 user_id);
+int set_marlin_sleep(uint32 chn,uint32 user_id);
+
+
+
+#if 0//#if !defined(CONFIG_MARLIN_NO_SLEEP)
+
+#define MARLIN_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
+#define _MARLIN_PM_RESUME_WAIT(a, b) do {\
+ int retry = 0; \
+ SMP_BARRIER(); \
+ while (marlin_mmc_suspend && retry++ != b) { \
+ SMP_BARRIER(); \
+ wait_event_interruptible_timeout(a, !marlin_mmc_suspend, HZ/100); \
+ } \
+ } while (0)
+#define MARLIN_PM_RESUME_WAIT(a) _MARLIN_PM_RESUME_WAIT(a, 200)
+#define MARLIN_PM_RESUME_WAIT_FOREVER(a) _MARLIN_PM_RESUME_WAIT(a, ~0)
+#define MARLIN_PM_RESUME_RETURN_ERROR(a) do { \
+ if (marlin_mmc_suspend) {\
+ SDIOTRAN_ERR("ERR!!!");\
+ return a;} \
+ } while (0)
+#else
+#define MARLIN_PM_RESUME_WAIT_INIT(a)
+#define _MARLIN_PM_RESUME_WAIT(a, b)
+#define MARLIN_PM_RESUME_WAIT(a)
+#define MARLIN_PM_RESUME_WAIT_FOREVER(a)
+#define MARLIN_PM_RESUME_RETURN_ERROR(a)
+#endif
+
+
+
+
+
+int sdio_dev_chn_idle(uint32 chn);
+int sdio_dev_get_chn_datalen(uint32 chn);
+int sdio_dev_get_read_chn(void);
+bool get_sdiohal_status(void);
+bool get_apsdiohal_status(void);
+void marlin_sdio_sync_uninit(void);
+int sdio_dev_write(uint32 chn,void* data_buf,uint32 count);
+int sdio_dev_read(uint32 chn,void* read_buf,uint32 *count);
+int sdiodev_readchn_init(uint32 chn,void* callback,bool with_para);
+int sdiodev_readchn_uninit(uint32 chn);
+void set_sprd_download_fin(int dl_tag);
+int marlin_sdio_init(void);
+bool get_sprd_marlin_status(void);
+
+void set_blklen(int blklen);
+void flush_blkchn(void);
+
+
+#endif
diff --git a/drivers/misc/sdiodev/sdio_dev_test.c b/drivers/misc/sdiodev/sdio_dev_test.c
new file mode 100644
index 00000000..31385b0a
--- /dev/null
+++ b/drivers/misc/sdiodev/sdio_dev_test.c
@@ -0,0 +1,1219 @@
+/*
+ * Copyright (C) 2013 Spreadtrum Communications Inc.
+ *
+ * Filename : sdio_dev_test.c
+ * Abstract : This file is a implementation for itm sipc command/event function
+ *
+ * Authors : gaole.zhang
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "sdio_dev.h"
+
+
+#if defined(SDIO_TEST_CASE1)
+
+#define SEND_BUF_LEN 1024//SDIO_TEST_CASE1
+
+char *data_send_ptr[17] = {0};
+
+
+static void test_sdio_send_func(int chn,int senddatalen,void* data_buf)
+{
+
+ uint32 chndatalen,ret;
+
+ char *tmp = (char*)data_buf;
+
+ //SDIOTRAN_ERR("\nrun to test_sdio_send_func,senddatalen is %d!!!\n",senddatalen);
+ SDIOTRAN_ERR("entry");
+
+
+
+ set_marlin_wakeup(chn,1);
+
+
+
+ if(!sdio_dev_chn_idle(chn))
+ {
+ SDIOTRAN_ERR("send chn active,can't send right now,chn is %d!!!",chn);
+ return;
+ }
+
+
+ chndatalen = sdio_dev_get_chn_datalen(chn);
+ if(senddatalen > chndatalen)
+ {
+ SDIOTRAN_ERR("channel %d chndatalen is =%d,senddatalen is =%d, can't send!!",chn,chndatalen,senddatalen);
+ return;
+ }
+
+ SDIOTRAN_ERR("ap chn %d send len %d data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",chn,senddatalen,\
+ tmp[0],\
+ tmp[1],\
+ tmp[2],\
+ tmp[3], \
+ tmp[101], \
+ tmp[102], \
+ tmp[103], \
+ tmp[104], \
+ tmp[230], \
+ tmp[231], \
+ tmp[232], \
+ tmp[233] \
+ );
+
+ sdio_dev_write(chn,data_buf,senddatalen);
+ set_marlin_sleep(chn,1);
+
+
+}
+
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j,k;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ /*for(i=0;i<16;i++){
+
+ data_send_ptr[i] = kmalloc(SEND_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_send_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc send buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf%d ok!!!",i);
+
+ for(j=0,k=0;j<SEND_BUF_LEN;j++,k++)
+ *(data_send_ptr[i]+j) = ((k+i)<=255?(k+i):(k=0,k+i));
+
+ }*/
+ set_blklen(512);
+
+ while(1)
+ {
+
+ /*
+ for(j=0;j<8;j++)
+ {
+ set_blklen(32<<j);
+ for(i=0;i<9;i++)
+ {
+ if(((32<<j)<<i) > 8192)
+ break;
+
+ test_sdio_send_func(j,(32<<j)<<i,data_send_ptr[1]);
+ }
+ }
+ */
+
+ /*
+ for(j=1;j<128;j++)
+ test_sdio_send_func(0,j,data_send_ptr[1]);
+ break;
+
+ msleep(1000);
+ test_sdio_send_func(0,64,data_send_ptr[1]);
+ test_sdio_send_func(0,128,data_send_ptr[1]);
+ test_sdio_send_func(0,192,data_send_ptr[1]);
+ */
+
+
+
+
+ /*if test CASE3 please unmark msleep func and modify sleep time,
+ CP side need not to change*/
+ //msleep(1000);
+
+ for(i=0;i<16;i++)
+ {
+ msleep(1000);
+ for(j=0;j<2;j++)
+ {
+ msleep(1000);
+ test_sdio_send_func(i,0x200<<j,data_send_ptr[i]);
+ }
+
+ SDIOTRAN_ERR("chn %d test finish!!!",i);
+ }
+
+ SDIOTRAN_ERR("sdio test write finish!!!");
+ break;
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+ int i,j,k;
+ for(i=0;i<16;i++){
+
+ data_send_ptr[i] = kmalloc(SEND_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_send_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc send buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf%d ok!!!",i);
+
+ for(j=0,k=0;j<SEND_BUF_LEN;j++,k++)
+ *(data_send_ptr[i]+j) = ((k+i)<=255?(k+i):(k=0,k+i));
+
+ }
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+
+#endif//SDIO_TEST_CASE1
+
+#if defined(SDIO_TEST_CASE2)
+
+#define RECV_BUF_LEN 1024//SDIO_TEST_CASE2
+
+char *data_recv_ptr[17] = {0};
+
+int invalid_num = 0;
+
+static int active_chn = 0;
+static int last_chn = 1;
+static int dummy_recv = 0;
+
+static int read_datalen = 0;
+
+void test_sdio_recv_func(void)
+{
+ int i,j;
+ SDIOTRAN_DEBUG("entry");
+
+ if((active_chn = sdio_dev_get_read_chn()) == -1)
+ {
+ invalid_num++;
+ return;
+ }
+
+ if(last_chn == active_chn)
+ {
+ dummy_recv++;
+ }
+ else
+ {
+ last_chn = active_chn;
+ dummy_recv--;
+ }
+
+ for(j=0;j<RECV_BUF_LEN;j++)
+ *(data_recv_ptr[active_chn]+j) = 0;
+
+ sdio_dev_read(active_chn,(data_recv_ptr[active_chn]+10),&read_datalen);
+
+ SDIOTRAN_ERR("ap recv: active_chn is %d!!!",active_chn);
+ SDIOTRAN_ERR("ap recv: read_datalen is 0x%x!!!",read_datalen);
+
+ SDIOTRAN_ERR("ap recv data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",\
+ *((data_recv_ptr[active_chn]+10)+read_datalen-9),\
+ *((data_recv_ptr[active_chn]+10)+read_datalen-8),\
+ *((data_recv_ptr[active_chn]+10)+read_datalen-7),\
+ *((data_recv_ptr[active_chn]+10)+read_datalen-6), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen-5), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen-4), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen-3), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen-2), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen-1), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen+1), \
+ *((data_recv_ptr[active_chn]+10)+read_datalen+2) \
+ );
+
+ active_chn = 0;
+ read_datalen = 0;
+}
+
+static int gaole_test_thread(void *data)
+{
+ int i,j;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ for(i=0;i<16;i++){
+
+ data_recv_ptr[i] = kmalloc(RECV_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_recv_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc recv buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc recv buf%d ok!!!",i);
+
+ for(j=0;j<RECV_BUF_LEN;j++)
+ *(data_recv_ptr[i]+j) = 0;
+
+ }
+
+ set_blklen(512);
+
+ while(1)
+ {
+
+ test_sdio_recv_func();
+
+
+ if(dummy_recv > 50)
+ break;
+
+ if(invalid_num > 50)
+ break;
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+
+
+#endif//SDIO_TEST_CASE2
+
+
+
+#if defined(SDIO_TEST_CASE4)
+
+#define BUF_LEN 1024//SDIO_TEST_CASE4
+
+char *data_ptr[10] = {0};
+
+bool continue_send = 1;
+
+static int test_send_chn = 0;
+
+
+
+static void test_sdio_send_func(int chn,void* data_buf)
+{
+
+ uint32 datalen;
+
+ char *tmp = (char*)data_buf;
+
+ //SDIOTRAN_ERR("\nrun to test_sdio_send_func!!!\n");
+
+ while(!sdio_dev_chn_idle(chn));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(chn);
+ if(datalen)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!!",chn,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!!",chn,datalen);
+
+ }
+
+ SDIOTRAN_ERR("ap %d send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",chn,\
+ tmp[0],\
+ tmp[1],\
+ tmp[2],\
+ tmp[3], \
+ tmp[101], \
+ tmp[102], \
+ tmp[103], \
+ tmp[104], \
+ tmp[230], \
+ tmp[231], \
+ tmp[232], \
+ tmp[233] \
+ );
+
+ sdio_dev_write(chn,data_buf,datalen);
+
+}
+
+void case4_workq_handler(void)
+{
+ int i;
+
+ int read_chn = 0;
+ int datalen = 0;
+
+ read_chn = sdio_dev_get_read_chn();
+
+ if(-1 == read_chn)
+ return;
+
+
+ SDIOTRAN_DEBUG("ap recv: active_chn is %d!!!",read_chn);
+
+
+ for(i=0;i<BUF_LEN;i++)
+ *(data_ptr[read_chn-7]+i) = 0;
+
+
+ sdio_dev_read(read_chn,data_ptr[read_chn-7],&datalen);
+
+ SDIOTRAN_ERR("ap recv chn %d data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",read_chn,\
+ *(data_ptr[read_chn-7]+0),\
+ *(data_ptr[read_chn-7]+1),\
+ *(data_ptr[read_chn-7]+2),\
+ *(data_ptr[read_chn-7]+3), \
+ *(data_ptr[read_chn-7]+100), \
+ *(data_ptr[read_chn-7]+101), \
+ *(data_ptr[read_chn-7]+102), \
+ *(data_ptr[read_chn-7]+103), \
+ *(data_ptr[read_chn-7]+230), \
+ *(data_ptr[read_chn-7]+231), \
+ *(data_ptr[read_chn-7]+232), \
+ *(data_ptr[read_chn-7]+233) \
+ );
+
+ continue_send = 1;
+}
+
+
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j,k;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ for(i=0;i<10;i++){
+
+ data_ptr[i] = kmalloc(BUF_LEN,GFP_KERNEL);
+ if (NULL == data_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc send buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf%d ok!!!",i);
+
+ for(j=0;j<BUF_LEN;j++)
+ *(data_ptr[i]+j) = 0;
+
+ }
+
+ for(j=0,k=0;j<BUF_LEN;j++,k++)
+ *(data_ptr[0]+j) = (k<=255?k:(k=0,k));
+
+ while(1)
+ {
+
+ if(1 == continue_send)
+ {
+ continue_send = 0;
+ test_sdio_send_func(test_send_chn,data_ptr[test_send_chn]);
+
+
+ test_send_chn++;
+ if(8 == test_send_chn)
+ {
+ test_send_chn = 0;
+ }
+ }
+ else
+ msleep(1);
+ }
+ return 0;
+}
+
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+
+#endif//SDIO_TEST_CASE4
+
+
+#if defined(SDIO_TEST_CASE5)
+
+#define TEST_BUF_LEN 8192 //SDIO_TEST_CASE5
+
+#define TEST_SEND_CHN 0
+
+char *data_test_ptr[17] = {0};
+
+
+int active_chn = 0;
+int read_datalen = 0;
+
+void case5_workq_handler(void)
+{
+ int i;
+
+ active_chn = 0;
+ read_datalen = 0;
+
+ active_chn = sdio_dev_get_read_chn();
+
+ if(-1 == active_chn)
+ return;
+
+ SDIOTRAN_DEBUG("ap recv: active_chn is %d!!!",active_chn);
+
+
+ for(i=0;i<TEST_BUF_LEN;i++)
+ *(data_test_ptr[active_chn]+i) = 0;
+
+
+ sdio_dev_read(active_chn,data_test_ptr[active_chn],&read_datalen);
+
+ SDIOTRAN_ERR("ap recv chn %d data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",active_chn,\
+ *(data_test_ptr[active_chn]+0),\
+ *(data_test_ptr[active_chn]+1),\
+ *(data_test_ptr[active_chn]+2),\
+ *(data_test_ptr[active_chn]+3), \
+ *(data_test_ptr[active_chn]+100), \
+ *(data_test_ptr[active_chn]+101), \
+ *(data_test_ptr[active_chn]+102), \
+ *(data_test_ptr[active_chn]+103), \
+ *(data_test_ptr[active_chn]+230), \
+ *(data_test_ptr[active_chn]+231), \
+ *(data_test_ptr[active_chn]+232), \
+ *(data_test_ptr[active_chn]+233) \
+ );
+}
+
+
+static void test_sdio_send_func(void)
+{
+
+ uint32 datalen;
+
+ SDIOTRAN_ERR("entry");
+
+ while(!sdio_dev_chn_idle(TEST_SEND_CHN));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(TEST_SEND_CHN);
+ if(datalen)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!!",TEST_SEND_CHN,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!!",TEST_SEND_CHN,datalen);
+
+ }
+
+ SDIOTRAN_ERR("ap send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",\
+ *(data_test_ptr[active_chn]+0),\
+ *(data_test_ptr[active_chn]+1),\
+ *(data_test_ptr[active_chn]+2),\
+ *(data_test_ptr[active_chn]+3), \
+ *(data_test_ptr[active_chn]+100), \
+ *(data_test_ptr[active_chn]+101), \
+ *(data_test_ptr[active_chn]+102), \
+ *(data_test_ptr[active_chn]+103), \
+ *(data_test_ptr[active_chn]+230), \
+ *(data_test_ptr[active_chn]+231), \
+ *(data_test_ptr[active_chn]+232), \
+ *(data_test_ptr[active_chn]+233)\
+ );
+
+ sdio_dev_write(TEST_SEND_CHN,data_test_ptr[active_chn],datalen);
+
+}
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ for(i=0;i<16;i++){
+
+ data_test_ptr[i] = kmalloc(TEST_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_test_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_ERR("kmalloc buf%d ok!!!",i);
+
+
+
+ }
+
+ while(1)
+ {
+ msleep(10);
+
+ for(i=0,j=0;i<TEST_BUF_LEN;i++,j++)
+ *(data_test_ptr[0]+i) = (j<=255?j:(j=0,j));
+
+ test_sdio_send_func();
+
+ break;
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+#endif//SDIO_TEST_CASE5
+
+#if defined(SDIO_TEST_CASE6)
+
+#define BUF_LEN 1024//SDIO_TEST_CASE6
+
+char *data_ptr[10] = {0};
+
+bool continue_send = 0;
+
+static int test_send_chn = 0;
+
+static void test_sdio_send_func(int chn,void* data_buf)
+{
+
+ uint32 datalen;
+uint32 ret;
+ char *tmp = (char*)data_buf;
+
+ //SDIOTRAN_ERR("\nrun to test_sdio_send_func!!!\n");
+
+ set_marlin_wakeup(chn,1);
+
+ while(!sdio_dev_chn_idle(chn));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(chn);
+ if(datalen)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!",chn,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!",chn,datalen);
+
+ }
+
+ SDIOTRAN_ERR("ap %d send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",chn,\
+ tmp[0],\
+ tmp[1],\
+ tmp[2],\
+ tmp[3], \
+ tmp[101], \
+ tmp[102], \
+ tmp[103], \
+ tmp[104], \
+ tmp[230], \
+ tmp[231], \
+ tmp[232], \
+ tmp[233] \
+ );
+
+ sdio_dev_write(chn,data_buf,datalen);
+ set_marlin_sleep(chn,1);
+
+
+}
+
+void case6_workq_handler(void)
+{
+ int i;
+
+ int read_chn = 0;
+ int datalen = 0;
+
+ read_chn = sdio_dev_get_read_chn();
+
+ if(-1 == read_chn)
+ return;
+
+
+ SDIOTRAN_ERR("ap recv: active_chn is %d!!!",read_chn);
+
+
+ for(i=0;i<BUF_LEN;i++)
+ *(data_ptr[read_chn-8]+i) = 0;
+
+
+ sdio_dev_read(read_chn,data_ptr[read_chn-8],&datalen);
+
+ SDIOTRAN_ERR("ap recv chn %d data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",read_chn,\
+ *(data_ptr[read_chn-8]+0),\
+ *(data_ptr[read_chn-8]+1),\
+ *(data_ptr[read_chn-8]+2),\
+ *(data_ptr[read_chn-8]+3), \
+ *(data_ptr[read_chn-8]+100), \
+ *(data_ptr[read_chn-8]+101), \
+ *(data_ptr[read_chn-8]+102), \
+ *(data_ptr[read_chn-8]+103), \
+ *(data_ptr[read_chn-8]+230), \
+ *(data_ptr[read_chn-8]+231), \
+ *(data_ptr[read_chn-8]+232), \
+ *(data_ptr[read_chn-8]+233) \
+ );
+
+ continue_send = 1;
+}
+
+
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j,k;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ for(i=0;i<10;i++){
+
+ data_ptr[i] = kmalloc(BUF_LEN,GFP_KERNEL);
+ if (NULL == data_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc send buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf%d ok!!!",i);
+
+ for(j=0;j<BUF_LEN;j++)
+ *(data_ptr[i]+j) = 0;
+
+ }
+
+ for(j=0,k=0;j<BUF_LEN;j++,k++)
+ *(data_ptr[0]+j) = (k<=255?k:(k=0,k));
+
+ while(1)
+ {
+ if(1 == continue_send)
+ {
+ continue_send = 0;
+ msleep(1000);
+ test_sdio_send_func(test_send_chn,data_ptr[test_send_chn]);
+
+
+ test_send_chn++;
+ if(8 == test_send_chn)
+ {
+ test_send_chn = 0;
+ }
+ }
+ else
+ msleep(1);
+ }
+ return 0;
+}
+
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+#endif//SDIO_TEST_CASE6
+
+#if defined(SDIO_TEST_CASE7)//test speed
+
+#define SEND_BUF_LEN 1024 //SDIO_TEST_CASE7
+
+char *data_send_ptr[17] = {0};
+
+
+static void test_sdio_send_func(int chn,void* data_buf)
+{
+
+ uint32 datalen;
+
+ char *tmp = (char*)data_buf;
+
+ //SDIOTRAN_ERR("\nrun to test_sdio_send_func!!!\n");
+
+ while(!sdio_dev_chn_idle(chn));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(chn);
+ if(datalen)
+ {
+ //SDIOTRAN_ERR("channel %d len is =%d!!\r\n",chn,datalen);
+ break;
+ }
+ else
+ ;//SDIOTRAN_ERR("channel %d len is =%d!!\r\n",chn,datalen);
+
+ }
+ /*
+ SDIOTRAN_ERR("\nap send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!\n",\
+ tmp[0],\
+ tmp[1],\
+ tmp[2],\
+ tmp[3], \
+ tmp[101], \
+ tmp[102], \
+ tmp[103], \
+ tmp[104], \
+ tmp[230], \
+ tmp[231], \
+ tmp[232], \
+ tmp[233] \
+ );*/
+
+ sdio_dev_write(chn,data_buf,datalen);
+
+}
+
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j,k;
+
+ static struct timeval start_time;
+ static struct timeval stop_time;
+ static signed long long elapsed_time;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ for(i=0;i<16;i++){
+
+ data_send_ptr[i] = kmalloc(SEND_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_send_ptr[i])
+ {
+ SDIOTRAN_ERR("kmalloc send buf%d err!!!",i);
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf%d ok!!!",i);
+
+ for(j=0,k=0;j<SEND_BUF_LEN;j++,k++)
+ *(data_send_ptr[i]+j) = ((k+i)<=255?(k+i):(k=0,k+i));
+
+ }
+ //set_blklen(1);
+
+
+ while(1)
+ {
+ for(i=0;i<16;i++)
+ {
+ do_gettimeofday(&start_time);
+
+ for(j=0;j<100;j++)
+ test_sdio_send_func(i,data_send_ptr[i]);
+
+ do_gettimeofday(&stop_time);
+ elapsed_time = timeval_to_ns(&stop_time) - timeval_to_ns(&start_time);
+ SDIOTRAN_ERR("Chn %d test elapsed_time is %lld!!!",i,elapsed_time);
+ elapsed_time = 0;
+ }
+ break;
+
+ SDIOTRAN_ERR("sdio test write finish!!!");
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+
+#endif//SDIO_TEST_CASE7
+
+#if defined(SDIO_TEST_CASE8)
+
+#define TEST_BUF_LEN 8192 //SDIO_TEST_CASE8
+
+char *data_test_ptr = NULL;
+
+static int gaole_test_count = 0;
+
+static struct timeval start_time;
+static struct timeval stop_time;
+static signed long long elapsed_time;
+
+static int last_chn = 0;
+bool stop_test = 0;
+
+void test_sdio_recv_func(void)
+{
+ int i;
+ int read_chn = 0;
+ int datalen = 0;
+
+
+
+ //SDIOTRAN_ERR("\nap recv: active_chn is 0x%x!!!\n",active_chn);
+
+
+ if(last_chn != read_chn)
+ {
+ last_chn = read_chn;
+ gaole_test_count = 0;
+
+ }
+ gaole_test_count ++;
+
+
+
+ //SDIOTRAN_ERR("\nap recv: read_datalen is 0x%x!!!\n",read_datalen);
+
+ //for(i=0;i<TEST_BUF_LEN;i++)
+ // data_test_ptr[i] = 0;
+
+ sdio_dev_read(read_chn,data_test_ptr,&datalen);
+
+ if(1 == gaole_test_count)
+ do_gettimeofday(&start_time);
+
+
+ if(100 == gaole_test_count)
+ {
+ do_gettimeofday(&stop_time);
+ elapsed_time = timeval_to_ns(&stop_time) - timeval_to_ns(&start_time);
+ SDIOTRAN_ERR("Chn %d test elapsed_time is %lld!!!",read_chn,elapsed_time);
+
+ elapsed_time = 0;
+ if(15 == read_chn)
+ stop_test = 1;
+ }
+ /*
+ SDIOTRAN_ERR("\ncase7:ap recv data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!\n",\
+ data_test_ptr[0],\
+ data_test_ptr[1],\
+ data_test_ptr[2],\
+ data_test_ptr[3], \
+ data_test_ptr[101], \
+ data_test_ptr[102], \
+ data_test_ptr[103], \
+ data_test_ptr[104], \
+ data_test_ptr[251], \
+ data_test_ptr[252], \
+ data_test_ptr[253], \
+ data_test_ptr[254] \
+ );*/
+}
+
+
+static void test_sdio_send_func(void)
+{
+
+ uint32 datalen;
+
+ SDIOTRAN_ERR("entry");
+
+ while(!sdio_dev_chn_idle(0));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(0);
+ if(datalen)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!",0,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!",0,datalen);
+
+ }
+
+ SDIOTRAN_ERR("ap send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",\
+ data_test_ptr[0],\
+ data_test_ptr[1],\
+ data_test_ptr[2],\
+ data_test_ptr[3], \
+ data_test_ptr[101], \
+ data_test_ptr[102], \
+ data_test_ptr[103], \
+ data_test_ptr[104], \
+ data_test_ptr[251], \
+ data_test_ptr[252], \
+ data_test_ptr[253], \
+ data_test_ptr[254] \
+ );
+
+ sdio_dev_write(0,data_test_ptr,datalen);
+
+}
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ data_test_ptr = kmalloc(TEST_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_test_ptr)
+ {
+ SDIOTRAN_ERR("kmalloc send buf err!!!");
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf ok!!!");
+
+ for(i=0,j=0;i<TEST_BUF_LEN;i++,j++)
+ data_test_ptr[i] = (j<=255?j:(j=0,j));
+
+ test_sdio_send_func();
+
+
+ while(1)
+ {
+ test_sdio_recv_func();
+
+ if(1 == stop_test)
+ break;
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+
+
+#endif//SDIO_TEST_CASE8
+
+
+#if defined(SDIO_TEST_CASE9)
+
+#define TEST_BUF_LEN 8192 //SDIO_TEST_CASE9
+
+#define TEST_SEND_CHN 0
+
+
+char *data_test_ptr = NULL;
+
+
+int active_chn = 0;
+int read_datalen = 0;
+static int gaole_test_count = 0;
+
+static struct timeval start_time;
+static struct timeval stop_time;
+static signed long long elapsed_time;
+
+static int last_chn = 0;
+
+void case9_workq_handler(void)
+{
+ int i;
+
+ active_chn = 0;
+ read_datalen = 0;
+
+ active_chn = sdio_dev_get_read_chn();
+ //SDIOTRAN_ERR("\nap recv: active_chn is 0x%x!!!\n",active_chn);
+
+ if(-1 == active_chn)
+ return;
+
+ if(last_chn != active_chn)
+ {
+ last_chn = active_chn;
+ gaole_test_count = 0;
+
+ }
+ gaole_test_count ++;
+
+
+
+ //SDIOTRAN_ERR("\nap recv: read_datalen is 0x%x!!!\n",read_datalen);
+
+ //for(i=0;i<TEST_BUF_LEN;i++)
+ // data_test_ptr[i] = 0;
+
+ sdio_dev_read(active_chn,data_test_ptr,&read_datalen);
+
+ if(2 == gaole_test_count)
+ do_gettimeofday(&start_time);
+
+
+ if(101 == gaole_test_count)
+ {
+ do_gettimeofday(&stop_time);
+ elapsed_time = timeval_to_ns(&stop_time) - timeval_to_ns(&start_time);
+ SDIOTRAN_ERR("Chn %d test elapsed_time is %lld!!!",active_chn,elapsed_time);
+ elapsed_time = 0;
+ }
+ /*
+ SDIOTRAN_ERR("\ncase7:ap recv data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!\n",\
+ data_test_ptr[0],\
+ data_test_ptr[1],\
+ data_test_ptr[2],\
+ data_test_ptr[3], \
+ data_test_ptr[101], \
+ data_test_ptr[102], \
+ data_test_ptr[103], \
+ data_test_ptr[104], \
+ data_test_ptr[251], \
+ data_test_ptr[252], \
+ data_test_ptr[253], \
+ data_test_ptr[254] \
+ );*/
+}
+
+
+static void test_sdio_send_func(void)
+{
+
+ uint32 datalen;
+
+ SDIOTRAN_ERR("entry");
+
+ while(!sdio_dev_chn_idle(TEST_SEND_CHN));
+
+ while(1)
+ {
+ datalen = sdio_dev_get_chn_datalen(TEST_SEND_CHN);
+ if(datalen)
+ {
+ SDIOTRAN_ERR("channel %d len is =%d!!",TEST_SEND_CHN,datalen);
+ break;
+ }
+ else
+ SDIOTRAN_ERR("channel %d len is =%d!!",TEST_SEND_CHN,datalen);
+
+ }
+
+ SDIOTRAN_ERR("ap send data: %d,%d,%d,%d %d,%d,%d,%d %d,%d,%d,%d!!!",\
+ data_test_ptr[0],\
+ data_test_ptr[1],\
+ data_test_ptr[2],\
+ data_test_ptr[3], \
+ data_test_ptr[101], \
+ data_test_ptr[102], \
+ data_test_ptr[103], \
+ data_test_ptr[104], \
+ data_test_ptr[251], \
+ data_test_ptr[252], \
+ data_test_ptr[253], \
+ data_test_ptr[254] \
+ );
+
+ sdio_dev_write(TEST_SEND_CHN,data_test_ptr,datalen);
+
+}
+
+
+static int gaole_test_thread(void *data)
+{
+ int i,j;
+
+ struct sched_param param = {.sched_priority = 90};
+
+ /*set the thread as a real time thread, and its priority is 90*/
+ sched_setscheduler(current, SCHED_RR, &param);
+
+ data_test_ptr = kmalloc(TEST_BUF_LEN,GFP_KERNEL);
+ if (NULL == data_test_ptr)
+ {
+ SDIOTRAN_ERR("kmalloc send buf err!!!");
+ return -1;
+ }
+
+ SDIOTRAN_DEBUG("kmalloc send buf ok!!!");
+
+ for(i=0,j=0;i<TEST_BUF_LEN;i++,j++)
+ data_test_ptr[i] = (j<=255?j:(j=0,j));
+
+
+ while(1)
+ {
+ msleep(10);
+ test_sdio_send_func();
+ break;
+ }
+
+ return 0;
+}
+
+void gaole_creat_test(void)
+{
+ struct task_struct * task;
+
+ task = kthread_create(gaole_test_thread, NULL, "GaoleTest");
+ if(0 != task)
+ wake_up_process(task);
+}
+#endif//SDIO_TEST_CASE9
+
+
diff --git a/drivers/misc/sdiodev/sdio_dev_test.h b/drivers/misc/sdiodev/sdio_dev_test.h
new file mode 100644
index 00000000..1259e9ec
--- /dev/null
+++ b/drivers/misc/sdiodev/sdio_dev_test.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 Spreadtrum Communications Inc.
+ *
+ * Filename : sdio_dev.h
+ * Abstract : This file is a implementation for itm sipc command/event function
+ *
+ * Authors : gaole.zhang
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __SDIO_DEV_TEST_H__
+#define __SDIO_DEV_TEST_H__
+
+void gaole_creat_test(void);
+
+
+#if defined(SDIO_TEST_CASE4)
+void case4_workq_handler(void);
+
+#endif
+
+
+#if defined(SDIO_TEST_CASE5)
+void case5_workq_handler(void);
+#endif
+
+#if defined(SDIO_TEST_CASE6)
+void case6_workq_handler(void);
+
+#endif
+
+
+
+#if defined(SDIO_TEST_CASE9)
+void case9_workq_handler(void);
+#endif
+
+
+#endif//__SDIO_DEV_TEST_H__