Merge remote-tracking branch 'origin/develop-3.0-rk30' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / host / rk29_sdmmc.c
index 708cc8bbb59cbb2267cc215d1af2ccb5f691aa67..625973bcce534cd52ee2cb6f1799a6a2a7175868 100755 (executable)
@@ -65,16 +65,21 @@ int debug_level = 5;
 
 #define RK29_SDMMC_ERROR_FLAGS         (SDMMC_INT_FRUN | SDMMC_INT_HLE )
 
+#if defined(CONFIG_ARCH_RK29) 
 #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 )
 
+#elif defined(CONFIG_ARCH_RK30)
+#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 )
+#endif
 
 #define RK29_SDMMC_SEND_START_TIMEOUT   3000  //The time interval from the time SEND_CMD to START_CMD_BIT cleared.
 #define RK29_ERROR_PRINTK_INTERVAL      200   //The time interval between the two printk for the same error. 
 #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.2.14 The last modify date is 2011-11-17,modifyed by XBW." 
+#define RK29_SDMMC_VERSION "Ver.3.03 The last modify date is 2012-03-23,modifyed by XBW."
 
 #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD) 
 #define RK29_CTRL_SDMMC_ID   0  //mainly used by SDMMC
@@ -86,6 +91,7 @@ int debug_level = 5;
 #define RK29_CTRL_SDIO2_ID   2  
 #endif
 
+#define SDMMC_CLOCK_TEST     0
 #define RK29_SDMMC_NOTIFY_REMOVE_INSERTION /* use sysfs to notify the removal or insertion of sd-card*/
 //#define RK29_SDMMC_LIST_QUEUE            /* use list-queue for multi-card*/
 
@@ -293,8 +299,6 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
         return count;
     }
     
-    spin_lock(&host->lock);
-    
     //envalue the address of host base on input-parameter.
     if( !strncmp(buf,"sd-" , strlen("sd-")) )
     {
@@ -302,7 +306,7 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
         if(!host)
         {
             printk("%s..%d.. fail to call progress_store because the host is null. ==xbw==\n",__FUNCTION__,__LINE__);
-            goto progress_store_out;
+            return count;
         }
     }    
     else if(  !strncmp(buf,"sdio1-" , strlen("sdio1-")) )
@@ -311,7 +315,7 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
         if(!host)
         {
             printk("%s..%d.. fail to call progress_store because the host-sdio1 is null. ==xbw==\n",__FUNCTION__,__LINE__);
-            goto progress_store_out;
+            return count;
         }
     }
     else if(  !strncmp(buf,"sdio2-" , strlen("sdio2-")) )
@@ -320,15 +324,17 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
         if(!host)
         {
             printk("%s..%d.. fail to call progress_store because the host-sdio2 is null. ==xbw==\n",__FUNCTION__,__LINE__);
-            goto progress_store_out;
+            return count;
         }
     }
     else
     {
         printk("%s..%d.. You want to use sysfs for SDMMC but input-parameter is wrong.====xbw====\n",__FUNCTION__,__LINE__);
-        goto progress_store_out;//return count;
+        return count;
     }
 
