mmc: Support sdmmc/uart_dbg auto switch
authorlintao <lintao@rock-chips.com>
Fri, 10 Oct 2014 01:44:02 +0000 (09:44 +0800)
committerlintao <lintao@rock-chips.com>
Fri, 10 Oct 2014 01:56:24 +0000 (09:56 +0800)
     Add pinctrl-names "udbg" in sdmmc blob, and drivers auto
switch io useage by card-detect tasklet routine. Only audi series need
it indeed now and ever.

Signed-off-by: lintao <lintao@rock-chips.com>
Acked-by: lw <lw@rock-chips.com>
Cc: phc <phc@rock-chips.com>
arch/arm/boot/dts/rk3036.dtsi
arch/arm/boot/dts/rk312x.dtsi
drivers/mmc/host/rk_sdmmc.c
include/linux/mmc/rk_mmc.h

index ebfe80b7420eba2216e9a873e371b555e1656afd..aae2e657041a688357b1dce4d9a9a5e25f7d0655 100755 (executable)
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default", "idle";
+               pinctrl-names = "default", "idle", "udbg";
                pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd &sdmmc0_dectn &sdmmc0_bus4>;
                pinctrl-1 = <&sdmmc0_gpio>;
+               pinctrl-2 = <&uart2_xfer>;
                cd-gpios = <&gpio1 GPIO_C1 GPIO_ACTIVE_HIGH>;/*CD GPIO*/
                clocks = <&clk_sdmmc0>, <&clk_gates5 10>;
                clock-names = "clk_mmc", "hclk_mmc";
index b4abbf6152c3232fe54f2281f3139a5756f17590..378761b4b720299ba18bd2267c0aac138ab0cbcb 100755 (executable)
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
-               pinctrl-names = "default", "idle";
+               pinctrl-names = "default", "idle", "udbg";
                pinctrl-0 = <&sdmmc0_clk &sdmmc0_cmd  &sdmmc0_dectn &sdmmc0_bus4>;
                pinctrl-1 = <&sdmmc0_gpio>;
+               pinctrl-2 = <&uart2_xfer>;
                clocks = <&clk_sdmmc0>, <&clk_gates5 10>;
                clock-names = "clk_mmc", "hclk_mmc";
                dmas = <&pdma 10>;
index cc1272daf03d0cedc370e7421b8c98911aed756c..0f50c70b6a13ed0fd71b7644a4126c6217a47ec8 100755 (executable)
@@ -2963,6 +2963,21 @@ static void dw_mci_work_routine_card(struct work_struct *work)
                        if(host->dma_ops && host->dma_ops->stop)
                                host->dma_ops->stop(host);
 
+                /* Card insert, switch data line to uart function, and vice verse.
+                 * ONLY audi chip need switched by software, using udbg tag in dts!
+                 */
+                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",
+                                                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",
+                                                mmc_hostname(host->mmc));
+                        }
+                }
+
                while (present != slot->last_detect_state) {
                        dev_dbg(&slot->mmc->class_dev, "card %s\n",
                                present ? "inserted" : "removed");
@@ -3261,6 +3276,64 @@ static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
 }
 #endif /* CONFIG_OF */
 
+/* @host: dw_mci host prvdata
+ * Init pinctrl for each platform. Usually we assign
+ * "defalut" tag for functional usage, "idle" tag for gpio
+ * state and "udbg" tag for uart_dbg if any.
+ */
+static void dw_mci_init_pinctrl(struct dw_mci *host)
+{
+        /* Fixme: DON'T TOUCH EMMC SETTING! */
+        if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC)
+                return;
+
+        /* Get pinctrl for DTS */
+        host->pinctrl = devm_pinctrl_get(host->dev);
+        if (IS_ERR(host->pinctrl)) {
+                dev_err(host->dev, "%s: No pinctrl used!\n",
+                        mmc_hostname(host->mmc));
+                return;
+        }
+
+        /* Lookup idle state */
+        host->pins_idle = pinctrl_lookup_state(host->pinctrl,
+                                                PINCTRL_STATE_IDLE);
+        if (IS_ERR(host->pins_idle)) {
+                dev_err(host->dev, "%s: No idle tag found!\n",
+                        mmc_hostname(host->mmc));
+        } else {
+                if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
+                        dev_err(host->dev, "%s: Idle pinctrl setting failed!\n",
+                                mmc_hostname(host->mmc));
+        }
+
+        /* Lookup default state */
+        host->pins_default = pinctrl_lookup_state(host->pinctrl,
+                                                        PINCTRL_STATE_DEFAULT);
+        if (IS_ERR(host->pins_default)) {
+                dev_err(host->dev, "%s: No default pinctrl found!\n",
+                        mmc_hostname(host->mmc));
+        } else {
+                if (pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
+                        dev_err(host->dev, "%s:  Default pinctrl setting failed!\n",
+                                mmc_hostname(host->mmc));
+        }
+
+        /* Sd card data0/1 may be used for uart_dbg, so were data2/3 for Jtag */
+        if ((host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD)) {
+                host->pins_udbg = pinctrl_lookup_state(host->pinctrl, "udbg");
+                if (IS_ERR(host->pins_udbg)) {
+                        dev_warn(host->dev, "%s: No udbg pinctrl found!\n",
+                                        mmc_hostname(host->mmc));
+                } else {
+                        if (pinctrl_select_state(host->pinctrl, host->pins_udbg) < 0)
+                                dev_err(host->dev, "%s: Udbg pinctrl setting failed!\n",
+                                        mmc_hostname(host->mmc));
+                }
+        }
+}
+
+
 static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
        struct mmc_host *mmc;
