SDMMC:use gpio-interrupt to detect card.
authorxbw <xbw@rock-chips.com>
Thu, 27 Sep 2012 13:23:07 +0000 (21:23 +0800)
committerxbw <xbw@rock-chips.com>
Thu, 27 Sep 2012 13:23:07 +0000 (21:23 +0800)
Please attention to define the detect-pin name and the insert-card voltage in your board_xxxx.c.

arch/arm/mach-rk2928/board-rk2928-a720.c
arch/arm/plat-rk/include/plat/board.h
drivers/mmc/host/Kconfig
drivers/mmc/host/rk29_sdmmc.c

index 06eee08cac54b54e30bae860191785f665184fd9..48cdf18a3a676d4587f6e019b06f6b36e19a3de7 100755 (executable)
@@ -520,6 +520,10 @@ static void rkusb_wifi_power(int on) {
 
 #define RK29SDK_WIFI_SDIO_CARD_DETECT_N    RK2928_PIN0_PB2
 
+#define RK29SDK_SD_CARD_DETECT_N        RK2928_PIN2_PA7  //According to your own project to set the value of card-detect-pin.
+#define RK29SDK_SD_CARD_INSERT_LEVEL    GPIO_LOW         // set the voltage of insert-card. Please pay attention to the default setting.
+
+
 #endif //endif ---#ifdef CONFIG_SDMMC_RK29
 
 #ifdef CONFIG_SDMMC0_RK29
@@ -527,7 +531,13 @@ static int rk29_sdmmc0_cfg_gpio(void)
 {
        rk29_sdmmc_set_iomux(0, 0xFFFF);
 
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+    rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_GPIO1C1);
+   // gpio_request(RK29SDK_SD_CARD_DETECT_N, "sd-detect");
+   // gpio_direction_output(RK29SDK_SD_CARD_DETECT_N,GPIO_HIGH);//set mmc0-data1 to high.
+#else
        rk30_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN);
+#endif 
 
 #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT)
        gpio_request(SDMMC0_WRITE_PROTECT_PIN, "sdmmc-wp");
