Skip to content

Commit

Permalink
mmc: sdhci-of-at91: force card detect value for non removable devices
Browse files Browse the repository at this point in the history
When the device is non removable, the card detect signal is often used
for another purpose i.e. muxed to another SoC peripheral or used as a
GPIO. It could lead to wrong behaviors depending the default value of
this signal if not muxed to the SDHCI controller.

Fixes: bb5f8ea ("mmc: sdhci-of-at91: introduce driver for the Atmel SDMMC")
Signed-off-by: Ludovic Desroches <[email protected]>
Acked-by: Adrian Hunter <[email protected]>
Cc: <[email protected]>
Signed-off-by: Ulf Hansson <[email protected]>
  • Loading branch information
ldesroches authored and storulf committed Aug 3, 2017
1 parent 16f73eb commit 7a1e3f1
Showing 1 changed file with 34 additions and 1 deletion.
35 changes: 34 additions & 1 deletion drivers/mmc/host/sdhci-of-at91.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

#define SDMMC_MC1R 0x204
#define SDMMC_MC1R_DDR BIT(3)
#define SDMMC_MC1R_FCD BIT(7)
#define SDMMC_CACR 0x230
#define SDMMC_CACR_CAPWREN BIT(0)
#define SDMMC_CACR_KEY (0x46 << 8)
Expand All @@ -43,6 +44,15 @@ struct sdhci_at91_priv {
struct clk *mainck;
};

static void sdhci_at91_set_force_card_detect(struct sdhci_host *host)
{
u8 mc1r;

mc1r = readb(host->ioaddr + SDMMC_MC1R);
mc1r |= SDMMC_MC1R_FCD;
writeb(mc1r, host->ioaddr + SDMMC_MC1R);
}

static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
Expand Down Expand Up @@ -110,10 +120,18 @@ void sdhci_at91_set_uhs_signaling(struct sdhci_host *host, unsigned int timing)
sdhci_set_uhs_signaling(host, timing);
}

static void sdhci_at91_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);

if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
sdhci_at91_set_force_card_detect(host);
}

static const struct sdhci_ops sdhci_at91_sama5d2_ops = {
.set_clock = sdhci_at91_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.reset = sdhci_at91_reset,
.set_uhs_signaling = sdhci_at91_set_uhs_signaling,
.set_power = sdhci_at91_set_power,
};
Expand Down Expand Up @@ -324,6 +342,21 @@ static int sdhci_at91_probe(struct platform_device *pdev)
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
}

/*
* If the device attached to the MMC bus is not removable, it is safer
* to set the Force Card Detect bit. People often don't connect the
* card detect signal and use this pin for another purpose. If the card
* detect pin is not muxed to SDHCI controller, a default value is
* used. This value can be different from a SoC revision to another
* one. Problems come when this default value is not card present. To
* avoid this case, if the device is non removable then the card
* detection procedure using the SDMCC_CD signal is bypassed.
* This bit is reset when a software reset for all command is performed
* so we need to implement our own reset function to set back this bit.
*/
if (host->mmc->caps & MMC_CAP_NONREMOVABLE)
sdhci_at91_set_force_card_detect(host);

pm_runtime_put_autosuspend(&pdev->dev);

return 0;
Expand Down

0 comments on commit 7a1e3f1

Please sign in to comment.