diff options
author | Ulf Hansson <ulf.hansson@linaro.org> | 2013-05-15 15:53:22 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2013-05-22 19:09:16 -0400 |
commit | 0125962000777cd1e2ce53deefb99779d5ee5199 (patch) | |
tree | a7c3a3c8d7e53391b9b02362407919c7f11045aa | |
parent | 9cc639a20fdc0b935e55d4992f93963f95233ca4 (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.c | 33 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 2 |
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 | */ |
65 | struct variant_data { | 66 | struct 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 | ||
79 | static struct variant_data variant_arm = { | 81 | static 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 | ||
137 | static struct variant_data variant_ux500v2 = { | 140 | static 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 | ||
155 | static 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 | */ |
194 | static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl) | 217 | static 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 | ||
1322 | static const struct mmc_host_ops mmci_ops = { | 1348 | static 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) |