@@ -557,7 +567,14 @@ struct rk29_sdmmc_platform_data default_sdmmc0_data = {
 #else
        .use_dma = 0,
 #endif
-       .detect_irq = RK2928_PIN1_PC1,  // INVALID_GPIO
+
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+    .detect_irq = RK29SDK_SD_CARD_DETECT_N,
+    .insert_card_level = RK29SDK_SD_CARD_INSERT_LEVEL,
+#else
+       .detect_irq = INVALID_GPIO,
+#endif
+
        .enable_sd_wakeup = 0,
 
 #if defined(CONFIG_SDMMC0_RK29_WRITE_PROTECT)
index 68cb8fdc9c35f7bb5d5773b683a17719088d6401..6178c3231f758558c11a350d0d8f0c46e86047c5 100644 (file)
@@ -83,6 +83,45 @@ struct rk29fb_info {
        void (*set_screen_info)(struct rk29fb_screen *screen, struct rk29lcd_info *lcd_info );
 };
 
+struct rksdmmc_iomux {
+    char    *name;  //set the MACRO of gpio
+    int     fgpio;
+    int     fmux;
+};
+
+struct rksdmmc_gpio {
+    int     io;                             //set the address of gpio
+    char    name[64];   //
+    int     enable;  // disable = !enable   //set the default value,i.e,GPIO_HIGH or GPIO_LOW
+    struct rksdmmc_iomux  iomux;
+};
+
+
+struct rksdmmc_gpio_board {
+    struct rksdmmc_gpio   clk_gpio;
+    struct rksdmmc_gpio   cmd_gpio;
+    struct rksdmmc_gpio   data0_gpio;
+    struct rksdmmc_gpio   data1_gpio;    
+    struct rksdmmc_gpio   data2_gpio;
+    struct rksdmmc_gpio   data3_gpio;
+   
+    struct rksdmmc_gpio   detect_irq;    
+    struct rksdmmc_gpio   power_en_gpio;   
+    struct rksdmmc_gpio   write_prt;
+    struct rksdmmc_gpio   sdio_irq_gpio;
+};
+
+
+struct rksdmmc_gpio_wifi_moudle {
+    struct rksdmmc_gpio   power_n;    
+    struct rksdmmc_gpio   reset_n;   
+    struct rksdmmc_gpio   vddio;
+    struct rksdmmc_gpio   bgf_int_b;
+    struct rksdmmc_gpio   wifi_int_b;
+    struct rksdmmc_gpio   gps_sync;
+};
+
+
 struct rk29_sdmmc_platform_data {
        unsigned int host_caps;
        unsigned int host_ocr_avail;
@@ -94,6 +133,7 @@ struct rk29_sdmmc_platform_data {
        int (*status)(struct device *);
        int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id);
        int detect_irq;
+       int insert_card_level;
        int enable_sd_wakeup;
        int write_prt;
        unsigned int sdio_INT_gpio; //add gpio INT for sdio interrupt.Modifed by xbw at 2012-08-09
index fabf9737c020be845dca790a7ed58af089f1185e..961ee2f49d0df33371a87a00f4c972bee4f104d8 100755 (executable)
@@ -32,6 +32,16 @@ if SDMMC_RK29
                         You will add the feature of write-protect for sdmmc-card if you say Yes.
                         Please note that this feature requires hardware support.
        
+       config SDMMC0_RK29_SDCARD_DET_FROM_GPIO
+        bool "use the gpio-interrupt to detect card"
+        default n
+        depends on SDMMC0_RK29
+            help
+                  You can detect the presence of card by the gpio-interrupt if you say Yes.
+                          Of course, you must define the pin-name for the detect-pin.
+
+                          If you say No, then detect the card by register interrupt.
+
 #      config USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD
 #          depends on SDMMC0_RK29
 #              bool "Switch the driver SDMMC0 for the debug of wifi_develop_board."
index b2e9e9611210a2e3df6d52905cf2ef52fa516c35..7c4b67f43ac75d099899e8487c99cdf2e0a63a9f 100755 (executable)
@@ -86,12 +86,22 @@ int debug_level = 5;
 
 #define RK29_SDMMC_ERROR_FLAGS         (SDMMC_INT_FRUN | SDMMC_INT_HLE )
 
-#if SDMMC_USE_INT_UNBUSY
-#define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
-#define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+    #if SDMMC_USE_INT_UNBUSY
+    #define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS )
+    #define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+    #else
+    #define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS )
+    #define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+    #endif
 #else
-#define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
-#define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+    #if SDMMC_USE_INT_UNBUSY
+    #define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
+    #define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | SDMMC_INT_UNBUSY |RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+    #else
+    #define RK29_SDMMC_INTMASK_USEDMA   (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD)
+    #define RK29_SDMMC_INTMASK_USEIO    (SDMMC_INT_CMD_DONE | SDMMC_INT_DTO | RK29_SDMMC_ERROR_FLAGS | SDMMC_INT_CD| SDMMC_INT_TXDR | SDMMC_INT_RXDR )
+    #endif
 #endif
 
 #define RK29_SDMMC_SEND_START_TIMEOUT   3000  //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
@@ -99,7 +109,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.4.06 The last modify date is 2012-09-26"
+#define RK29_SDMMC_VERSION "Ver.4.07 The last modify date is 2012-09-27"
 
 #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) 
 #define RK29_CTRL_SDMMC_ID   0  //mainly used by SDMMC
@@ -242,10 +252,10 @@ struct rk29_sdmmc {
     unsigned int            complete_done;
     unsigned int            retryfunc;
     
-#ifdef CONFIG_PM
     int gpio_irq;
        int gpio_det;
-#endif
+       int insert_level;
+       struct delayed_work             work;
 
 #ifdef CONFIG_RK29_SDIO_IRQ_FROM_GPIO
     unsigned int sdio_INT_gpio;
@@ -1564,16 +1574,23 @@ static int rk29_sdmmc_get_cd(struct mmc_host *mmc)
     switch(host->pdev->id)
     {
         case 0:
-        {
-            #ifdef CONFIG_PM
-               if(host->gpio_det == INVALID_GPIO)
-                       return 1;
-            #endif
-
+        {            
+         #if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+            if(host->gpio_det == INVALID_GPIO)
+               return 1;
+
+            cdetect = gpio_get_value(host->gpio_det);          
+            if(host->insert_level)
+                cdetect = cdetect?1:0;
+            else
+                cdetect = cdetect?0:1;
+                
+         #else
                cdetect = rk29_sdmmc_read(host->regs, SDMMC_CDETECT);
 
             cdetect = (cdetect & SDMMC_CARD_DETECT_N)?0:1;
-
+         #endif
+         
             break;
         }        
 
@@ -3463,13 +3480,75 @@ static void rk29_sdmmc1_status_notify_cb(int card_present, void *dev_id)
 }
 
 
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+static irqreturn_t det_keys_isr(int irq, void *dev_id);
+static void rk29_sdmmc_detect_change_work(struct work_struct *work)
+{
+       int ret;
+    struct rk29_sdmmc *host =  container_of(work, struct rk29_sdmmc, work.work);
+
+    rk28_send_wakeup_key();
+       rk29_sdmmc_detect_change(host);
+
+       free_irq(host->gpio_irq, host);
+       ret = request_irq(host->gpio_irq,det_keys_isr,
+                        rk29_sdmmc_get_cd(host->mmc)?IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING,
+                        "sd_detect",
+                        host);
+}
+#endif
+
+static irqreturn_t det_keys_isr(int irq, void *dev_id)
+{
+       struct rk29_sdmmc *host = dev_id;
+
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+       bool present;
+       bool present_old;
+
+    present = rk29_sdmmc_get_cd(host->mmc);
+    present_old = test_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+
+    if(present != present_old)
+    {
+        printk(KERN_INFO "\n******************\n%s: present Old=%d ==> New=%d . [%s]\n",\
+                __FUNCTION__,  present_old, present,  host->dma_name);
+
+       disable_irq_nosync(host->gpio_irq);
+
+        #if 1
+        del_timer(&host->request_timer);
+        del_timer(&host->DTO_timer);
+        rk29_sdmmc_dealwith_timeout(host);              
+        #endif
+            
+       if(present)
+       {
+           set_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+               schedule_delayed_work(&host->work, msecs_to_jiffies(500));
+       }
+       else
+       {
+           clear_bit(RK29_SDMMC_CARD_PRESENT, &host->flags);
+            host->mmc->re_initialized_flags = 0;
+               schedule_delayed_work(&host->work, 0);
+        }
+    }
+#else
+       dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n",
+               gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert");
+       rk29_sdmmc_detect_change((unsigned long)dev_id);
+#endif 
+       return IRQ_HANDLED;
+}
+
 static int rk29_sdmmc_probe(struct platform_device *pdev)
 {
        struct mmc_host                 *mmc;
        struct rk29_sdmmc               *host;
        struct resource                 *regs;
        struct rk29_sdmmc_platform_data *pdata;
-       //int                           irq;
+    int level_value;
        int                             ret = 0;
 
 #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)    
@@ -3514,10 +3593,12 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
        host->mrq = NULL;
        host->new_mrq = NULL;
        host->irq_state = true;
-       
-#ifdef CONFIG_PM
+
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)   
     host->gpio_det = pdata->detect_irq;
+    host->insert_level = pdata->insert_card_level;
 #endif
+
     host->set_iomux = pdata->set_iomux;
 
 #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)
@@ -3711,6 +3792,32 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
            goto err_dmaunmap;
        }
 
+#if defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+    if(INVALID_GPIO != host->gpio_det)
+    {
+        INIT_DELAYED_WORK(&host->work, rk29_sdmmc_detect_change_work);
+        ret = gpio_request(host->gpio_det, "sd_detect");
+               if(ret < 0) {
+                       dev_err(&pdev->dev, "gpio_request error\n");
+                       goto err_dmaunmap;
+               }
+               gpio_direction_input(host->gpio_det);
+
+        level_value = gpio_get_value(host->gpio_det);       
+        printk("%d..%s:   level value =%d    ======trace detect =====\n",__LINE__ ,__FUNCTION__, level_value);
+        
+               host->gpio_irq = gpio_to_irq(host->gpio_det);
+        ret = request_irq(host->gpio_irq, det_keys_isr,
+                                           level_value?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
+                                           "sd_detect",
+                                           host);
+               if(ret < 0) {
+                       dev_err(&pdev->dev, "gpio request_irq error\n");
+                       goto err_dmaunmap;
+               }
+    }
+#endif
+       
 #if defined(CONFIG_RK29_SDIO_IRQ_FROM_GPIO)
     if(RK29_CTRL_SDIO1_ID == host->pdev->id)
     {
@@ -3870,18 +3977,10 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
-static irqreturn_t det_keys_isr(int irq, void *dev_id)
-{
-       struct rk29_sdmmc *host = dev_id;
-       dev_info(&host->pdev->dev, "sd det_gpio changed(%s), send wakeup key!\n",
-               gpio_get_value(RK29_SDMMC0DETECTN_GPIO)?"removed":"insert");
-       rk29_sdmmc_detect_change((unsigned long)dev_id);
-
-       return IRQ_HANDLED;
-}
 static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
 {
        int ret = 0;
+#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
        
 #if defined(CONFIG_ARCH_RK29)
     rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_GPIO2A2);
@@ -3895,6 +3994,7 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
 
        gpio_request(RK29_SDMMC0DETECTN_GPIO, "sd_detect");
        gpio_direction_input(RK29_SDMMC0DETECTN_GPIO);
+
        host->gpio_irq = gpio_to_irq(RK29_SDMMC0DETECTN_GPIO);
        ret = request_irq(host->gpio_irq, det_keys_isr,
                                            (gpio_get_value(RK29_SDMMC0DETECTN_GPIO))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
@@ -3902,10 +4002,16 @@ static int rk29_sdmmc_sdcard_suspend(struct rk29_sdmmc *host)
                                            host);
        
        enable_irq_wake(host->gpio_irq);
+       
+#endif  ////----end of #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+
        return ret;
 }
+
 static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
 {
+#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
+
        disable_irq_wake(host->gpio_irq);
        free_irq(host->gpio_irq,host);
        gpio_free(RK29_SDMMC0DETECTN_GPIO);
@@ -3919,6 +4025,8 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
 #elif defined(CONFIG_ARCH_RK2928)
        rk29_mux_api_set(GPIO1C1_MMC0_DETN_NAME, GPIO1C_MMC0_DETN);
 #endif 
+
+#endif ////----end of #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
 }
 
 static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
@@ -3936,8 +4044,10 @@ static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)
             ret = mmc_suspend_host(mmc, state);
 #endif
 
+#if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
         if(rk29_sdmmc_sdcard_suspend(host) < 0)
                        dev_info(&host->pdev->dev, "rk29_sdmmc_sdcard_suspend error\n");
+#endif    
     }
 
     return ret;
@@ -3953,7 +4063,11 @@ static int rk29_sdmmc_resume(struct platform_device *pdev)
     {
         if (mmc)
         {
+            
+            #if !defined(CONFIG_SDMMC0_RK29_SDCARD_DET_FROM_GPIO)
             rk29_sdmmc_sdcard_resume(host);    
+            #endif
+            
                ret = mmc_resume_host(mmc);
        }
        }