diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt index 82cf9b0d1c5e..643944fa8565 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt @@ -52,6 +52,11 @@ In the following, can be vdd (flash core voltage) or vdd-io (I/O voltag Tlmm pins are specified as and starting with eMMC5.0 as + - Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" + for following optional properties: + - pinctrl-names + - pinctrl-0, pinctrl-1,.. pinctrl-n + Example: aliases { @@ -76,6 +81,11 @@ Example: qcom,vdd-io-voltage-level = <1800000 2950000>; qcom,vdd-io-current-level = <6 22000>; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_on &sdc1_data_on>; + + qcom,bus-width = <4>; qcom,nonremovable; qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v"; @@ -99,6 +109,11 @@ Example: vdd-supply = <&pm8941_l21>; vdd-io-supply = <&pm8941_l13>; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_on &sdc2_data_on>; + + qcom,bus-width = <4>; qcom,pad-pull-on = <0x0 0x3 0x3>; /* no-pull, pull-up, pull-up */ diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 4ebbcfaa2fab..3b5f9032fcd5 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -245,11 +247,16 @@ struct sdhci_msm_pin_data { * = 0 if controller has dedicated MSM pads */ u8 is_gpio; - bool cfg_sts; struct sdhci_msm_gpio_data *gpio_data; struct sdhci_msm_pad_data *pad_data; }; +struct sdhci_pinctrl_data { + struct pinctrl *pctrl; + struct pinctrl_state *pins_active; + struct pinctrl_state *pins_sleep; +}; + struct sdhci_msm_bus_voting_data { struct msm_bus_scale_pdata *bus_pdata; unsigned int *bw_vecs; @@ -266,7 +273,9 @@ struct sdhci_msm_pltfm_data { unsigned long mmc_bus_width; struct sdhci_msm_slot_reg_data *vreg_data; bool nonremovable; + bool pin_cfg_sts; struct sdhci_msm_pin_data *pin_data; + struct sdhci_pinctrl_data *pctrl_data; u32 cpu_dma_latency_us; int status_gpio; /* card detection GPIO that is configured as IRQ */ struct sdhci_msm_bus_voting_data *voting_data; @@ -1049,19 +1058,44 @@ static int sdhci_msm_setup_pad(struct sdhci_msm_pltfm_data *pdata, bool enable) return 0; } +static int sdhci_msm_setup_pinctrl(struct sdhci_msm_pltfm_data *pdata, + bool enable) +{ + int ret = 0; + + if (enable) + ret = pinctrl_select_state(pdata->pctrl_data->pctrl, + pdata->pctrl_data->pins_active); + else + ret = pinctrl_select_state(pdata->pctrl_data->pctrl, + pdata->pctrl_data->pins_sleep); + + if (ret < 0) + pr_err("%s state for pinctrl failed with %d\n", + enable ? "Enabling" : "Disabling", ret); + + return ret; +} + static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable) { int ret = 0; - if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable)) + if (pdata->pin_cfg_sts == enable) { return 0; + } else if (pdata->pctrl_data) { + ret = sdhci_msm_setup_pinctrl(pdata, enable); + goto out; + } else if (!pdata->pin_data) { + return 0; + } if (pdata->pin_data->is_gpio) ret = sdhci_msm_setup_gpio(pdata, enable); else ret = sdhci_msm_setup_pad(pdata, enable); - +out: if (!ret) - pdata->pin_data->cfg_sts = enable; + pdata->pin_cfg_sts = enable; return ret; } @@ -1323,6 +1357,46 @@ out: return ret; } +static int sdhci_msm_parse_pinctrl_info(struct device *dev, + struct sdhci_msm_pltfm_data *pdata) +{ + struct sdhci_pinctrl_data *pctrl_data; + struct pinctrl *pctrl; + int ret = 0; + + /* Try to obtain pinctrl handle */ + pctrl = devm_pinctrl_get(dev); + if (IS_ERR(pctrl)) { + ret = PTR_ERR(pctrl); + goto out; + } + pctrl_data = devm_kzalloc(dev, sizeof(*pctrl_data), GFP_KERNEL); + if (!pctrl_data) { + dev_err(dev, "No memory for sdhci_pinctrl_data\n"); + ret = -ENOMEM; + goto out; + } + pctrl_data->pctrl = pctrl; + /* Look-up and keep the states handy to be used later */ + pctrl_data->pins_active = pinctrl_lookup_state( + pctrl_data->pctrl, "active"); + if (IS_ERR(pctrl_data->pins_active)) { + ret = PTR_ERR(pctrl_data->pins_active); + dev_err(dev, "Could not get active pinstates, err:%d\n", ret); + goto out; + } + pctrl_data->pins_sleep = pinctrl_lookup_state( + pctrl_data->pctrl, "sleep"); + if (IS_ERR(pctrl_data->pins_sleep)) { + ret = PTR_ERR(pctrl_data->pins_sleep); + dev_err(dev, "Could not get sleep pinstates, err:%d\n", ret); + goto out; + } + pdata->pctrl_data = pctrl_data; +out: + return ret; +} + #define GPIO_NAME_MAX_LEN 32 static int sdhci_msm_dt_parse_gpio_info(struct device *dev, struct sdhci_msm_pltfm_data *pdata) @@ -1331,6 +1405,16 @@ static int sdhci_msm_dt_parse_gpio_info(struct device *dev, struct sdhci_msm_pin_data *pin_data; struct device_node *np = dev->of_node; + ret = sdhci_msm_parse_pinctrl_info(dev, pdata); + if (!ret) { + goto out; + } else if (ret == -EPROBE_DEFER) { + dev_err(dev, "Pinctrl framework not registered, err:%d\n", ret); + goto out; + } else { + dev_err(dev, "Parsing Pinctrl failed with %d, falling back on GPIO lib\n", + ret); + } pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL); if (!pin_data) { dev_err(dev, "No memory for pin_data\n"); @@ -3133,8 +3217,8 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); - if (pdata->pin_data) - sdhci_msm_setup_pins(pdata, false); + sdhci_msm_setup_pins(pdata, true); + sdhci_msm_setup_pins(pdata, false); if (msm_host->msm_bus_vote.client_handle) { sdhci_msm_bus_cancel_work_and_set_vote(host, 0);