Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: mmci_sdmmc: Implement signal voltage callbacks

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 <ludovic.barre@st.com>
Link: https://lore.kernel.org/r/20200128090636.13689-9-ludovic.barre@st.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Ludovic Barre and committed by
Ulf Hansson
94b94a93 75773165

+47
+4
drivers/mmc/host/mmci.h
··· 165 165 /* Extended status bits for the STM32 variants */ 166 166 #define MCI_STM32_BUSYD0 BIT(20) 167 167 #define MCI_STM32_BUSYD0END BIT(21) 168 + #define MCI_STM32_VSWEND BIT(25) 168 169 169 170 #define MMCICLEAR 0x038 170 171 #define MCI_CMDCRCFAILCLR (1 << 0) ··· 183 182 #define MCI_ST_SDIOITC (1 << 22) 184 183 #define MCI_ST_CEATAENDC (1 << 23) 185 184 #define MCI_ST_BUSYENDC (1 << 24) 185 + /* Extended clear bits for the STM32 variants */ 186 + #define MCI_STM32_VSWENDC BIT(25) 187 + #define MCI_STM32_CKSTOPC BIT(26) 186 188 187 189 #define MMCIMASK0 0x03c 188 190 #define MCI_CMDCRCFAILMASK (1 << 0)
+43
drivers/mmc/host/mmci_stm32_sdmmc.c
··· 32 32 #define DLYB_CFGR_UNIT_MAX 127 33 33 34 34 #define DLYB_LNG_TIMEOUT_US 1000 35 + #define SDMMC_VSWEND_TIMEOUT_US 10000 35 36 36 37 struct sdmmc_lli_desc { 37 38 u32 idmalar; ··· 266 265 struct mmc_ios ios = host->mmc->ios; 267 266 struct sdmmc_dlyb *dlyb = host->variant_priv; 268 267 268 + /* adds OF options */ 269 269 pwr = host->pwr_reg_add; 270 270 271 271 sdmmc_dlyb_input_ck(dlyb); ··· 292 290 */ 293 291 writel(MCI_IRQENABLE | host->variant->start_err, 294 292 host->base + MMCIMASK0); 293 + 294 + /* preserves voltage switch bits */ 295 + pwr |= host->pwr_reg & (MCI_STM32_VSWITCHEN | 296 + MCI_STM32_VSWITCH); 295 297 296 298 /* 297 299 * After a power-cycle state, we must set the SDMMC in ··· 462 456 return sdmmc_dlyb_phase_tuning(host, opcode); 463 457 } 464 458 459 + static void sdmmc_pre_sig_volt_vswitch(struct mmci_host *host) 460 + { 461 + /* clear the voltage switch completion flag */ 462 + writel_relaxed(MCI_STM32_VSWENDC, host->base + MMCICLEAR); 463 + /* enable Voltage switch procedure */ 464 + mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCHEN); 465 + } 466 + 467 + static int sdmmc_post_sig_volt_switch(struct mmci_host *host, 468 + struct mmc_ios *ios) 469 + { 470 + unsigned long flags; 471 + u32 status; 472 + int ret = 0; 473 + 474 + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { 475 + spin_lock_irqsave(&host->lock, flags); 476 + mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); 477 + spin_unlock_irqrestore(&host->lock, flags); 478 + 479 + /* wait voltage switch completion while 10ms */ 480 + ret = readl_relaxed_poll_timeout(host->base + MMCISTATUS, 481 + status, 482 + (status & MCI_STM32_VSWEND), 483 + 10, SDMMC_VSWEND_TIMEOUT_US); 484 + 485 + writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, 486 + host->base + MMCICLEAR); 487 + mmci_write_pwrreg(host, host->pwr_reg & 488 + ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); 489 + } 490 + 491 + return ret; 492 + } 493 + 465 494 static struct mmci_host_ops sdmmc_variant_ops = { 466 495 .validate_data = sdmmc_idma_validate_data, 467 496 .prep_data = sdmmc_idma_prep_data, ··· 508 467 .set_clkreg = mmci_sdmmc_set_clkreg, 509 468 .set_pwrreg = mmci_sdmmc_set_pwrreg, 510 469 .busy_complete = sdmmc_busy_complete, 470 + .pre_sig_volt_switch = sdmmc_pre_sig_volt_vswitch, 471 + .post_sig_volt_switch = sdmmc_post_sig_volt_switch, 511 472 }; 512 473 513 474 void sdmmc_variant_init(struct mmci_host *host)