1. The accuracy enhanced gpio_detect_card, such as RK2926.
authorxbw <xbw@rock-chips.com>
Mon, 20 May 2013 02:59:14 +0000 (10:59 +0800)
committerxbw <xbw@rock-chips.com>
Mon, 20 May 2013 02:59:14 +0000 (10:59 +0800)
2. To enhance removeal-insert card, voltage stability.
3. add the suspend-resume process for SDIO module.
4. 4. close the clock when the sdio go into suspend. refer to No3.
5. 5. add the wake-up-host for wifi when use CONFIG_RK29_SDIO_IRQ_FROM_GPIO.

arch/arm/plat-rk/include/plat/board.h
arch/arm/plat-rk/rk-sdmmc-ops.c
drivers/mmc/core/sdio.c
drivers/mmc/host/rk29_sdmmc.c

index 4529b1ea789a5432555e37f7642e56223bf36f73..43ee181cd1840f71cc0ff44cddebdbd44fb7592b 100755 (executable)
@@ -168,7 +168,9 @@ struct rk29_sdmmc_platform_data {
        int enable_sd_wakeup;
        int write_prt;
        int write_prt_enalbe_level;
-       unsigned int sdio_INT_gpio; 
+       unsigned int sdio_INT_gpio;
+       int sdio_INT_level;
+#define USE_SDIO_INT_LEVEL  /*In order to be compatible with old project, those who do not define the member  sdio_INT_level */
        struct rksdmmc_gpio   det_pin_info;
         int (*sd_vcc_reset)(void);
 };
index 784b7585c99420cae7773325095b20adfdd1f0e8..2d66bc459f178744cd90c9ce1e9c8b5a6d8a8da5 100644 (file)
@@ -624,9 +624,9 @@ static struct rksdmmc_gpio_board rksdmmc1_gpio_init = {
 * define the varaious operations for SDMMC module
 * Generally only the author of SDMMC module will modify this section.
 *************************************************************************/
-
 #if !defined(CONFIG_SDMMC_RK29_OLD)    
-static void rk29_sdmmc_gpio_open(int device_id, int on)
+//static void rk29_sdmmc_gpio_open(int device_id, int on)
+void rk29_sdmmc_gpio_open(int device_id, int on)
 {
     switch(device_id)
     {
index e1bf6274cf0c9e677825e3fab4d036ea64a5e1e2..41f400cb5e57ac1cd0ef549f5f5bb646253dfd76 100755 (executable)
@@ -689,8 +689,15 @@ static int mmc_sdio_resume(struct mmc_host *host)
                }
        }
 
+#if defined(CONFIG_MTK_COMBO) && defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
+    /* sdio_funcs are NOT resumed yet! Signal irq only in host driver. */
+    //
+    // do not to  wake up sdio_irq_thread; noted by xbw at 2013-05-08
+    //
+#else
        if (!err && host->sdio_irqs)
                wake_up_process(host->sdio_irq_thread);
+#endif
        mmc_release_host(host);
 
        /*
index a2d2149af78c5c10003645253bd62ace71588517..6f928009734571fbcd5ea5889e78479a0c0b614c 100755 (executable)
@@ -70,6 +70,17 @@ int debug_level = 5;
 #define SDMMC_USE_INT_UNBUSY     0///1 
 #endif
 
+/*
+** You can set the macro to true, if some module wants to use this feature, which is about SDIO suspend-resume.
+** As the following example.
+** added by xbw at 2013-05-08
+*/
+#if defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
+#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME    1
+#else
+#define RK_SDMMC_USE_SDIO_SUSPEND_RESUME    0
+#endif
+
 #define RK29_SDMMC_ERROR_FLAGS         (SDMMC_INT_FRUN | SDMMC_INT_HLE )
 
 #if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
@@ -95,7 +106,7 @@ int debug_level = 5;
 #define RK29_SDMMC_WAIT_DTO_INTERNVAL   4500  //The time interval from the CMD_DONE_INT to DTO_INT
 #define RK29_SDMMC_REMOVAL_DELAY        2000  //The time interval from the CD_INT to detect_timer react.
 
-#define RK29_SDMMC_VERSION "Ver.5.03 The last modify date is 2013-02-21"
+#define RK29_SDMMC_VERSION "Ver.5.05 The last modify date is 2013-05-08"
 
 #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) 
 #define RK29_CTRL_SDMMC_ID   0  //mainly used by SDMMC
@@ -253,6 +264,7 @@ struct rk29_sdmmc {
 #ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO
     unsigned int sdio_INT_gpio;
     unsigned int sdio_irq;
+    unsigned long trigger_level;
 #endif
 
 #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT) || defined(CONFIG_SDMMC1_RK29_WRITE_PROTECT)
@@ -1484,6 +1496,9 @@ static void rk29_sdmmc_submit_data(struct rk29_sdmmc *host, struct mmc_data *dat
                if (sg->offset & 3 || sg->length & 3) 
                {
                        data->error = -EILSEQ;
+                       printk("%s..%d..CMD%d(arg=0x%x), data->blksz=%d, data->blocks=%d   [%s]\n", \
+                               __FUNCTION__, __LINE__, host->cmd->opcode,\
+                               host->cmd->arg,data->blksz, data->blocks,  host->dma_name);
                        return ;
                }
            }
@@ -1564,7 +1579,9 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
 {
        struct rk29_sdmmc *host = mmc_priv(mmc);
        u32 cdetect=1;
-
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)   
+    int i=0,cdetect1=0, cdetect2=0;
+#endif    
     switch(host->pdev->id)
     {
         case 0:
@@ -1573,7 +1590,16 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
             if(host->det_pin.io == INVALID_GPIO)
                return 1;
 
-            cdetect = gpio_get_value(host->det_pin.io);          
+            for(i=0;i<5;i++)
+            {
+                udelay(10);
+                cdetect1 = gpio_get_value(host->det_pin.io);  
+                udelay(10);
+                cdetect2 = gpio_get_value(host->det_pin.io); 
+                if(cdetect1 == cdetect2)
+                    break;
+            }
+            cdetect = cdetect2;          
             if(host->det_pin.enable)
                 cdetect = cdetect?1:0;
             else
@@ -2377,7 +2403,7 @@ static void rk29_sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 }
 
 
-
+extern void rk29_sdmmc_gpio_open(int device_id, int on);
 static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
     int timeout = 250;
@@ -2425,8 +2451,11 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                         rk29_sdmmc_reset_controller(host);
                        }
 
-                    //power-off 
-                    gpio_direction_output(host->gpio_power_en, !(host->gpio_power_en_level));               
+                  
+                               rk29_sdmmc_gpio_open(0, 0);                             
+                               //power-off 
+                    gpio_direction_output(host->gpio_power_en, !(host->gpio_power_en_level));  
+                               goto out;
                }
 
                break;          
