Merge branch 'rk_develop-3.10' into rk_develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / host / rk_sdmmc.c
index e4488a8de558e6f94202c398b9a860fb1a5dfdd7..ae0a86ccdec8fe849b8c414e5f277a7413f26c50 100755 (executable)
@@ -46,6 +46,8 @@
 #include <linux/clk-private.h>
 #include <linux/rockchip/cpu.h>
 #include <linux/rfkill-wlan.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <linux/log2.h>
 #include "rk_sdmmc.h"
 #include "rk_sdmmc_dbg.h"
@@ -1539,15 +1541,21 @@ static int dw_mci_set_sdio_status(struct mmc_host *mmc, int val)
         spin_unlock_bh(&host->lock);
 
         if(test_bit(DW_MMC_CARD_PRESENT, &slot->flags)){
-                if(__clk_is_enabled(host->hclk_mmc) == false)
+                if (!IS_ERR(host->hpclk_mmc) &&
+                        __clk_is_enabled(host->hpclk_mmc) == false)
+                        clk_prepare_enable(host->hpclk_mmc);
+               if (__clk_is_enabled(host->hclk_mmc) == false)
                         clk_prepare_enable(host->hclk_mmc);
-                if(__clk_is_enabled(host->clk_mmc) == false)
+                if (__clk_is_enabled(host->clk_mmc) == false)
                         clk_prepare_enable(host->clk_mmc);
         }else{
-                if(__clk_is_enabled(host->clk_mmc) == true)
+                if (__clk_is_enabled(host->clk_mmc) == true)
                         clk_disable_unprepare(slot->host->clk_mmc);
-                if(__clk_is_enabled(host->hclk_mmc) == true)
+                if (__clk_is_enabled(host->hclk_mmc) == true)
                         clk_disable_unprepare(slot->host->hclk_mmc);
+               if (!IS_ERR(host->hpclk_mmc) &&
+                       __clk_is_enabled(host->hpclk_mmc) == true)
+                       clk_disable_unprepare(slot->host->hpclk_mmc);
         }
 
         mmc_detect_change(slot->mmc, 20);
@@ -1582,7 +1590,7 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
                        }
                         msleep(10);
                         if (gpio_val == gpio_get_value(gpio_cd)) {
-                                gpio_cd = gpio_get_value(gpio_cd) == 0 ? 1 : 0;
+                                gpio_cd = (gpio_val == 0 ? 1 : 0);
                                 if (gpio_cd == 0) {
                                         irq_set_irq_type(irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT);
                                        /* Enable force_jtag wihtout card in slot, ONLY for NCD-package */
@@ -1728,12 +1736,12 @@ static void dw_mci_hw_reset(struct mmc_host *mmc)
        */
        mci_writel(slot->host, PWREN, 0x0);
        mci_writel(slot->host, RST_N, 0x0);
-       dsb();
+       dsb(sy);
        udelay(10); /* 10us for bad quality eMMc. */
 
        mci_writel(slot->host, PWREN, 0x1);
        mci_writel(slot->host, RST_N, 0x1);
-       dsb();
+       dsb(sy);
        usleep_range(500, 1000); /* at least 500(> 200us) */
 }
 
@@ -1823,12 +1831,17 @@ static void dw_mci_do_grf_io_domain_switch(struct dw_mci *host, u32 voltage)
                         break;
         }
 
-        if(cpu_is_rk3288()){
+        if (cpu_is_rk3288()) {
                 if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)      
                         grf_writel((voltage << 7) | (1 << 23), RK3288_GRF_IO_VSEL);
                 else
                         return ;
-        }else{
+        } else if (host->cid == DW_MCI_TYPE_RK3368) {
+               if(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)
+                        regmap_write(host->grf, 0x900, (voltage << 6) | (1 << 22));    
+               else
+                       return;
+       } else {
                 MMC_DBG_ERR_FUNC(host->mmc,"%s : unknown chip [%s]\n",
                                         __FUNCTION__, mmc_hostname(host->mmc));
         }
