mmc: usdhi6rol0: add pinctrl to set pin drive strength
authorLars Persson <lars.persson@axis.com>
Wed, 27 Apr 2016 15:21:29 +0000 (17:21 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 2 May 2016 08:36:06 +0000 (10:36 +0200)
Some boards need different pin drive strength for the UHS mode. Add an
optional pinctrl setting with two pin states covering UHS speeds and
other speeds.

Signed-off-by: Lars Persson <larper@axis.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/usdhi6rol0.c

index 743e2005ab17d510218dd5e04e0f513806f8a57f..1bd5f1a18d4e239784082a2ddfca46d2492345e7 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/mmc/sdio.h>
 #include <linux/module.h>
 #include <linux/pagemap.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/string.h>
@@ -198,6 +199,11 @@ struct usdhi6_host {
        struct dma_chan *chan_rx;
        struct dma_chan *chan_tx;
        bool dma_active;
+
+       /* Pin control */
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *pins_default;
+       struct pinctrl_state *pins_uhs;
 };
 
 /*                     I/O primitives                                  */
@@ -1147,12 +1153,35 @@ static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable)
        }
 }
 
+static int usdhi6_set_pinstates(struct usdhi6_host *host, int voltage)
+{
+       if (IS_ERR(host->pins_uhs))
+               return 0;
+
+       switch (voltage) {
+       case MMC_SIGNAL_VOLTAGE_180:
+       case MMC_SIGNAL_VOLTAGE_120:
+               return pinctrl_select_state(host->pinctrl,
+                                           host->pins_uhs);
+
+       default:
+               return pinctrl_select_state(host->pinctrl,
+                                           host->pins_default);
+       }
+}
+
 static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        int ret;
 
        ret = mmc_regulator_set_vqmmc(mmc, ios);
+       if (ret < 0)
+               return ret;
 
+       ret = usdhi6_set_pinstates(mmc_priv(mmc), ios->signal_voltage);
+       if (ret)
+               dev_warn_once(mmc_dev(mmc),
+                             "Failed to set pinstate err=%d\n", ret);
        return ret;
 }
 
@@ -1740,6 +1769,25 @@ static int usdhi6_probe(struct platform_device *pdev)
        host->wait      = USDHI6_WAIT_FOR_REQUEST;
        host->timeout   = msecs_to_jiffies(4000);
 
+       host->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (IS_ERR(host->pinctrl)) {
+               ret = PTR_ERR(host->pinctrl);
+               goto e_free_mmc;
+       }
+
+       host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs");
+       if (!IS_ERR(host->pins_uhs)) {
+               host->pins_default = pinctrl_lookup_state(host->pinctrl,
+                                                         PINCTRL_STATE_DEFAULT);
+
+               if (IS_ERR(host->pins_default)) {
+                       dev_err(dev,
+                               "UHS pinctrl requires a default pin state.\n");
+                       ret = PTR_ERR(host->pins_default);
+                       goto e_free_mmc;
+               }
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(host->base)) {