@@ -3464,42 +3537,11 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
         if (mmc->restrict_caps & RESTRICT_CARD_TYPE_SDIO)
                 clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
 
+        dw_mci_init_pinctrl(host);
         ret = mmc_add_host(mmc);
         if (ret)
                 goto err_setup_bus;
 
-        /* Pinctrl set default iomux state to fucntion port.
-         * Fixme: DON'T TOUCH EMMC SETTING!
-         */
-        if(!(host->mmc->restrict_caps & RESTRICT_CARD_TYPE_EMMC))
-        {
-                host->pinctrl = devm_pinctrl_get(host->dev);
-                if(IS_ERR(host->pinctrl)){
-                        printk("%s: Warning : No pinctrl used!\n",mmc_hostname(host->mmc));
-                }else{
-                        host->pins_idle= pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_IDLE);
-                        if(IS_ERR(host->pins_default)){
-                                printk("%s: Warning : No IDLE pinctrl matched!\n", mmc_hostname(host->mmc));
-                        }
-                        else
-                        { 
-                                if(pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
-                                        printk("%s: Warning :  Idle pinctrl setting failed!\n", mmc_hostname(host->mmc));  
-                        }
-        
-                        host->pins_default = pinctrl_lookup_state(host->pinctrl,PINCTRL_STATE_DEFAULT);
-                        if(IS_ERR(host->pins_default)){
-                                printk("%s: Warning : No default pinctrl matched!\n", mmc_hostname(host->mmc));
-                        }
-                        else
-                        {
-                                if(pinctrl_select_state(host->pinctrl, host->pins_default) < 0)
-                                        printk("%s: Warning :  Default pinctrl setting failed!\n", mmc_hostname(host->mmc));
-                        }
-                }
-        }
-    
-    
 #if defined(CONFIG_DEBUG_FS)
        dw_mci_init_debugfs(slot);
 #endif
index 34a0413d351b0bd11f0055a300d6b3a0f7b82fdb..b7fc0e128bde6fc916ba7b7fa81572261cc3f0d2 100755 (executable)
@@ -206,15 +206,17 @@ struct dw_mci {
        /* Workaround flags */
        u32                     quirks;
        bool        irq_state;
-       u32                     svi_flags; /*switch voltage interrupt flags*/
+       u32                     svi_flags; /* Switch voltage interrupt flags */
        struct regulator        *vmmc;  /* Power regulator */
        unsigned long           irq_flags; /* IRQ flags */
        int                     irq;
-       u32         cmd_rto;     /*cmd response timeout hold times*/
-       struct pinctrl *pinctrl; /*Pinctrl state*/
-       struct pinctrl_state    *pins_default;
-       struct pinctrl_state    *pins_idle;
-       struct pinctrl_state    *pins_sleep;
+       u32         cmd_rto;     /* Cmd response timeout hold times */
+       struct pinctrl *pinctrl;
+
+       /* Pinctrl state */
+       struct pinctrl_state    *pins_default; /* Function port */
+       struct pinctrl_state    *pins_idle;    /* Gpio port */
+       struct pinctrl_state    *pins_udbg;    /* uart_dbg port */
 };
 
 /* DMA ops for Internal/External DMAC interface */