Skip to content

Commit 7310ece

Browse files
osctobetorvalds
authored andcommitted
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>
1 parent 71578a1 commit 7310ece

File tree

4 files changed

+134
-23
lines changed

4 files changed

+134
-23
lines changed

drivers/mmc/core/bus.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ static ssize_t mmc_type_show(struct device *dev,
3737
return sprintf(buf, "SD\n");
3838
case MMC_TYPE_SDIO:
3939
return sprintf(buf, "SDIO\n");
40+
case MMC_TYPE_SD_COMBO:
41+
return sprintf(buf, "SDcombo\n");
4042
default:
4143
return -EFAULT;
4244
}
@@ -74,6 +76,9 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
7476
case MMC_TYPE_SDIO:
7577
type = "SDIO";
7678
break;
79+
case MMC_TYPE_SD_COMBO:
80+
type = "SDcombo";
81+
break;
7782
default:
7883
type = NULL;
7984
}
@@ -239,6 +244,10 @@ int mmc_add_card(struct mmc_card *card)
239244
case MMC_TYPE_SDIO:
240245
type = "SDIO";
241246
break;
247+
case MMC_TYPE_SD_COMBO:
248+
type = "SD-combo";
249+
if (mmc_card_blockaddr(card))
250+
type = "SDHC-combo";
242251
default:
243252
type = "?";
244253
break;

drivers/mmc/core/core.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,8 +1099,15 @@ void mmc_rescan(struct work_struct *work)
10991099
*/
11001100
err = mmc_send_io_op_cond(host, 0, &ocr);
11011101
if (!err) {
1102-
if (mmc_attach_sdio(host, ocr))
1103-
mmc_power_off(host);
1102+
if (mmc_attach_sdio(host, ocr)) {
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+
}
11041111
goto out;
11051112
}
11061113

@@ -1124,6 +1131,7 @@ void mmc_rescan(struct work_struct *work)
11241131
goto out;
11251132
}
11261133

1134+
out_fail:
11271135
mmc_release_host(host);
11281136
mmc_power_off(host);
11291137

drivers/mmc/core/sdio.c

Lines changed: 114 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,7 @@ static int sdio_enable_wide(struct mmc_card *card)
160160
if (ret)
161161
return ret;
162162

163-
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
164-
165-
return 0;
163+
return 1;
166164
}
167165

168166
/*
@@ -222,10 +220,34 @@ static int sdio_disable_wide(struct mmc_card *card)
222220
return 0;
223221
}
224222

223+
224+
static 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+
225247
/*
226248
* Test if the card supports high-speed mode and, if so, switch to it.
227249
*/
228-
static int sdio_enable_hs(struct mmc_card *card)
250+
static int mmc_sdio_switch_hs(struct mmc_card *card, int enable)
229251
{
230252
int ret;
231253
u8 speed;
@@ -240,7 +262,10 @@ static int sdio_enable_hs(struct mmc_card *card)
240262
if (ret)
241263
return ret;
242264

243-
speed |= SDIO_SPEED_EHS;
265+
if (enable)
266+
speed |= SDIO_SPEED_EHS;
267+
else
268+
speed &= ~SDIO_SPEED_EHS;
244269

245270
ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
246271
if (ret)
@@ -249,6 +274,24 @@ static int sdio_enable_hs(struct mmc_card *card)
249274
return 1;
250275
}
251276

277+
/*
278+
* Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported.
279+
*/
280+
static 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+
252295
static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
253296
{
254297
unsigned max_dtr;
@@ -265,6 +308,9 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
265308
max_dtr = card->cis.max_dtr;
266309
}
267310

311+
if (card->type == MMC_TYPE_SD_COMBO)
312+
max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
313+
268314
return max_dtr;
269315
}
270316

@@ -310,7 +356,24 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
310356
goto err;
311357
}
312358

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+
}
314377

315378
/*
316379
* Call the optional HC's init_card function to handle quirks.
@@ -329,6 +392,17 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
329392
mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
330393
}
331394

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+
332406
/*
333407
* Select card, as all following commands rely on that.
334408
*/
@@ -356,14 +430,33 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
356430
int same = (card->cis.vendor == oldcard->cis.vendor &&
357431
card->cis.device == oldcard->cis.device);
358432
mmc_remove_card(card);
359-
if (!same) {
360-
err = -ENOENT;
361-
goto err;
362-
}
433+
if (!same)
434+
return -ENOENT;
435+
363436
card = oldcard;
364437
return 0;
365438
}
366439

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+
367460
/*
368461
* Switch to high-speed (if supported).
369462
*/
@@ -381,8 +474,10 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
381474
/*
382475
* Switch to wider bus (if supported).
383476
*/
384-
err = sdio_enable_wide(card);
385-
if (err)
477+
err = sdio_enable_4bit_bus(card);
478+
if (err > 0)
479+
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
480+
else if (err)
386481
goto remove;
387482

388483
if (!oldcard)
@@ -496,9 +591,14 @@ static int mmc_sdio_resume(struct mmc_host *host)
496591
mmc_claim_host(host);
497592
err = mmc_sdio_init_card(host, host->ocr, host->card,
498593
(host->pm_flags & MMC_PM_KEEP_POWER));
499-
if (!err)
594+
if (!err) {
500595
/* 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+
}
502602
if (!err && host->sdio_irqs)
503603
mmc_signal_sdio_irq(host);
504604
mmc_release_host(host);
@@ -582,13 +682,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
582682
funcs = (ocr & 0x70000000) >> 28;
583683
card->sdio_funcs = 0;
584684

585-
/*
586-
* If needed, disconnect card detection pull-up resistor.
587-
*/
588-
err = sdio_disable_cd(card);
589-
if (err)
590-
goto remove;
591-
592685
/*
593686
* Initialize (but don't add) all present functions.
594687
*/

include/linux/mmc/card.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct mmc_card {
9393
#define MMC_TYPE_MMC 0 /* MMC card */
9494
#define MMC_TYPE_SD 1 /* SD card */
9595
#define MMC_TYPE_SDIO 2 /* SDIO card */
96+
#define MMC_TYPE_SD_COMBO 3 /* SD combo (IO+mem) card */
9697
unsigned int state; /* (our) card state */
9798
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
9899
#define MMC_STATE_READONLY (1<<1) /* card is read-only */

0 commit comments

Comments
 (0)