mmc: pwrseq: sd8787: Fix WILC CHIP_EN and RESETN toggling order
authorMarek Vasut <marex@denx.de>
Sat, 13 May 2023 19:23:52 +0000 (21:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 9 Jun 2023 08:34:22 +0000 (10:34 +0200)
commit 0b5d5c436a5c572a45f976cfd34a6741e143e5d9 upstream.

Chapter "5.3 Power-Up/Down Sequence" of WILC1000 [1] and WILC3000 [2]
states that CHIP_EN must be pulled HIGH first, RESETN second. Fix the
order of these signals in the driver.

Use the mmc_pwrseq_ops as driver data as the delay between signals is
specific to SDIO card type anyway.

[1] https://ww1.microchip.com/downloads/aemDocuments/documents/WSG/ProductDocuments/DataSheets/ATWILC1000-MR110XB-IEEE-802.11-b-g-n-Link-Controller-Module-DS70005326E.pdf
[2] https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/IEEE-802.11-b-g-n-Link-Controller-Module-with-Integrated-Bluetooth-5.0-DS70005327B.pdf

Fixes: b2832b96fcf5 ("mmc: pwrseq: sd8787: add support for wilc1000")
Signed-off-by: Marek Vasut <marex@denx.de>
Reviewed-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20230513192352.479627-1-marex@denx.de
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mmc/core/pwrseq_sd8787.c

index 2e120ad83020f8f51d4bb529b1a470f9de65bf78..0c5f5e371e1f8311f3454e1fc0c462cde2841787 100644 (file)
@@ -28,7 +28,6 @@ struct mmc_pwrseq_sd8787 {
        struct mmc_pwrseq pwrseq;
        struct gpio_desc *reset_gpio;
        struct gpio_desc *pwrdn_gpio;
-       u32 reset_pwrdwn_delay_ms;
 };
 
 #define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq)
@@ -39,7 +38,7 @@ static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host)
 
        gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
 
-       msleep(pwrseq->reset_pwrdwn_delay_ms);
+       msleep(300);
        gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
 }
 
@@ -51,17 +50,37 @@ static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host)
        gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
 }
 
+static void mmc_pwrseq_wilc1000_pre_power_on(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       /* The pwrdn_gpio is really CHIP_EN, reset_gpio is RESETN */
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
+       msleep(5);
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
+}
+
+static void mmc_pwrseq_wilc1000_power_off(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0);
+}
+
 static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = {
        .pre_power_on = mmc_pwrseq_sd8787_pre_power_on,
        .power_off = mmc_pwrseq_sd8787_power_off,
 };
 
-static const u32 sd8787_delay_ms = 300;
-static const u32 wilc1000_delay_ms = 5;
+static const struct mmc_pwrseq_ops mmc_pwrseq_wilc1000_ops = {
+       .pre_power_on = mmc_pwrseq_wilc1000_pre_power_on,
+       .power_off = mmc_pwrseq_wilc1000_power_off,
+};
 
 static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = {
-       { .compatible = "mmc-pwrseq-sd8787", .data = &sd8787_delay_ms },
-       { .compatible = "mmc-pwrseq-wilc1000", .data = &wilc1000_delay_ms },
+       { .compatible = "mmc-pwrseq-sd8787", .data = &mmc_pwrseq_sd8787_ops },
+       { .compatible = "mmc-pwrseq-wilc1000", .data = &mmc_pwrseq_wilc1000_ops },
        {/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match);
@@ -77,7 +96,6 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        match = of_match_node(mmc_pwrseq_sd8787_of_match, pdev->dev.of_node);
-       pwrseq->reset_pwrdwn_delay_ms = *(u32 *)match->data;
 
        pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
        if (IS_ERR(pwrseq->pwrdn_gpio))
@@ -88,7 +106,7 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
                return PTR_ERR(pwrseq->reset_gpio);
 
        pwrseq->pwrseq.dev = dev;
-       pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops;
+       pwrseq->pwrseq.ops = match->data;
        pwrseq->pwrseq.owner = THIS_MODULE;
        platform_set_drvdata(pdev, pwrseq);