@@ -62,6 +62,9 @@ struct omap_mmc_platform_data {
int (*suspend)(struct device *dev, int slot);
int (*resume)(struct device *dev, int slot);
+ /* To get the OFF mode counter */
+ int (*context_loss) (struct device *dev);
+
@@ -150,14 +152,50 @@ struct mmc_omap_host {
int slot_id;
int dbclk_enabled;
int clks_enabled;
+ int off_counter;
spinlock_t clk_lock;
struct timer_list inact_timer;
struct omap_mmc_platform_data *pdata;
};
@@ -190,6 +228,43 @@ static int omap_hsmmc_enable_clks(struct mmc_omap_host *host)
host->dbclk_enabled = 1;
}
+ if (host->pdata->context_loss) {
+ if (host->pdata->context_loss(host->dev) > 0) {
+ if (host->pdata->context_loss(host->dev) >
+ host->off_counter) {
+ /* Coming out of OFF:
+ * The SRA bit of SYSCTL reg has a wrong reset
+ * value.
+ * The bit resets automatically in subsequent
+ * reads. Idealy it should have been 0 as per
+ * the reset value of the register.
+ * Wait for the reset to complete */
+ timeout = jiffies +
+ msecs_to_jiffies(MMC_TIMEOUT_MS);
+ while ((OMAP_HSMMC_READ(host->base, SYSSTATUS)
+ & RESETDONE) != RESETDONE
+ && time_before(jiffies, timeout))
+ ;
+ omap2_hsmmc_restore_ctx(host);
+ }
+ }
+ } else {
+ /* Restore allways */
+ /* Coming out of OFF:
+ * The SRA bit of SYSCTL reg has a wrong reset
+ * value.
+ * The bit resets automatically in subsequent
+ * reads. Idealy it should have been 0 as per
+ * the reset value of the register.
+ * Wait for the reset to complete */
+ timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
+ while ((OMAP_HSMMC_READ(host->base, SYSSTATUS)
+ & RESETDONE) != RESETDONE
+ && time_before(jiffies, timeout))
+ ;
+ omap2_hsmmc_restore_ctx(host);
+ }
+
done:
spin_unlock_irqrestore(&host->clk_lock, flags);
return ret;
@@ -211,6 +286,10 @@ static void omap_hsmmc_disable_clks(struct mmc_omap_host *host)
if (!host->clks_enabled)
goto done;
+ omap2_hsmmc_save_ctx(host);
+ if (host->pdata->context_loss)
+ host->off_counter = host->pdata->context_loss(host->dev);
+
clk_disable(host->fclk);
clk_disable(host->iclk);
host->clks_enabled = 0;
patch set 2
@@ -62,6 +62,9 @@ struct omap_mmc_platform_data {
int (*suspend)(struct device *dev, int slot);
int (*resume)(struct device *dev, int slot);
+ /* To get the OFF mode counter */
+ unsigned (*context_loss) (struct device *dev);
+
@@ -150,14 +152,50 @@ struct mmc_omap_host {
int slot_id;
int dbclk_enabled;
int clks_enabled;
+ unsigned off_counter;
spinlock_t clk_lock;
struct timer_list inact_timer;
struct omap_mmc_platform_data *pdata;
};
@@ -150,14 +152,50 @@ struct mmc_omap_host {
int slot_id;
int dbclk_enabled;
int clks_enabled;
+ unsigned off_counter;
spinlock_t clk_lock;
struct timer_list inact_timer;
struct omap_mmc_platform_data *pdata;
};
+struct omap_hsmmc_regs {
+ u32 hctl;
+ u32 capa;
+ u32 sysconfig;
+ u32 ise;
+ u32 ie;
+ u32 con;
+ u32 sysctl;
+};
+static struct omap_hsmmc_regs hsmmc_ctx[3];
+
+static void omap2_hsmmc_save_ctx(struct mmc_omap_host *host)
+{
+ /* MMC : context save */
+ hsmmc_ctx[host->id].hctl = OMAP_HSMMC_READ(host->base, HCTL);
+ hsmmc_ctx[host->id].capa = OMAP_HSMMC_READ(host->base, CAPA);
+ hsmmc_ctx[host->id].ise = OMAP_HSMMC_READ(host->base, ISE);
+ hsmmc_ctx[host->id].ie = OMAP_HSMMC_READ(host->base, IE);
+ hsmmc_ctx[host->id].con = OMAP_HSMMC_READ(host->base, CON);
+ hsmmc_ctx[host->id].sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
+}
+
+static void omap2_hsmmc_restore_ctx(struct mmc_omap_host *host)
+{
+ /* MMC : context restore */
+ OMAP_HSMMC_WRITE(host->base, HCTL, hsmmc_ctx[host->id].hctl);
+ OMAP_HSMMC_WRITE(host->base, CAPA, hsmmc_ctx[host->id].capa);
+ OMAP_HSMMC_WRITE(host->base, CON, hsmmc_ctx[host->id].con);
+ OMAP_HSMMC_WRITE(host->base, ISE, hsmmc_ctx[host->id].ise);
+ OMAP_HSMMC_WRITE(host->base, IE, hsmmc_ctx[host->id].ie);
+ OMAP_HSMMC_WRITE(host->base, SYSCTL, hsmmc_ctx[host->id].sysctl);