mmc: sdhci-uhs2: add add_host() and others to set up the driver

This is a UHS-II version of sdhci's add_host/remove_host operation.
Any sdhci drivers which are capable of handling UHS-II cards must
call those functions instead of the corresponding sdhci's.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Message-ID: <20241018105333.4569-9-victorshihgli@gmail.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Victor Shih 2024-10-18 18:53:25 +08:00 committed by Ulf Hansson
parent 7e5b19f3a7
commit 06a0d072ba
2 changed files with 93 additions and 0 deletions

View File

@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/iopoll.h>
#include <linux/bitfield.h>
#include <linux/regulator/consumer.h>
#include "sdhci.h"
#include "sdhci-uhs2.h"
@ -224,6 +225,96 @@ static void __exit sdhci_uhs2_mod_exit(void)
}
module_exit(sdhci_uhs2_mod_exit);
/*****************************************************************************\
*
* Device allocation/registration *
* *
\*****************************************************************************/
static void __sdhci_uhs2_add_host_v4(struct sdhci_host *host, u32 caps1)
{
struct mmc_host *mmc;
u32 max_current_caps2;
mmc = host->mmc;
/* Support UHS2 */
if (caps1 & SDHCI_SUPPORT_UHS2)
mmc->caps2 |= MMC_CAP2_SD_UHS2;
max_current_caps2 = sdhci_readl(host, SDHCI_MAX_CURRENT_1);
if ((caps1 & SDHCI_CAN_VDD2_180) &&
!max_current_caps2 &&
!IS_ERR(mmc->supply.vqmmc2)) {
/* UHS2 - VDD2 */
int curr = regulator_get_current_limit(mmc->supply.vqmmc2);
if (curr > 0) {
/* convert to SDHCI_MAX_CURRENT format */
curr = curr / 1000; /* convert to mA */
curr = curr / SDHCI_MAX_CURRENT_MULTIPLIER;
curr = min_t(u32, curr, SDHCI_MAX_CURRENT_LIMIT);
max_current_caps2 = curr;
}
}
if (!(caps1 & SDHCI_CAN_VDD2_180))
mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
}
static void __sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
{
if (!mmc_card_uhs2(host->mmc))
return;
if (!dead)
sdhci_uhs2_reset(host, SDHCI_UHS2_SW_RESET_FULL);
}
int sdhci_uhs2_add_host(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
int ret;
ret = sdhci_setup_host(host);
if (ret)
return ret;
if (host->version >= SDHCI_SPEC_400)
__sdhci_uhs2_add_host_v4(host, host->caps1);
if ((mmc->caps2 & MMC_CAP2_SD_UHS2) && !host->v4_mode)
/* host doesn't want to enable UHS2 support */
mmc->caps2 &= ~MMC_CAP2_SD_UHS2;
/* LED support not implemented for UHS2 */
host->quirks |= SDHCI_QUIRK_NO_LED;
ret = __sdhci_add_host(host);
if (ret)
goto cleanup;
return 0;
cleanup:
if (host->version >= SDHCI_SPEC_400)
__sdhci_uhs2_remove_host(host, 0);
sdhci_cleanup_host(host);
return ret;
}
EXPORT_SYMBOL_GPL(sdhci_uhs2_add_host);
void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead)
{
__sdhci_uhs2_remove_host(host, dead);
sdhci_remove_host(host, dead);
}
EXPORT_SYMBOL_GPL(sdhci_uhs2_remove_host);
MODULE_AUTHOR("Intel, Genesys Logic, Linaro");
MODULE_DESCRIPTION("MMC UHS-II Support");
MODULE_LICENSE("GPL");

View File

@ -179,5 +179,7 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host);
void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
void sdhci_uhs2_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd);
void sdhci_uhs2_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
int sdhci_uhs2_add_host(struct sdhci_host *host);
void sdhci_uhs2_remove_host(struct sdhci_host *host, int dead);
#endif /* __SDHCI_UHS2_H */