@@ -3007,11 +3020,11 @@ static void dw_mci_work_routine_card(struct work_struct *work)
                 if (!(IS_ERR(host->pins_udbg)) && !(IS_ERR(host->pins_default))) {
                          if (present) {
                                 if (pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
-                                        dev_err(host->dev, "%s: Udbg pinctrl setting failed!\n",
+                                        dev_err(host->dev, "%s: Default pinctrl setting failed!\n",
                                                 mmc_hostname(host->mmc));
                          } else {
                                 if (pinctrl_select_state(host->pinctrl, host->pins_udbg) < 0)
-                                        dev_err(host->dev, "%s: Default pinctrl setting failed!\n",
+                                        dev_err(host->dev, "%s: Udbg pinctrl setting failed!\n",
                                                 mmc_hostname(host->mmc));
                         }
                 }
@@ -3469,6 +3482,14 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
                 }
         }
 
+       if (host->cid == DW_MCI_TYPE_RK3368) {
+               if (IS_ERR(host->grf))
+                       pr_err("rk_sdmmc: dts couldn't find grf regmap for 3368\n");
+               else
+                       /* Disable force_jtag */
+                       regmap_write(host->grf, 0x43c, (1<<13)<<16 | (0 << 13));
+       }
+
         /* We assume only low-level chip use gpio_cd */
         if ((soc_is_rk3126() || soc_is_rk3126b() || soc_is_rk3036()) &&
                 (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)) {
@@ -3664,6 +3685,9 @@ static void dw_mci_init_dma(struct dw_mci *host)
                        __func__);
                goto no_dma;
        }
+       #ifdef CONFIG_ARM64
+       memset(host->sg_cpu, 0, PAGE_SIZE);
+       #endif
 
        /* Determine which DMA interface to use */
 #if defined(CONFIG_MMC_DW_IDMAC)
@@ -3874,6 +3898,14 @@ int dw_mci_probe(struct dw_mci *host)
        else
                host->data_offset = DATA_240A_OFFSET;
 
+       //hpclk enable
+       host->hpclk_mmc= devm_clk_get(host->dev, "hpclk_mmc");
+       if (IS_ERR(host->hpclk_mmc)) {
+               dev_err(host->dev, "failed to get hpclk_mmc\n");
+       } else {
+               clk_prepare_enable(host->hpclk_mmc);
+       }
+
         //hclk enable
         host->hclk_mmc= devm_clk_get(host->dev, "hclk_mmc");
         if (IS_ERR(host->hclk_mmc)) {
@@ -4069,12 +4101,11 @@ err_dmaunmap:
        }
 
 err_clk_mmc:
-    if (!IS_ERR(host->clk_mmc))
+       if (!IS_ERR(host->clk_mmc))
                clk_disable_unprepare(host->clk_mmc);
 err_hclk_mmc:
-    if (!IS_ERR(host->hclk_mmc))
+       if (!IS_ERR(host->hclk_mmc))
                clk_disable_unprepare(host->hclk_mmc);
-               
        return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -4102,21 +4133,23 @@ void dw_mci_remove(struct dw_mci *host)
         if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)
                 unregister_pm_notifier(&host->mmc->pm_notify);
 
-        if(host->use_dma && host->dma_ops->exit)
+        if (host->use_dma && host->dma_ops->exit)
                 host->dma_ops->exit(host);
 
         if (gpio_is_valid(slot->cd_gpio))
                 dw_mci_of_free_cd_gpio_irq(host->dev, slot->cd_gpio, host->mmc);
 
