summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2012-11-12 15:28:39 +0100
commitf987e832a9e79d2ce8009a5ea9c7b677624b3b30 (patch)
tree0dd09a5e6b4c60ee0a9916907dfc2cda83f3e496 /drivers/mmc
parentf737b7f46a72c099cf8ac88baff02fbf61b1a47c (diff)
parentfc993d9bc48f772133d8cd156c67c296477db070 (diff)
Merge branch 'l4t/l4t-r16-r2' into colibri
Conflicts: arch/arm/mach-tegra/tegra3_usb_phy.c arch/arm/mach-tegra/usb_phy.c drivers/usb/gadget/tegra_udc.c drivers/usb/otg/Makefile drivers/video/tegra/fb.c sound/soc/tegra/tegra_pcm.c
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/core/core.c26
-rw-r--r--drivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/sd_ops.c26
-rw-r--r--drivers/mmc/core/sd_ops.h3
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/sdhci-tegra.c123
-rw-r--r--drivers/mmc/host/sdhci.c38
-rw-r--r--drivers/mmc/host/sdhci.h1
8 files changed, 146 insertions, 91 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 35f3df8810e0..f7528db8fd06 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2109,6 +2109,26 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
}
+int mmc_speed_class_control(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = -ENOSYS;
+ u32 status;
+
+ err = mmc_send_speed_class_ctrl(host, speed_class_ctrl_arg);
+ if (err)
+ return err;
+
+ /* Issue CMD13 to check for any errors during the busy period of CMD20 */
+ err = mmc_send_status(host->card, &status);
+ if (!err) {
+ if (status & R1_ERROR)
+ err = -EINVAL;
+ }
+ return err;
+}
+EXPORT_SYMBOL(mmc_speed_class_control);
+
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
@@ -2163,6 +2183,9 @@ int mmc_card_awake(struct mmc_host *host)
{
int err = -ENOSYS;
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ return 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
@@ -2178,6 +2201,9 @@ int mmc_card_sleep(struct mmc_host *host)
{
int err = -ENOSYS;
+ if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+ return 0;
+
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 40c93b3dccd7..0e8001facac3 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -976,13 +976,19 @@ static void mmc_detect(struct mmc_host *host)
*/
static int mmc_suspend(struct mmc_host *host)
{
+ int err;
+
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
- if (!mmc_host_is_spi(host))
+ if (mmc_card_can_sleep(host)) {
+ err = mmc_card_sleep(host);
+ if (!err)
+ mmc_card_set_sleep(host->card);
+ } else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
- host->card->state &= ~MMC_STATE_HIGHSPEED;
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_release_host(host);
return 0;
@@ -1002,7 +1008,11 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
- err = mmc_init_card(host, host->ocr, host->card);
+ if (mmc_card_is_sleep(host->card)) {
+ err = mmc_card_awake(host);
+ mmc_card_clr_sleep(host->card);
+ } else
+ err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
@@ -1012,7 +1022,8 @@ static int mmc_power_restore(struct mmc_host *host)
{
int ret;
- host->card->state &= ~MMC_STATE_HIGHSPEED;
+ host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+ mmc_card_clr_sleep(host->card);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed153804..b06781e69ce3 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -389,3 +389,29 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
return 0;
}
+
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = 0;
+ struct mmc_command cmd = {
+ .opcode = SD_SPEED_CLASS_CONTROL,
+ .arg = (speed_class_ctrl_arg << 28),
+ .flags = MMC_RSP_R1B | MMC_CMD_AC | MMC_RSP_BUSY,
+ };
+
+ BUG_ON(!host);
+ BUG_ON(speed_class_ctrl_arg > 3);
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ return err;
+
+ /*
+ * If the host does not wait while the card signals busy, then we will
+ * will have to wait the max busy indication timeout.
+ */
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ mmc_delay(1000);
+ return err;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index ffc2305d905f..a77b8facceb4 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -20,6 +20,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
-
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg);
#endif
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index f5ea51bd0ed3..2f9d6f4f43e1 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
+CFLAGS_sdhci-tegra.o = -Werror
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 609fd6391d1f..8ff35e4cbfe4 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -74,7 +74,9 @@ static unsigned int tegra_sdhost_std_freq;
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock);
static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci);
+#endif
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
static unsigned int tegra3_sdhost_max_clk[4] = {
208000000, 104000000, 208000000, 104000000 };
#endif
@@ -227,7 +229,7 @@ static void tegra3_sdhci_post_reset_init(struct sdhci_host *sdhci)
SDHCI_VENDOR_MISC_CNTRL_ENABLE_SDR50_SUPPORT;
sdhci_writew(sdhci, misc_ctrl, SDHCI_VENDOR_MISC_CNTRL);
}
-#endif
+#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */
static int tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
unsigned int uhs)
@@ -372,14 +374,7 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
unsigned int clk_rate;
unsigned int emc_clk;
- /*
- * In SDR50 mode, run the sdmmc controller at freq greater than
- * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
- * is below 1.2V, CRC errors would occur during data transfers.
- */
- if (sdhci->mmc->card &&
- (mmc_card_ddr_mode(sdhci->mmc->card) ||
- (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50))) {
+ if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_DDR50) {
/*
* In ddr mode, tegra sdmmc controller clock frequency
* should be double the card clock frequency.
@@ -394,6 +389,13 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
} else {
clk_rate = clock * 2;
}
+ } else if (sdhci->mmc->ios.timing == MMC_TIMING_UHS_SDR50) {
+ /*
+ * In SDR50 mode, run the sdmmc controller at freq greater than
+ * 104MHz to ensure the core voltage is at 1.2V. If the core voltage
+ * is below 1.2V, CRC errors would occur during data transfers.
+ */
+ clk_rate = clock * 2;
} else {
if (clock <= tegra_sdhost_min_freq)
clk_rate = tegra_sdhost_min_freq;
@@ -410,7 +412,6 @@ static void tegra_sdhci_set_clk_rate(struct sdhci_host *sdhci,
clk_set_rate(pltfm_host->clk, clk_rate);
sdhci->max_clk = clk_get_rate(pltfm_host->clk);
}
-
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static void tegra_3x_sdhci_set_card_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -496,7 +497,7 @@ set_clk:
out:
sdhci->clock = clock;
}
-#endif
+#endif /* #ifdef CONFIG_ARCH_TEGRA_3x_SOC */
static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
{
@@ -509,7 +510,12 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
if (clock) {
/* bring out sd instance from io dpd mode */
- tegra_io_dpd_disable(tegra_host->dpd);
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ cancel_delayed_work_sync(&tegra_host->dpd->delay_dpd);
+ tegra_io_dpd_disable(tegra_host->dpd);
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
if (!tegra_host->clk_enabled) {
clk_enable(pltfm_host->clk);
@@ -530,7 +536,18 @@ static void tegra_sdhci_set_clock(struct sdhci_host *sdhci, unsigned int clock)
clk_disable(pltfm_host->clk);
tegra_host->clk_enabled = false;
/* io dpd enable call for sd instance */
- tegra_io_dpd_enable(tegra_host->dpd);
+
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ if (tegra_host->dpd->need_delay_dpd) {
+ schedule_delayed_work(
+ &tegra_host->dpd->delay_dpd,
+ msecs_to_jiffies(100));
+ } else {
+ tegra_io_dpd_enable(tegra_host->dpd);
+ }
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
}
}
@@ -658,36 +675,15 @@ static void sdhci_tegra_set_tap_delay(struct sdhci_host *sdhci,
sdhci_writel(sdhci, vendor_ctrl, SDHCI_VENDOR_CLOCK_CNTRL);
}
-static void sdhci_tegra_clear_set_irqs(struct sdhci_host *host,
- u32 clear, u32 set)
-{
- u32 ier;
-
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- ier &= ~clear;
- ier |= set;
- sdhci_writel(host, ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci)
{
int err = 0;
u8 ctrl;
- u32 ier;
u32 mask;
unsigned int timeout = 10;
int flags;
u32 intstatus;
- /*
- * As per the Host Controller spec v3.00, tuning command
- * generates Buffer Read Ready interrupt only, so enable that.
- */
- ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE);
- sdhci_tegra_clear_set_irqs(sdhci, ier, SDHCI_INT_DATA_AVAIL |
- SDHCI_INT_DATA_CRC);
-
mask = SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT;
while (sdhci_readl(sdhci, SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
@@ -759,7 +755,6 @@ static int sdhci_tegra_run_frequency_tuning(struct sdhci_host *sdhci)
}
mdelay(1);
out:
- sdhci_tegra_clear_set_irqs(sdhci, SDHCI_INT_DATA_AVAIL, ier);
return err;
}
@@ -773,6 +768,7 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
unsigned int temp_pass_window = 0;
unsigned int best_low_pass_tap = 0;
unsigned int best_pass_window = 0;
+ u32 ier;
/* Tuning is valid only in SDR104 and SDR50 modes */
ctrl_2 = sdhci_readw(sdhci, SDHCI_HOST_CONTROL2);
@@ -785,11 +781,20 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
if (tap_delay_status == NULL) {
dev_err(mmc_dev(sdhci->mmc), "failed to allocate memory"
"for storing tap_delay_status\n");
- err = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
/*
+ * Disable all interrupts signalling.Enable interrupt status
+ * detection for buffer read ready and data crc. We use
+ * polling for tuning as it involves less overhead.
+ */
+ ier = sdhci_readl(sdhci, SDHCI_INT_ENABLE);
+ sdhci_writel(sdhci, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_writel(sdhci, SDHCI_INT_DATA_AVAIL |
+ SDHCI_INT_DATA_CRC, SDHCI_INT_ENABLE);
+
+ /*
* Set each tap delay value and run frequency tuning. After each
* run, update the tap delay status as working or not working.
*/
@@ -840,7 +845,10 @@ static int sdhci_tegra_execute_tuning(struct sdhci_host *sdhci)
/* Run frequency tuning */
err = sdhci_tegra_run_frequency_tuning(sdhci);
-out:
+ /* Enable the normal interrupts signalling */
+ sdhci_writel(sdhci, ier, SDHCI_INT_ENABLE);
+ sdhci_writel(sdhci, ier, SDHCI_SIGNAL_ENABLE);
+
if (tap_delay_status)
kfree(tap_delay_status);
@@ -865,6 +873,12 @@ static int tegra_sdhci_suspend(struct sdhci_host *sdhci, pm_message_t state)
}
}
+ if (tegra_host->dpd) {
+ mutex_lock(&tegra_host->dpd->delay_lock);
+ tegra_host->dpd->need_delay_dpd = 1;
+ mutex_unlock(&tegra_host->dpd->delay_lock);
+ }
+
return 0;
}
@@ -905,9 +919,6 @@ static struct sdhci_ops tegra_sdhci_ops = {
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
.platform_8bit_width = tegra_sdhci_8bit,
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- .set_card_clock = tegra_3x_sdhci_set_card_clock,
-#endif
.set_clock = tegra_sdhci_set_clock,
.suspend = tegra_sdhci_suspend,
.resume = tegra_sdhci_resume,
@@ -981,7 +992,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate power gpio\n");
goto err_power_req;
}
- tegra_gpio_enable(plat->power_gpio);
gpio_direction_output(plat->power_gpio, 1);
}
@@ -992,7 +1002,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate cd gpio\n");
goto err_cd_req;
}
- tegra_gpio_enable(plat->cd_gpio);
gpio_direction_input(plat->cd_gpio);
tegra_host->card_present = (gpio_get_value(plat->cd_gpio) == 0);
@@ -1027,7 +1036,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate wp gpio\n");
goto err_wp_req;
}
- tegra_gpio_enable(plat->wp_gpio);
gpio_direction_input(plat->wp_gpio);
}
@@ -1133,12 +1141,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
host->mmc->caps |= MMC_CAP_BKOPS;
#endif
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- /* Do not turn OFF embedded sdio cards as it support Wake on Wireless */
- if (plat->mmc_data.embedded_sdio)
- host->mmc->pm_flags |= MMC_PM_KEEP_POWER;
-#endif
-
tegra_sdhost_min_freq = TEGRA_SDHOST_MIN_FREQ;
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
tegra_host->hw_ops = &tegra_2x_sdhci_ops;
@@ -1160,23 +1162,17 @@ err_add_host:
err_clk_put:
clk_put(pltfm_host->clk);
err_clk_get:
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
err_wp_req:
if (gpio_is_valid(plat->cd_gpio))
free_irq(gpio_to_irq(plat->cd_gpio), host);
err_cd_irq_req:
- if (gpio_is_valid(plat->cd_gpio)) {
- tegra_gpio_disable(plat->cd_gpio);
+ if (gpio_is_valid(plat->cd_gpio))
gpio_free(plat->cd_gpio);
- }
err_cd_req:
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
err_power_req:
err_no_mem:
kfree(tegra_host);
@@ -1209,21 +1205,16 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
regulator_put(tegra_host->vdd_io_reg);
}
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
if (gpio_is_valid(plat->cd_gpio)) {
free_irq(gpio_to_irq(plat->cd_gpio), host);
- tegra_gpio_disable(plat->cd_gpio);
gpio_free(plat->cd_gpio);
}
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
if (tegra_host->clk_enabled)
clk_disable(pltfm_host->clk);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index d3e9a4a4169f..aa03ca7d5226 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1852,19 +1852,15 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
int sdhci_enable(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
+ u16 clk;
- if (!mmc->card)
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
return 0;
if (mmc->ios.clock) {
- if (mmc->card->type != MMC_TYPE_SDIO) {
- if (host->ops->set_clock)
- host->ops->set_clock(host, mmc->ios.clock);
- sdhci_set_clock(host, mmc->ios.clock);
- } else {
- if (host->ops->set_card_clock)
- host->ops->set_card_clock(host, mmc->ios.clock);
- }
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, mmc->ios.clock);
+ sdhci_set_clock(host, mmc->ios.clock);
}
return 0;
@@ -1873,19 +1869,14 @@ int sdhci_enable(struct mmc_host *mmc)
int sdhci_disable(struct mmc_host *mmc, int lazy)
{
struct sdhci_host *host = mmc_priv(mmc);
+ u16 clk;
- if (!mmc->card)
+ if (!mmc->card || mmc->card->type == MMC_TYPE_SDIO)
return 0;
- /* For SDIO cards, only disable the card clock. */
- if (mmc->card->type != MMC_TYPE_SDIO) {
- sdhci_set_clock(host, 0);
- if (host->ops->set_clock)
- host->ops->set_clock(host, 0);
- } else {
- if (host->ops->set_card_clock)
- host->ops->set_card_clock(host, 0);
- }
+ sdhci_set_clock(host, 0);
+ if (host->ops->set_clock)
+ host->ops->set_clock(host, 0);
return 0;
}
@@ -2348,6 +2339,15 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
}
if (mmc->card) {
+ /*
+ * If eMMC cards are put in sleep state, Vccq can be disabled
+ * but Vcc would still be powered on. In resume, we only restore
+ * the controller context. So, set MMC_PM_KEEP_POWER flag.
+ */
+ if (mmc_card_can_sleep(mmc) &&
+ !(mmc->caps & MMC_CAP2_NO_SLEEP_CMD))
+ mmc->pm_flags = MMC_PM_KEEP_POWER;
+
ret = mmc_suspend_host(host->mmc);
if (ret) {
if (has_tuning_timer) {
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index bf48767e0ef2..c00833de19da 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -260,7 +260,6 @@ struct sdhci_ops {
#endif
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
- void (*set_card_clock)(struct sdhci_host *host, unsigned int clock);
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);