Commit 06a0d072 authored by Victor Shih's avatar Victor Shih Committed by Ulf Hansson
Browse files

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: default avatarBen Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: default avatarAKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: default avatarVictor Shih <victor.shih@genesyslogic.com.tw>
Acked-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Message-ID: <20241018105333.4569-9-victorshihgli@gmail.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 7e5b19f3
Loading
Loading
Loading
Loading
+91 −0
Original line number Diff line number Diff line
@@ -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");
+2 −0
Original line number Diff line number Diff line
@@ -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 */