aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Miroslaw <mirq-linux@rere.qmqm.pl>2010-08-10 21:01:40 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:03 -0400
commit7310ece86ad7da027f85a37a0638164118a5d12f (patch)
tree122fd13237eba533876b08aadeee4b7128d9feb0
parent71578a1eaa7b8b9bd3efc9c97d77ef2b63d5dc2b (diff)
mmc: implement SD-combo (IO+mem) support
Signed-off-by: Michal Miroslaw <mirq-linux@rere.qmqm.pl> Cc: Adrian Hunter <adrian.hunter@nokia.com> Cc: Chris Ball <cjb@laptop.org> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/mmc/core/bus.c9
-rw-r--r--drivers/mmc/core/core.c12
-rw-r--r--drivers/mmc/core/sdio.c135
-rw-r--r--include/linux/mmc/card.h1
4 files changed, 134 insertions, 23 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 49d9dcaeca49..7cd9749dc21d 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -37,6 +37,8 @@ static ssize_t mmc_type_show(struct device *dev,
37 return sprintf(buf, "SD\n"); 37 return sprintf(buf, "SD\n");
38 case MMC_TYPE_SDIO: 38 case MMC_TYPE_SDIO:
39 return sprintf(buf, "SDIO\n"); 39 return sprintf(buf, "SDIO\n");
40 case MMC_TYPE_SD_COMBO:
41 return sprintf(buf, "SDcombo\n");
40 default: 42 default:
41 return -EFAULT; 43 return -EFAULT;
42 } 44 }
@@ -74,6 +76,9 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
74 case MMC_TYPE_SDIO: 76 case MMC_TYPE_SDIO:
75 type = "SDIO"; 77 type = "SDIO";
76 break; 78 break;
79 case MMC_TYPE_SD_COMBO:
80 type = "SDcombo";
81 break;
77 default: 82 default:
78 type = NULL; 83 type = NULL;
79 } 84 }
@@ -239,6 +244,10 @@ int mmc_add_card(struct mmc_card *card)
239 case MMC_TYPE_SDIO: 244 case MMC_TYPE_SDIO:
240 type = "SDIO"; 245 type = "SDIO";
241 break; 246 break;
247 case MMC_TYPE_SD_COMBO:
248 type = "SD-combo";
249 if (mmc_card_blockaddr(card))
250 type = "SDHC-combo";
242 default: 251 default:
243 type = "?"; 252 type = "?";
244 break; 253 break;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 569e94da844c..b69ce91b11e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1099,8 +1099,15 @@ void mmc_rescan(struct work_struct *work)
1099 */ 1099 */
1100 err = mmc_send_io_op_cond(host, 0, &ocr); 1100 err = mmc_send_io_op_cond(host, 0, &ocr);
1101 if (!err) { 1101 if (!err) {
1102 if (mmc_attach_sdio(host, ocr)) 1102 if (mmc_attach_sdio(host, ocr)) {
1103 mmc_power_off(host); 1103 mmc_claim_host(host);
1104 /* try SDMEM (but not MMC) even if SDIO is broken */
1105 if (mmc_send_app_op_cond(host, 0, &ocr))
1106 goto out_fail;
1107
1108 if (mmc_attach_sd(host, ocr))
1109 mmc_power_off(host);
1110 }
1104 goto out; 1111 goto out;
1105 } 1112 }
1106 1113
@@ -1124,6 +1131,7 @@ void mmc_rescan(struct work_struct *work)
1124 goto out; 1131 goto out;
1125 } 1132 }
1126 1133
1134out_fail:
1127 mmc_release_host(host); 1135 mmc_release_host(host);
1128 mmc_power_off(host); 1136 mmc_power_off(host);
1129 1137
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 47d1708810bd..b0b6ce93e519 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -160,9 +160,7 @@ static int sdio_enable_wide(struct mmc_card *card)
160 if (ret) 160 if (ret)
161 return ret; 161 return ret;
162 162
163 mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); 163 return 1;
164
165 return 0;
166} 164}
167 165
168/* 166/*
@@ -222,10 +220,34 @@ static int sdio_disable_wide(struct mmc_card *card)
222 return 0; 220 return 0;
223} 221}
224 222
223
224static int sdio_enable_4bit_bus(struct mmc_card *card)
225{
226 int err;
227
228 if (card->type == MMC_TYPE_SDIO)
229 return sdio_enable_wide(card);
230
231 if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
232 (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
233 err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
234 if (err)
235 return err;
236 } else
237 return 0;
238
239 err = sdio_enable_wide(card);
240 if (err <= 0)
241 mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
242
243 return err;
244}
245
246
225/* 247/*
226 * Test if the card supports high-speed mode and, if so, switch to it. 248 * Test if the card supports high-speed mode and, if so, switch to it.
227 */ 249 */
228static int sdio_enable_hs(struct mmc_card *card) 250static int mmc_sdio_switch_hs(struct mmc_card *card, int enable)
229{ 251{
230 int ret; 252 int ret;
231 u8 speed; 253 u8 speed;
@@ -240,7 +262,10 @@ static int sdio_enable_hs(struct mmc_card *card)
240 if (ret) 262 if (ret)
241 return ret; 263 return ret;
242 264
243 speed |= SDIO_SPEED_EHS; 265 if (enable)
266 speed |= SDIO_SPEED_EHS;
267 else
268 speed &= ~SDIO_SPEED_EHS;
244 269
245 ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); 270 ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
246 if (ret) 271 if (ret)
@@ -249,6 +274,24 @@ static int sdio_enable_hs(struct mmc_card *card)
249 return 1; 274 return 1;
250} 275}
251 276
277/*
278 * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported.
279 */
280static int sdio_enable_hs(struct mmc_card *card)
281{
282 int ret;
283
284 ret = mmc_sdio_switch_hs(card, true);
285 if (ret <= 0 || card->type == MMC_TYPE_SDIO)
286 return ret;
287
288 ret = mmc_sd_switch_hs(card);
289 if (ret <= 0)
290 mmc_sdio_switch_hs(card, false);
291
292 return ret;
293}
294
252static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) 295static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
253{ 296{
254 unsigned max_dtr; 297 unsigned max_dtr;
@@ -265,6 +308,9 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
265 max_dtr = card->cis.max_dtr; 308 max_dtr = card->cis.max_dtr;
266 } 309 }
267 310
311 if (card->type == MMC_TYPE_SD_COMBO)
312 max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
313
268 return max_dtr; 314 return max_dtr;
269} 315}
270 316
@@ -310,7 +356,24 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
310 goto err; 356 goto err;
311 } 357 }
312 358
313 card->type = MMC_TYPE_SDIO; 359 err = mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid);
360
361 if (!err) {
362 card->type = MMC_TYPE_SD_COMBO;
363
364 if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
365 memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
366 mmc_remove_card(card);
367 return -ENOENT;
368 }
369 } else {
370 card->type = MMC_TYPE_SDIO;
371
372 if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
373 mmc_remove_card(card);
374 return -ENOENT;
375 }
376 }
314 377
315 /* 378 /*
316 * Call the optional HC's init_card function to handle quirks. 379 * Call the optional HC's init_card function to handle quirks.
@@ -330,6 +393,17 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
330 } 393 }
331 394
332 /* 395 /*
396 * Read CSD, before selecting the card
397 */
398 if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
399 err = mmc_sd_get_csd(host, card);
400 if (err)
401 return err;
402
403 mmc_decode_cid(card);
404 }
405
406 /*
333 * Select card, as all following commands rely on that. 407 * Select card, as all following commands rely on that.
334 */ 408 */
335 if (!powered_resume && !mmc_host_is_spi(host)) { 409 if (!powered_resume && !mmc_host_is_spi(host)) {
@@ -356,14 +430,33 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
356 int same = (card->cis.vendor == oldcard->cis.vendor && 430 int same = (card->cis.vendor == oldcard->cis.vendor &&
357 card->cis.device == oldcard->cis.device); 431 card->cis.device == oldcard->cis.device);
358 mmc_remove_card(card); 432 mmc_remove_card(card);
359 if (!same) { 433 if (!same)
360 err = -ENOENT; 434 return -ENOENT;
361 goto err; 435
362 }
363 card = oldcard; 436 card = oldcard;
364 return 0; 437 return 0;
365 } 438 }
366 439
440 if (card->type == MMC_TYPE_SD_COMBO) {
441 err = mmc_sd_setup_card(host, card, oldcard != NULL);
442 /* handle as SDIO-only card if memory init failed */
443 if (err) {
444 mmc_go_idle(host);
445 if (mmc_host_is_spi(host))
446 /* should not fail, as it worked previously */
447 mmc_spi_set_crc(host, use_spi_crc);
448 card->type = MMC_TYPE_SDIO;
449 } else
450 card->dev.type = &sd_type;
451 }
452
453 /*
454 * If needed, disconnect card detection pull-up resistor.
455 */
456 err = sdio_disable_cd(card);
457 if (err)
458 goto remove;
459
367 /* 460 /*
368 * Switch to high-speed (if supported). 461 * Switch to high-speed (if supported).
369 */ 462 */
@@ -381,8 +474,10 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
381 /* 474 /*
382 * Switch to wider bus (if supported). 475 * Switch to wider bus (if supported).
383 */ 476 */
384 err = sdio_enable_wide(card); 477 err = sdio_enable_4bit_bus(card);
385 if (err) 478 if (err > 0)
479 mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
480 else if (err)
386 goto remove; 481 goto remove;
387 482
388 if (!oldcard) 483 if (!oldcard)
@@ -496,9 +591,14 @@ static int mmc_sdio_resume(struct mmc_host *host)
496 mmc_claim_host(host); 591 mmc_claim_host(host);
497 err = mmc_sdio_init_card(host, host->ocr, host->card, 592 err = mmc_sdio_init_card(host, host->ocr, host->card,
498 (host->pm_flags & MMC_PM_KEEP_POWER)); 593 (host->pm_flags & MMC_PM_KEEP_POWER));
499 if (!err) 594 if (!err) {
500 /* We may have switched to 1-bit mode during suspend. */ 595 /* We may have switched to 1-bit mode during suspend. */
501 err = sdio_enable_wide(host->card); 596 err = sdio_enable_4bit_bus(host->card);
597 if (err > 0) {
598 mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
599 err = 0;
600 }
601 }
502 if (!err && host->sdio_irqs) 602 if (!err && host->sdio_irqs)
503 mmc_signal_sdio_irq(host); 603 mmc_signal_sdio_irq(host);
504 mmc_release_host(host); 604 mmc_release_host(host);
@@ -583,13 +683,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
583 card->sdio_funcs = 0; 683 card->sdio_funcs = 0;
584 684
585 /* 685 /*
586 * If needed, disconnect card detection pull-up resistor.
587 */
588 err = sdio_disable_cd(card);
589 if (err)
590 goto remove;
591
592 /*
593 * Initialize (but don't add) all present functions. 686 * Initialize (but don't add) all present functions.
594 */ 687 */
595 for (i = 0; i < funcs; i++, card->sdio_funcs++) { 688 for (i = 0; i < funcs; i++, card->sdio_funcs++) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index c83c7a7303fd..340d391aecbb 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -93,6 +93,7 @@ struct mmc_card {
93#define MMC_TYPE_MMC 0 /* MMC card */ 93#define MMC_TYPE_MMC 0 /* MMC card */
94#define MMC_TYPE_SD 1 /* SD card */ 94#define MMC_TYPE_SD 1 /* SD card */
95#define MMC_TYPE_SDIO 2 /* SDIO card */ 95#define MMC_TYPE_SDIO 2 /* SDIO card */
96#define MMC_TYPE_SD_COMBO 3 /* SD combo (IO+mem) card */
96 unsigned int state; /* (our) card state */ 97 unsigned int state; /* (our) card state */
97#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ 98#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
98#define MMC_STATE_READONLY (1<<1) /* card is read-only */ 99#define MMC_STATE_READONLY (1<<1) /* card is read-only */