|
@@ -107,6 +107,9 @@
|
|
|
#define SRD (1 << 26)
|
|
|
#define SOFTRESET (1 << 1)
|
|
|
|
|
|
+/* PSTATE */
|
|
|
+#define DLEV_DAT(x) (1 << (20 + (x)))
|
|
|
+
|
|
|
/* Interrupt masks for IE and ISE register */
|
|
|
#define CC_EN (1 << 0)
|
|
|
#define TC_EN (1 << 1)
|
|
@@ -2387,6 +2390,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
|
|
|
{
|
|
|
struct omap_hsmmc_host *host;
|
|
|
unsigned long flags;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
host = platform_get_drvdata(to_platform_device(dev));
|
|
|
omap_hsmmc_context_save(host);
|
|
@@ -2398,14 +2402,29 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
|
|
|
/* disable sdio irq handling to prevent race */
|
|
|
OMAP_HSMMC_WRITE(host->base, ISE, 0);
|
|
|
OMAP_HSMMC_WRITE(host->base, IE, 0);
|
|
|
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
|
|
|
+
|
|
|
+ if (!(OMAP_HSMMC_READ(host->base, PSTATE) & DLEV_DAT(1))) {
|
|
|
+ /*
|
|
|
+ * dat1 line low, pending sdio irq
|
|
|
+ * race condition: possible irq handler running on
|
|
|
+ * multi-core, abort
|
|
|
+ */
|
|
|
+ dev_dbg(dev, "pending sdio irq, abort suspend\n");
|
|
|
+ OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
|
|
|
+ OMAP_HSMMC_WRITE(host->base, ISE, CIRQ_EN);
|
|
|
+ OMAP_HSMMC_WRITE(host->base, IE, CIRQ_EN);
|
|
|
+ pm_runtime_mark_last_busy(dev);
|
|
|
+ ret = -EBUSY;
|
|
|
+ goto abort;
|
|
|
+ }
|
|
|
|
|
|
WARN_ON(host->flags & HSMMC_WAKE_IRQ_ENABLED);
|
|
|
enable_irq(host->wake_irq);
|
|
|
host->flags |= HSMMC_WAKE_IRQ_ENABLED;
|
|
|
}
|
|
|
+abort:
|
|
|
spin_unlock_irqrestore(&host->irq_lock, flags);
|
|
|
- return 0;
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int omap_hsmmc_runtime_resume(struct device *dev)
|