+    spin_lock(&host->lock);
+
     if(strncmp(buf,oldbuf , strlen(buf)))
     {
            printk(".%d.. MMC0 receive the message %s from VOLD.====xbw[%s]====\n", __LINE__, buf, host->dma_name);
@@ -343,6 +349,24 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
     #if !defined(CONFIG_USE_SDMMC0_FOR_WIFI_DEVELOP_BOARD)
     if(RK29_CTRL_SDMMC_ID == host->pdev->id)
     {
+#if 1 //to wirte log in log-file-system during the stage of umount. Modifyed by xbw at 2011-12-26
+        if(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting")))
+        {
+            if(unmounting_times++%10 == 0)
+            {
+                printk(".%d.. MMC0 receive the message Unmounting(waitTimes=%d) from VOLD.====xbw[%s]====\n", \
+                    __LINE__, unmounting_times, host->dma_name);
+            }
+
+            if(0 == host->mmc->re_initialized_flags)
+                mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
+        }
+        else if(!strncmp(buf, "sd-Idle-Unmounted", strlen("sd-Idle-Unmounted")))
+        {
+            if(0 == host->mmc->re_initialized_flags)
+                mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
+        }
+#else
         if(!strncmp(buf, "sd-Unmounting", strlen("sd-Unmounting")))
         {
             if(unmounting_times++%10 == 0)
@@ -352,7 +376,8 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
             }
             host->mmc->re_initialized_flags = 0;
             mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(RK29_SDMMC_REMOVAL_DELAY*2));
-        }
+        } 
+#endif
         else if( !strncmp(buf, "sd-No-Media", strlen("sd-No-Media")))
         {
             printk(".%d.. MMC0 receive the message No-Media from VOLD. waitTimes=%d ====xbw[%s]====\n" ,\
@@ -433,7 +458,6 @@ ssize_t rk29_sdmmc_progress_store(struct kobject *kobj, struct kobj_attribute *a
         }
     }
     
-progress_store_out:
     spin_unlock(&host->lock);
     
     return count;
@@ -445,7 +469,7 @@ struct kobj_attribute mmc_reset_attrs =
 {
         .attr = {
                 .name = "rescan",
-                .mode = 0766},
+                .mode = 0764},
         .show = NULL,
         .store = rk29_sdmmc_progress_store,
 };
@@ -1095,8 +1119,8 @@ static int rk29_sdmmc_prepare_write_data(struct rk29_sdmmc *host, struct mmc_dat
             {
                        host->dodma = 0;
                                
-                   printk("%s..%d... CMD%d setupDMA failure!!!!!  ==xbw[%s]==\n", \
-                                               __FUNCTION__, __LINE__, host->cmd->opcode, host->dma_name);
+                   printk("%s..%d... CMD%d setupDMA failure!!!!! pre_cmd=%d  ==xbw[%s]==\n", \
+                                               __FUNCTION__, __LINE__, host->cmd->opcode,host->old_cmd, host->dma_name);
                    
                                host->errorstep = 0x81;
 
@@ -1407,8 +1431,11 @@ int rk29_sdmmc_reset_controller(struct rk29_sdmmc *host)
     }
    
     /* reset */
+#if defined(CONFIG_ARCH_RK29)     
     rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET ));
-
+#elif defined(CONFIG_ARCH_RK30)
+    rk29_sdmmc_write(host->regs, SDMMC_CTRL,(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET));
+#endif
     timeOut = 1000;
     value = rk29_sdmmc_read(host->regs, SDMMC_CTRL);
     while (( value & (SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_RESET)) && (timeOut > 0))
@@ -1542,14 +1569,28 @@ static int rk29_sdmmc_control_clock(struct rk29_sdmmc *host, bool enable)
     if(RK29_CTRL_SDMMC_ID == host->pdev->id)
     { 
         //SDMMC use low-power mode
+        #if SDMMC_CLOCK_TEST
         if (enable)
         {
-            value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE);
+            value = (SDMMC_CLKEN_ENABLE);
         }
         else
         {
-            value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_DISABLE);
+            value = (SDMMC_CLKEN_DISABLE);
         }
+        
+        #else
+        {
+            if (enable)
+            {
+                value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_ENABLE);
+            }
+            else
+            {
+                value = (SDMMC_CLKEN_LOW_PWR | SDMMC_CLKEN_DISABLE);
+            }
+        }
+        #endif
     }
     else
     {
@@ -2866,8 +2907,8 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id)
            host->error_times = 0;
 
            #if 1
-           del_timer_sync(&host->request_timer);
-               del_timer_sync(&host->DTO_timer);
+           del_timer(&host->request_timer);
+               del_timer(&host->DTO_timer);
            rk29_sdmmc_dealwith_timeout(host);              
             #endif
                            
@@ -2957,7 +2998,7 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id)
                                __FUNCTION__, __LINE__,host->cmd->opcode,pending, host->dma_name);
         
         rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_DTO); 
-        del_timer_sync(&host->DTO_timer); //delete the timer for INT_DTO
+        del_timer(&host->DTO_timer); //delete the timer for INT_DTO
 
        host->data_status |= status;
 
