aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-05-15 15:53:22 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2013-05-22 19:09:16 -0400
commit0125962000777cd1e2ce53deefb99779d5ee5199 (patch)
treea7c3a3c8d7e53391b9b02362407919c7f11045aa
parent9cc639a20fdc0b935e55d4992f93963f95233ca4 (diff)
ARM: 7726/1: mmc: mmci: Add card_busy function to improve UHS card support
To verify a signal voltage switch at initialization of UHS cards the .card_busy callback is used. For some of the ST-variants, card busy detection on the DAT0 pin is supported. We extend the variant struct with a busy_detect flag to indicate support for it. A corresponding busy detect function, which polls the busy status bit, is then set to the .card_busy callback. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/mmc/host/mmci.c33
-rw-r--r--drivers/mmc/host/mmci.h2
2 files changed, 34 insertions, 1 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index ccfe0bc62f78..c3785edc0e92 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -61,6 +61,7 @@ static unsigned int fmax = 515633;
61 * @pwrreg_powerup: power up value for MMCIPOWER register 61 * @pwrreg_powerup: power up value for MMCIPOWER register
62 * @signal_direction: input/out direction of bus signals can be indicated 62 * @signal_direction: input/out direction of bus signals can be indicated
63 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock 63 * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
64 * @busy_detect: true if busy detection on dat0 is supported
64 */ 65 */
65struct variant_data { 66struct variant_data {
66 unsigned int clkreg; 67 unsigned int clkreg;
@@ -74,6 +75,7 @@ struct variant_data {
74 u32 pwrreg_powerup; 75 u32 pwrreg_powerup;
75 bool signal_direction; 76 bool signal_direction;
76 bool pwrreg_clkgate; 77 bool pwrreg_clkgate;
78 bool busy_detect;
77}; 79};
78 80
79static struct variant_data variant_arm = { 81static struct variant_data variant_arm = {
@@ -132,6 +134,7 @@ static struct variant_data variant_ux500 = {
132 .pwrreg_powerup = MCI_PWR_ON, 134 .pwrreg_powerup = MCI_PWR_ON,
133 .signal_direction = true, 135 .signal_direction = true,
134 .pwrreg_clkgate = true, 136 .pwrreg_clkgate = true,
137 .busy_detect = true,
135}; 138};
136 139
137static struct variant_data variant_ux500v2 = { 140static struct variant_data variant_ux500v2 = {
@@ -146,8 +149,28 @@ static struct variant_data variant_ux500v2 = {
146 .pwrreg_powerup = MCI_PWR_ON, 149 .pwrreg_powerup = MCI_PWR_ON,
147 .signal_direction = true, 150 .signal_direction = true,
148 .pwrreg_clkgate = true, 151 .pwrreg_clkgate = true,
152 .busy_detect = true,
149}; 153};
150 154
155static int mmci_card_busy(struct mmc_host *mmc)
156{
157 struct mmci_host *host = mmc_priv(mmc);
158 unsigned long flags;
159 int busy = 0;
160
161 pm_runtime_get_sync(mmc_dev(mmc));
162
163 spin_lock_irqsave(&host->lock, flags);
164 if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY)
165 busy = 1;
166 spin_unlock_irqrestore(&host->lock, flags);
167
168 pm_runtime_mark_last_busy(mmc_dev(mmc));
169 pm_runtime_put_autosuspend(mmc_dev(mmc));
170
171 return busy;
172}
173
151/* 174/*
152 * Validate mmc prerequisites 175 * Validate mmc prerequisites
153 */ 176 */
@@ -193,6 +216,9 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
193 */ 216 */
194static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) 217static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
195{ 218{
219 /* Keep ST Micro busy mode if enabled */
220 datactrl |= host->datactrl_reg & MCI_ST_DPSM_BUSYMODE;
221
196 if (host->datactrl_reg != datactrl) { 222 if (host->datactrl_reg != datactrl) {
197 host->datactrl_reg = datactrl; 223 host->datactrl_reg = datactrl;
198 writel(datactrl, host->base + MMCIDATACTRL); 224 writel(datactrl, host->base + MMCIDATACTRL);
@@ -1319,7 +1345,7 @@ static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
1319 return IRQ_HANDLED; 1345 return IRQ_HANDLED;
1320} 1346}
1321 1347
1322static const struct mmc_host_ops mmci_ops = { 1348static struct mmc_host_ops mmci_ops = {
1323 .request = mmci_request, 1349 .request = mmci_request,
1324 .pre_req = mmci_pre_request, 1350 .pre_req = mmci_pre_request,
1325 .post_req = mmci_post_request, 1351 .post_req = mmci_post_request,
@@ -1455,6 +1481,11 @@ static int mmci_probe(struct amba_device *dev,
1455 goto clk_disable; 1481 goto clk_disable;
1456 } 1482 }
1457 1483
1484 if (variant->busy_detect) {
1485 mmci_ops.card_busy = mmci_card_busy;
1486 mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
1487 }
1488
1458 mmc->ops = &mmci_ops; 1489 mmc->ops = &mmci_ops;
1459 /* 1490 /*
1460 * The ARM and ST versions of the block have slightly different 1491 * The ARM and ST versions of the block have slightly different
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 0b6cc54be966..69080fab6375 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -94,6 +94,7 @@
94/* Extended status bits for the ST Micro variants */ 94/* Extended status bits for the ST Micro variants */
95#define MCI_ST_SDIOIT (1 << 22) 95#define MCI_ST_SDIOIT (1 << 22)
96#define MCI_ST_CEATAEND (1 << 23) 96#define MCI_ST_CEATAEND (1 << 23)
97#define MCI_ST_CARDBUSY (1 << 24)
97 98
98#define MMCICLEAR 0x038 99#define MMCICLEAR 0x038
99#define MCI_CMDCRCFAILCLR (1 << 0) 100#define MCI_CMDCRCFAILCLR (1 << 0)
@@ -110,6 +111,7 @@
110/* Extended status bits for the ST Micro variants */ 111/* Extended status bits for the ST Micro variants */
111#define MCI_ST_SDIOITC (1 << 22) 112#define MCI_ST_SDIOITC (1 << 22)
112#define MCI_ST_CEATAENDC (1 << 23) 113#define MCI_ST_CEATAENDC (1 << 23)
114#define MCI_ST_BUSYENDC (1 << 24)
113 115
114#define MMCIMASK0 0x03c 116#define MMCIMASK0 0x03c
115#define MCI_CMDCRCFAILMASK (1 << 0) 117#define MCI_CMDCRCFAILMASK (1 << 0)