Skip to content

Commit

Permalink
mmc: mmci_sdmmc: Implement signal voltage callbacks
Browse files Browse the repository at this point in the history
To prepare the voltage switch procedure, the VSWITCHEN bit must be set
before sending the CMD11. To confirm completion of voltage switch, the
VSWEND flag must be checked.

Signed-off-by: Ludovic Barre <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Ulf Hansson <[email protected]>
  • Loading branch information
ludovicbarre authored and storulf committed Mar 24, 2020
1 parent 7577316 commit 94b94a9
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 0 deletions.
4 changes: 4 additions & 0 deletions drivers/mmc/host/mmci.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
/* Extended status bits for the STM32 variants */
#define MCI_STM32_BUSYD0 BIT(20)
#define MCI_STM32_BUSYD0END BIT(21)
#define MCI_STM32_VSWEND BIT(25)

#define MMCICLEAR 0x038
#define MCI_CMDCRCFAILCLR (1 << 0)
Expand All @@ -182,6 +183,9 @@
#define MCI_ST_SDIOITC (1 << 22)
#define MCI_ST_CEATAENDC (1 << 23)
#define MCI_ST_BUSYENDC (1 << 24)
/* Extended clear bits for the STM32 variants */
#define MCI_STM32_VSWENDC BIT(25)
#define MCI_STM32_CKSTOPC BIT(26)

#define MMCIMASK0 0x03c
#define MCI_CMDCRCFAILMASK (1 << 0)
Expand Down
43 changes: 43 additions & 0 deletions drivers/mmc/host/mmci_stm32_sdmmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#define DLYB_CFGR_UNIT_MAX 127

#define DLYB_LNG_TIMEOUT_US 1000
#define SDMMC_VSWEND_TIMEOUT_US 10000

struct sdmmc_lli_desc {
u32 idmalar;
Expand Down Expand Up @@ -265,6 +266,7 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
struct mmc_ios ios = host->mmc->ios;
struct sdmmc_dlyb *dlyb = host->variant_priv;

/* adds OF options */
pwr = host->pwr_reg_add;

sdmmc_dlyb_input_ck(dlyb);
Expand All @@ -291,6 +293,10 @@ static void mmci_sdmmc_set_pwrreg(struct mmci_host *host, unsigned int pwr)
writel(MCI_IRQENABLE | host->variant->start_err,
host->base + MMCIMASK0);

/* preserves voltage switch bits */
pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN |
MCI_STM32_VSWITCH);

/*
* After a power-cycle state, we must set the SDMMC in
* Power-off. The SDMMC_D[7:0], SDMMC_CMD and SDMMC_CK are
Expand Down Expand Up @@ -456,6 +462,41 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
return sdmmc_dlyb_phase_tuning(host, opcode);
}

static void sdmmc_pre_sig_volt_vswitch(struct mmci_host *host)
{
/* clear the voltage switch completion flag */
writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR);
/* enable Voltage switch procedure */
mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN);
}

static int sdmmc_post_sig_volt_switch(struct mmci_host *host,
struct mmc_ios *ios)
{
unsigned long flags;
u32 status;
int ret = 0;

if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
spin_lock_irqsave(&host->lock, flags);
mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH);
spin_unlock_irqrestore(&host->lock, flags);

/* wait voltage switch completion while 10ms */
ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS,
status,
(status & MCI_STM32_VSWEND),
10, SDMMC_VSWEND_TIMEOUT_US);

writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC,
host->base + MMCICLEAR);
mmci_write_pwrreg(host, host->pwr_reg &
~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH));
}

return ret;
}

static struct mmci_host_ops sdmmc_variant_ops = {
.validate_data = sdmmc_idma_validate_data,
.prep_data = sdmmc_idma_prep_data,
Expand All @@ -467,6 +508,8 @@ static struct mmci_host_ops sdmmc_variant_ops = {
.set_clkreg = mmci_sdmmc_set_clkreg,
.set_pwrreg = mmci_sdmmc_set_pwrreg,
.busy_complete = sdmmc_busy_complete,
.pre_sig_volt_switch = sdmmc_pre_sig_volt_vswitch,
.post_sig_volt_switch = sdmmc_post_sig_volt_switch,
};

void sdmmc_variant_init(struct mmci_host *host)
Expand Down

0 comments on commit 94b94a9

Please sign in to comment.