mmc: sdhci: Add support for pinctrl interface
Add support for Linux pin control framework while also supporting the older TLMM configuration for backward compatibility CRs-Fixed: 568232 Change-Id: Ib6b8f41fd6ced9aa62c980d7e4a73469603cbc5b Signed-off-by: Pratibhasagar V <pratibha@codeaurora.org>
This commit is contained in:
parent
d621731e5f
commit
5e8e7c2098
2 changed files with 105 additions and 6 deletions
|
@ -52,6 +52,11 @@ In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltag
|
|||
Tlmm pins are specified as <clk cmd data> and starting with eMMC5.0 as
|
||||
<clk cmd data rclk>
|
||||
|
||||
- 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 */
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/mmc/mmc.h>
|
||||
#include <linux/mmc/slot-gpio.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <mach/gpio.h>
|
||||
#include <mach/msm_bus.h>
|
||||
|
||||
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue