#define OMAP_MMC_DATADIR_WRITE 2
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MASTER_CLOCK 96000000
-#define DRIVER_NAME "mmci-omap"
+#define DRIVER_NAME "mmci-omap-hs"
/*
* One controller can have multiple slots, like on some omap boards using
__raw_writel((val), (base) + OMAP_HSMMC_##reg)
enum {OFF = 0, ON};
-#define IDLE_TIMEOUT (5*HZ)
+#define IDLE_TIMEOUT (jiffies_to_msecs(10))
struct mmc_omap_host {
struct device *dev;
struct timer_list idle_timer;
spinlock_t clk_lock; /* for changing enabled state */
- int fclk_enabled:1;
+ unsigned int fclk_enabled:1;
struct omap_mmc_platform_data *pdata;
};
-int mmc_omap_fclk_state(struct mmc_omap_host *host, unsigned int state)
+static int mmc_omap_fclk_state(struct mmc_omap_host *host, unsigned int state)
{
unsigned long flags;
- int ret;
+ int ret = 0;
spin_lock_irqsave(&host->clk_lock, flags);
+ del_timer(&host->idle_timer);
if (host->fclk_enabled != state) {
if (state == ON) {
- if (host->fclk_enabled == OFF) {
- ret = clk_enable(host->fclk);
- if (ret != 0)
- return ret;
- dev_dbg(mmc_dev(host->mmc),
- "mmc_fclk: enabled\n");
- }
- /* Revisit: Change the timer bump based on real
- MMC usage characteristics */
- mod_timer(&host->idle_timer, jiffies + IDLE_TIMEOUT);
+ ret = clk_enable(host->fclk);
+ if (ret != 0)
+ goto err_out;
+
+ dev_dbg(mmc_dev(host->mmc), "mmc_fclk: enabled\n");
} else {
clk_disable(host->fclk);
dev_dbg(mmc_dev(host->mmc), "mmc_fclk: disabled\n");
- del_timer(&host->idle_timer);
}
host->fclk_enabled = state;
}
+
+err_out:
spin_unlock_irqrestore(&host->clk_lock, flags);
- return 0;
+ return ret;
}
static void mmc_omap_idle_timer(unsigned long data)
mmc_omap_fclk_state(host, OFF);
}
+static void mmc_omap_fclk_lazy_disable(struct mmc_omap_host *host)
+{
+ mod_timer(&host->idle_timer, jiffies + IDLE_TIMEOUT);
+}
+
/*
* Stop clock to the card
*/
/*
* Unlike OMAP1 controller, the cmdtype does not seem to be based on
- * ac, bc, adtc, bcr. Only CMD12 needs a val of 0x3, rest 0x0.
+ * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
+ * a val of 0x3, rest 0x0.
*/
- if (cmd->opcode == 12)
+ if (cmd == host->mrq->stop)
cmdtype = 0x3;
cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
if (!data->stop) {
host->mrq = NULL;
+ mmc_omap_fclk_lazy_disable(host);
mmc_request_done(host->mmc, data->mrq);
return;
}
}
if (host->data == NULL || cmd->error) {
host->mrq = NULL;
+ mmc_omap_fclk_lazy_disable(host);
mmc_request_done(host->mmc, cmd->mrq);
}
}
* Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is
* set in HCTL.
*/
- if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
- ((1 << vdd) == MMC_VDD_33_34)))
- reg_val |= SDVS30;
- if ((1 << vdd) == MMC_VDD_165_195)
+ if (host->id == OMAP_MMC1_DEVID) {
+ if (((1 << vdd) == MMC_VDD_32_33) ||
+ ((1 << vdd) == MMC_VDD_33_34))
+ reg_val |= SDVS30;
+ else if ((1 << vdd) == MMC_VDD_165_195)
+ reg_val |= SDVS18;
+ } else
reg_val |= SDVS18;
OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
mmc_carddetect_work);
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
+ mmc_omap_fclk_state(host, ON);
if (host->carddetect) {
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
/*
while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD) ;
mmc_detect_change(host->mmc, (HZ * 50) / 1000);
}
+ mmc_omap_fclk_lazy_disable(host);
}
/*
WARN_ON(host->mrq != NULL);
host->mrq = req;
- mmc_omap_prepare_data(host, req);
mmc_omap_fclk_state(host, ON);
+ mmc_omap_prepare_data(host, req);
mmc_omap_start_command(host, req->cmd, req->data);
}
unsigned long regval;
unsigned long timeout;
+ mmc_omap_fclk_state(host, ON);
+
switch (ios->power_mode) {
case MMC_POWER_OFF:
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) | OD);
+ mmc_omap_fclk_lazy_disable(host);
}
static int omap_hsmmc_get_cd(struct mmc_host *mmc)
* MMC can still work without debounce clock.
*/
if (IS_ERR(host->dbclk))
- dev_dbg(mmc_dev(host->mmc), "Failed to get debounce clock\n");
+ dev_warn(mmc_dev(host->mmc), "Failed to get debounce clock\n");
else
if (clk_enable(host->dbclk) != 0)
dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
if (ret < 0)
goto err_cover_switch;
}
+ mmc_omap_fclk_lazy_disable(host);
return 0;
{
struct mmc_omap_host *host = platform_get_drvdata(pdev);
struct resource *res;
- u16 vdd = 0;
- if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
- /*
- * Set the vdd back to 3V,
- * applicable for dual volt support.
- */
- vdd = fls(host->mmc->ocr_avail) - 1;
- if (omap_mmc_switch_opcond(host, vdd) != 0)
- host->mmc->ios.vdd = vdd;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, res->end - res->start + 1);
-
- platform_set_drvdata(pdev, NULL);
if (host) {
mmc_remove_host(host->mmc);
if (host->pdata->cleanup)
iounmap(host->base);
}
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_set_drvdata(pdev, NULL);
+
return 0;
}
if (ret == 0) {
host->suspended = 1;
+ mmc_omap_fclk_state(host, ON);
OMAP_HSMMC_WRITE(host->base, ISE, 0);
OMAP_HSMMC_WRITE(host->base, IE, 0);
" level suspend\n");
}
- if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL)
- & SDVSCLR);
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL)
- | SDVS30);
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL)
- | SDBP);
- }
-
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
mmc_omap_fclk_state(host, OFF);
clk_disable(host->iclk);
clk_disable(host->dbclk);
return 0;
if (host) {
-
+ int i;
if (mmc_omap_fclk_state(host, ON) != 0)
goto clk_en_err;
dev_dbg(mmc_dev(host->mmc),
"Enabling debounce clk failed\n");
+ OMAP_HSMMC_WRITE(host->base, HCTL,
+ OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+
+ for (i = 0; i < 100; i++)
+ if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
+ break;
+
if (host->pdata->resume) {
ret = host->pdata->resume(&pdev->dev, host->slot_id);
if (ret)
ret = mmc_resume_host(host->mmc);
if (ret == 0)
host->suspended = 0;
+
+ mmc_omap_fclk_lazy_disable(host);
}
return ret;