@@ -2978,6 +3019,16 @@ static irqreturn_t rk29_sdmmc_interrupt(int irq, void *dev_id)
         goto Exit_INT;
     }
 
+#if defined(CONFIG_ARCH_RK30)
+    if(pending & SDMMC_INT_UNBUSY) 
+    {
+      //  printk("%d..%s:  ==test=== xbw======\n", __LINE__, __FUNCTION__);
+       // rk29_sdmmc_regs_printk(host);
+        rk29_sdmmc_write(host->regs, SDMMC_RINTSTS,SDMMC_INT_UNBUSY); 
+        goto Exit_INT;
+    }
+#endif
+
     if (pending & SDMMC_INT_RXDR) 
     {  
         xbwprintk(6, "%s..%d..  SDMMC_INT_RXDR  INT=0x%x   ====xbw[%s]====\n", \
@@ -3017,7 +3068,7 @@ static void rk29_sdmmc_detect_change(unsigned long data)
    
        smp_rmb();
 
-    if(RK29_CTRL_SDMMC_ID == host->pdev->id)
+    if((RK29_CTRL_SDMMC_ID == host->pdev->id) && rk29_sdmmc_get_cd(host->mmc))
     {
         host->mmc->re_initialized_flags =1;
     }
@@ -3127,7 +3178,7 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
 #endif 
 
        host->clk = clk_get(&pdev->dev, "mmc");
-       
+
 #if RK29_SDMMC_DEFAULT_SDIO_FREQ
     clk_set_rate(host->clk,SDHC_FPP_FREQ);
 #else    
@@ -3137,7 +3188,7 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
            clk_set_rate(host->clk,RK29_MAX_SDIO_FREQ); 
 
 #endif
-               
+
        clk_enable(host->clk);
        clk_enable(clk_get(&pdev->dev, "hclk_mmc"));
 
@@ -3226,6 +3277,9 @@ static int rk29_sdmmc_probe(struct platform_device *pdev)
     memcpy(host->dma_name, pdata->dma_name, 8);    
        host->use_dma = pdata->use_dma;
 
+    xbwprintk(7,"%s..%s..%d..***********  Bus clock= %d Khz  ====xbw[%s]===\n",\
+        __FILE__, __FUNCTION__,__LINE__,clk_get_rate(host->clk)/1000, host->dma_name);
+
        /*DMA init*/
        if(host->use_dma)
        {
@@ -3415,6 +3469,7 @@ static int __exit rk29_sdmmc_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
+#if defined(CONFIG_ARCH_RK29)
 static irqreturn_t det_keys_isr(int irq, void *dev_id)
 {
        struct rk29_sdmmc *host = dev_id;
@@ -3450,6 +3505,43 @@ static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
        rk29_mux_api_set(GPIO2A2_SDMMC0DETECTN_NAME, GPIO2L_SDMMC0_DETECT_N);
 }
 
+#elif defined(CONFIG_ARCH_RK30)
+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(RK30_PIN3_PB6)?"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;
+       rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_GPIO3B6);
+       gpio_request(RK30_PIN3_PB6, "sd_detect");
+       gpio_direction_input(RK30_PIN3_PB6);
+
+       host->gpio_irq = gpio_to_irq(RK30_PIN3_PB6);
+       ret = request_irq(host->gpio_irq, det_keys_isr,
+                                           (gpio_get_value(RK30_PIN3_PB6))?IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING,
+                                           "sd_detect",
+                                           host);
+       
+       enable_irq_wake(host->gpio_irq);
+
+       return ret;
+}
+static void rk29_sdmmc_sdcard_resume(struct rk29_sdmmc *host)
+{
+       disable_irq_wake(host->gpio_irq);
+       free_irq(host->gpio_irq,host);
+       gpio_free(RK30_PIN3_PB6);
+       rk29_mux_api_set(GPIO3B6_SDMMC0DETECTN_NAME, GPIO3B_SDMMC0_DETECT_N);
+}
+
+#endif
 
 
 static int rk29_sdmmc_suspend(struct platform_device *pdev, pm_message_t state)