Skip to contentSkip to conversation

dw_mmc: fix suspend/resume operation

PATCH In review Jaehoon Chung 3 participants 3 messages Mar 17, 2011

Subsystems (2)
lore
Share & tools
lore

Jaehoon Chung

author maintainer
#0 lore raw

PATCH 1/1 dw_mmc: fix suspend/resume operation

This patch is applied about re-init processing when suspend/resume.

When card is resuming, some register is reset.
If card is removable, maybe controller should be rescan for card. But if assume card is non-removable, need to restore the old value at registers.

---
 drivers/mmc/host/dw_mmc.c  |   22 ++++++++++++++++++++--
 include/linux/mmc/dw_mmc.h |    1 +
 2 files changed, 21 insertions(+), 2 deletions(-)
drivers/mmc/host/dw_mmc.c +20 -2
index 299c1d6..892bfe3 100644
@@ -1633,8 +1633,9 @@ static int dw_mci_probe(struct platform_device *pdev)
 	 */
 	fifo_size = mci_readl(host, FIFOTH);
 	fifo_size = (fifo_size >> 16) & 0x7ff;
-	mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
-				  ((fifo_size/2) << 0)));
+	host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+			((fifo_size/2) << 0));
+	mci_writel(host, FIFOTH, host->fifoth_val);
 
 	/* disable clock to CIU */
 	mci_writel(host, CLKENA, 0);
@@ -1766,6 +1767,23 @@ static int dw_mci_resume(struct platform_device *pdev)
 	int i, ret;
 	struct dw_mci *host = platform_get_drvdata(pdev);
 
+	if (host->dma_ops->init)
+		host->dma_ops->init(host);
+
+	if (!mci_wait_reset(&pdev->dev, host)) {
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/* Restore the old value at FIFOTH register */
+	mci_writel(host, FIFOTH, host->fifoth_val);
+
+	mci_writel(host, RINTSTS, 0xFFFFFFFF);
+	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
+		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
+		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+
 	for (i = 0; i < host->num_slots; i++) {
 		struct dw_mci_slot *slot = host->slot[i];
 		if (!slot)
include/linux/mmc/dw_mmc.h +1 -0
index 3f22c20..5b2b414 100644
@@ -140,6 +140,7 @@ struct dw_mci {
 	u32			bus_hz;
 	u32			current_speed;
 	u32			num_slots;
+	u32			fifoth_val;
 	struct platform_device	*pdev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];
Acked-by on v1 1/1
#1 lore raw
Quoted 8 lines · Jaehoon Chung

This patch is applied about re-init processing when suspend/resume.

When card is resuming, some register is reset.
If card is removable, maybe controller should be rescan for card. But if assume card is non-removable, need to restore the old value at registers.

Looks ok to me.

#2 lore raw
In reply to Jaehoon Chung

Hi,

Quoted 59 lines · Jaehoon Chung

This patch is applied about re-init processing when suspend/resume.

When card is resuming, some register is reset.
If card is removable, maybe controller should be rescan for card. But if assume card is non-removable, need to restore the old value at registers.

---
 drivers/mmc/host/dw_mmc.c  |   22 ++++++++++++++++++++--
 include/linux/mmc/dw_mmc.h |    1 +
 2 files changed, 21 insertions(+), 2 deletions(-)
drivers/mmc/host/dw_mmc.c +20 -2
index 299c1d6..892bfe3 100644
@@ -1633,8 +1633,9 @@ static int dw_mci_probe(struct platform_device *pdev)
 	 */
 	fifo_size = mci_readl(host, FIFOTH);
 	fifo_size = (fifo_size >> 16) & 0x7ff;
-	mci_writel(host, FIFOTH, ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
-				  ((fifo_size/2) << 0)));
+	host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
+			((fifo_size/2) << 0));
+	mci_writel(host, FIFOTH, host->fifoth_val);
 
 	/* disable clock to CIU */
 	mci_writel(host, CLKENA, 0);
@@ -1766,6 +1767,23 @@ static int dw_mci_resume(struct platform_device *pdev)
 	int i, ret;
 	struct dw_mci *host = platform_get_drvdata(pdev);
 
+	if (host->dma_ops->init)
+		host->dma_ops->init(host);
+
+	if (!mci_wait_reset(&pdev->dev, host)) {
+		ret = -ENODEV;
+		return ret;
+	}
+
+	/* Restore the old value at FIFOTH register */
+	mci_writel(host, FIFOTH, host->fifoth_val);
+
+	mci_writel(host, RINTSTS, 0xFFFFFFFF);
+	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
+		   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
+		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
+
 	for (i = 0; i < host->num_slots; i++) {
 		struct dw_mci_slot *slot = host->slot[i];
 		if (!slot)
include/linux/mmc/dw_mmc.h +0 -0
index 3f22c20..5b2b414 100644

include/linux/mmc/dw_mmc.h struct dw_mci { · line 146

Quoted 7 lines
include/linux/mmc/dw_mmc.h +1 -0
@@ -140,6 +140,7 @@ struct dw_mci {
 	u32			bus_hz;
 	u32			current_speed;
 	u32			num_slots;
+	u32			fifoth_val;
 	struct platform_device	*pdev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS];

Thanks, will merge for .39 with Will's ACK.

Signature · 2 lines
Chris Ball   <[email protected]>   <http://printf.net/>
One Laptop Per Child