@@ -2463,7 +2492,8 @@ static void rk29_sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
 
-    if(!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags) || (RK29_CTRL_SDIO1_ID != host->pdev->id)))
+    if((!(test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags))|| !rk29_sdmmc_get_cd(host->mmc))
+        &&(RK29_CTRL_SDIO1_ID != host->pdev->id))
         goto out; //exit the set_ios directly if the SDIO is not present. 
         
        if(host->ctype != ios->bus_width)
@@ -2564,11 +2594,22 @@ static void rk29_sdmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct rk29_sdmmc *host = mmc_priv(mmc);
                
 #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)    
-    if(enable) 
+    if(enable)
+    {
         enable_irq(host->sdio_irq);
-        //enable_irq_wake(host->sdio_irq);
-    else 
+        
+        #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
+        enable_irq_wake(host->sdio_irq);
+        #endif
+    }
+    else
+    {
         disable_irq_nosync(host->sdio_irq);
+        
+        #if !defined(CONFIG_MTK_COMBO_DRIVER_VERSION_JB2)
+        disable_irq_wake(host->sdio_irq);
+        #endif
+    }
 
 #else
     spin_lock_irqsave(&host->lock, flags);
@@ -3441,6 +3482,11 @@ static void rk29_sdmmc1_check_status(unsigned long data)
     {        
         if (status) 
         {
+            #if RK_SDMMC_USE_SDIO_SUSPEND_RESUME
+               if(host->pdev->id == RK29_CTRL_SDIO1_ID)
+                      host->mmc->pm_caps |= (MMC_PM_KEEP_POWER|MMC_PM_WAKE_SDIO_IRQ);
+                   #endif
+                   
             rk29_sdmmc_hw_init(host);
             set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
             mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(200));
@@ -3594,6 +3640,9 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
     if(RK29_CTRL_SDIO1_ID == host->pdev->id)
     {
         host->sdio_INT_gpio = pdata->sdio_INT_gpio;
+        #ifdef USE_SDIO_INT_LEVEL
+        host->trigger_level = pdata->sdio_INT_level;
+        #endif
     }
 #endif
 
@@ -3826,7 +3875,11 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
         gpio_pull_updown(host->sdio_INT_gpio, 0); //disable default internal pull-down
 
         host->sdio_irq = gpio_to_irq(host->sdio_INT_gpio);
+        #ifdef USE_SDIO_INT_LEVEL
+        trigger_flags = (host->trigger_level==GPIO_HIGH)?IRQF_TRIGGER_HIGH:IRQF_TRIGGER_LOW;
+        #else
         trigger_flags = IRQF_TRIGGER_LOW;
+        #endif
         //printk("%d..%s  sdio interrupt gpio level=%lu   ====[%s]====\n", __LINE__, __FUNCTION__, trigger_flags, host->dma_name);
         ret = request_irq(host->sdio_irq, rk29_sdmmc_sdio_irq_cb,
                     trigger_flags,
@@ -3839,8 +3892,10 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
                                __FUNCTION__, __LINE__, ret, host->dma_name);
             host->errorstep = 0x8D;
             goto err_dmaunmap;
-        } 
-        disable_irq_nosync(host->sdio_irq);   
+        }
+        
+        disable_irq_nosync(host->sdio_irq);
+        enable_irq_wake(host->sdio_irq);
     }
 
 #endif
@@ -4034,6 +4089,22 @@ static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
                        dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n");
 #endif    
     }
+#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME    
+    else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id))
+    {
+        if (mmc)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
+            ret = mmc_suspend_host(mmc);
+#else
+            ret = mmc_suspend_host(mmc, state);
+#endif
+        if(!ret)
+        {
+            clk_disable(host->clk);
+            clk_disable(clk_get(&pdev->dev, "hclk_mmc"));
+        }
+    }
+#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME
 
     return ret;
 }
@@ -4055,7 +4126,19 @@ static int rk29_sdmmc_resume(struct platform_device *pdev)
             
                ret = mmc_resume_host(mmc);
        }
-       }
+    }
+#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME        
+    else if(host && host->pdev && (RK29_CTRL_SDIO1_ID == host->pdev->id))
+    {
+        if (mmc)
+        {
+               clk_enable(host->clk);
+              clk_enable(clk_get(&pdev->dev, "hclk_mmc"));
+                mdelay(20);
+               ret = mmc_resume_host(mmc);
+       }
+    } 
+#endif // --#if RK_SDMMC_USE_SDIO_SUSPEND_RESUME
 
        return ret;
 }