@@ -683,10 +683,35 @@ void mmc_ungate_clock(struct mmc_host *host)
}
}
+/*
+ * Let hardware automatically gate the clock when the card becomes idle
+ */
+void mmc_hwgate_clock(struct mmc_host *host)
+{
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING) {
+ host->clk_gated = true;
+ mmc_set_ios(host);
+ }
+}
+
+/*
+ * This ungates the clock by turning off h/w gating
+ */
+void mmc_hwungate_clock(struct mmc_host *host)
+{
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING) {
+ host->clk_gated = false;
+ mmc_set_ios(host);
+ }
+}
+
+
void mmc_set_ungated(struct mmc_host *host)
{
unsigned long flags;
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ return;
/*
* We've been given a new frequency while the clock is gated,
* so make sure we regard this as ungating it.
@@ -1553,6 +1578,7 @@ void mmc_rescan(struct work_struct *work)
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host);
+ mmc_hwungate_clock(host);
sdio_reset(host);
mmc_go_idle(host);
@@ -1577,6 +1603,9 @@ void mmc_rescan(struct work_struct *work)
if (mmc_send_app_op_cond(host, 0, &ocr))
goto out_fail;
+ /* hw clock gating is off when we get here */
+ /* do not enable clock gating for sdio cards */
+ /* sdio cards can miss interrupts */
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
}
@@ -1590,6 +1619,8 @@ void mmc_rescan(struct work_struct *work)
if (!err) {
if (mmc_attach_sd(host, ocr))
mmc_power_off(host);
+ else
+ mmc_hwgate_clock(host);
goto out;
}
@@ -1600,6 +1631,8 @@ void mmc_rescan(struct work_struct *work)
if (!err) {
if (mmc_attach_mmc(host, ocr))
mmc_power_off(host);
+ else
+ mmc_hwgate_clock(host);
goto out;
}
@@ -35,6 +35,19 @@ void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
void mmc_gate_clock(struct mmc_host *host);
void mmc_ungate_clock(struct mmc_host *host);
+
+#ifdef CONFIG_MMC_CLKGATE
+void mmc_hwgate_clock(struct mmc_host *host);
+void mmc_hwungate_clock(struct mmc_host *host);
+#else
+static inline void mmc_hwgate_clock(struct mmc_host *host)
+{
+}
+
+static inline void mmc_hwungate_clock(struct mmc_host *host)
+{
+}
+#endif
void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
@@ -130,6 +130,9 @@ void mmc_host_clk_ungate(struct mmc_host *host)
{
unsigned long flags;
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ return;
+
mutex_lock(&host->clk_gate_mutex);
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated) {
@@ -178,6 +181,9 @@ void mmc_host_clk_gate(struct mmc_host *host)
{
unsigned long flags;
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ return;
+
spin_lock_irqsave(&host->clk_lock, flags);
host->clk_requests--;
if (mmc_host_may_gate_card(host->card) &&
@@ -198,7 +204,10 @@ unsigned int mmc_host_clk_rate(struct mmc_host *host)
unsigned long flags;
spin_lock_irqsave(&host->clk_lock, flags);
- if (host->clk_gated)
+ freq = host->ios.clock;
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ freq = host->ios.clock;
+ else if (host->clk_gated)
freq = host->clk_old;
else
freq = host->ios.clock;
@@ -212,6 +221,9 @@ unsigned int mmc_host_clk_rate(struct mmc_host *host)
*/
static inline void mmc_host_clk_init(struct mmc_host *host)
{
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ return;
+
host->clk_requests = 0;
/* Hold MCI clock for 8 cycles by default */
host->clk_delay = 8;
@@ -227,6 +239,9 @@ static inline void mmc_host_clk_init(struct mmc_host *host)
*/
static inline void mmc_host_clk_exit(struct mmc_host *host)
{
+ if (host->caps & MMC_CAP_HW_CLOCK_GATING)
+ return;
+
/*
* Wait for any outstanding gate and then make sure we're
* ungated before exiting.
@@ -173,6 +173,7 @@ struct mmc_host {
/* DDR mode at 1.2V */
#define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
#define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */
+#define MMC_CAP_HW_CLOCK_GATING (1 << 15) /* h/w supports clock gating */
mmc_pm_flag_t pm_caps; /* supported pm features */