-        if(host->vmmc){
+        if (host->vmmc){
                 regulator_disable(host->vmmc);
                 regulator_put(host->vmmc);
         }
-       if(!IS_ERR(host->clk_mmc))
+       if (!IS_ERR(host->clk_mmc))
                 clk_disable_unprepare(host->clk_mmc);
 
-        if(!IS_ERR(host->hclk_mmc))
+        if (!IS_ERR(host->hclk_mmc))
                 clk_disable_unprepare(host->hclk_mmc);
+       if (!IS_ERR(host->hpclk_mmc))
+               clk_disable_unprepare(host->hpclk_mmc);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
@@ -4129,6 +4162,8 @@ EXPORT_SYMBOL(dw_mci_remove);
 extern int get_wifi_chip_type(void);
 int dw_mci_suspend(struct dw_mci *host)
 {
+       int present = dw_mci_get_cd(host->mmc);
+
        if((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) &&
                (get_wifi_chip_type() == WIFI_ESP8089 || get_wifi_chip_type() > WIFI_AP6XXX_SERIES))
                return 0;
@@ -4139,9 +4174,12 @@ int dw_mci_suspend(struct dw_mci *host)
         /*only for sdmmc controller*/
         if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
                 disable_irq(host->irq);
-                if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
-                        MMC_DBG_ERR_FUNC(host->mmc, "Idle pinctrl setting failed! [%s]",
-                                                mmc_hostname(host->mmc));
+               if (present) {
+                       if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
+                               MMC_DBG_ERR_FUNC(host->mmc,
+                                       "Idle pinctrl setting failed! [%s]",
+                                       mmc_hostname(host->mmc));
+               }
 
                 mci_writel(host, RINTSTS, 0xFFFFFFFF);
                 mci_writel(host, INTMASK, 0x00);
@@ -4159,19 +4197,19 @@ EXPORT_SYMBOL(dw_mci_suspend);
 
 int dw_mci_resume(struct dw_mci *host)
 {
-       int i, ret, retry_cnt = 0;
+       int i, ret;
        u32 regs;
-        struct dw_mci_slot *slot;
+       struct dw_mci_slot *slot;
+       int present = dw_mci_get_cd(host->mmc);
 
-       if((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) &&
-               (get_wifi_chip_type() == WIFI_ESP8089 || get_wifi_chip_type() > WIFI_AP6XXX_SERIES))
+       if ((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) &&
+               (get_wifi_chip_type() == WIFI_ESP8089 ||
+                       get_wifi_chip_type() > WIFI_AP6XXX_SERIES))
                return 0;
 
-
-    
         if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO) {
                 slot = mmc_priv(host->mmc);
-                if(!test_bit(DW_MMC_CARD_PRESENT, &slot->flags))
+                if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags))
                        return 0;
         }
 
@@ -4182,9 +4220,29 @@ int dw_mci_resume(struct dw_mci *host)
                         disable_irq_wake(host->mmc->slot.cd_irq);
                         mmc_gpio_free_cd(host->mmc);
                 }
-               if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
-                        MMC_DBG_ERR_FUNC(host->mmc, "Default pinctrl setting failed! [%s]",
-                                                mmc_hostname(host->mmc));
+
+               if (!present) {
+                       if (!IS_ERR(host->pins_udbg)) {
+                               if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
+                                       MMC_DBG_ERR_FUNC(host->mmc,
+                                               "Idle pinctrl setting failed! [%s]",
+                                               mmc_hostname(host->mmc));
+                               if (pinctrl_select_state(host->pinctrl, host->pins_udbg) < 0)
+                                       MMC_DBG_ERR_FUNC(host->mmc,
+                                               "%s: Udbg pinctrl setting failed! [%s]",
+                                               mmc_hostname(host->mmc));
+                       } else {
+                               if (pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
+                                       MMC_DBG_ERR_FUNC(host->mmc,
+                                               "Default pinctrl setting failed! [%s]",
+                                               mmc_hostname(host->mmc));
+                       }
+               } else {
+                       if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
+                               MMC_DBG_ERR_FUNC(host->mmc,
+                                       "Default pinctrl setting failed! [%s]",
+                                       mmc_hostname(host->mmc));
+               }
 
                /* Disable jtag*/
                if(cpu_is_rk3288())
@@ -4230,7 +4288,7 @@ int dw_mci_resume(struct dw_mci *host)
        mci_writel(host, INTMASK, regs);
        mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
        /*only for sdmmc controller*/
-       if((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)&& (!retry_cnt)){
+       if((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)){
                enable_irq(host->irq);  
        }