diff options
Diffstat (limited to 'drivers/mmc/core/sd.c')
-rw-r--r-- | drivers/mmc/core/sd.c | 318 |
1 files changed, 208 insertions, 110 deletions
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ae54e8eb7fea..6597e778f70e 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c | |||
@@ -263,55 +263,13 @@ out: | |||
263 | } | 263 | } |
264 | 264 | ||
265 | /* | 265 | /* |
266 | * Host is being removed. Free up the current card. | 266 | * Handle the detection and initialisation of a card. |
267 | */ | 267 | * |
268 | static void mmc_sd_remove(struct mmc_host *host) | 268 | * In the case of a resume, "curcard" will contain the card |
269 | { | 269 | * we're trying to reinitialise. |
270 | BUG_ON(!host); | ||
271 | BUG_ON(!host->card); | ||
272 | |||
273 | mmc_remove_card(host->card); | ||
274 | host->card = NULL; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * Card detection callback from host. | ||
279 | */ | ||
280 | static void mmc_sd_detect(struct mmc_host *host) | ||
281 | { | ||
282 | int err; | ||
283 | |||
284 | BUG_ON(!host); | ||
285 | BUG_ON(!host->card); | ||
286 | |||
287 | mmc_claim_host(host); | ||
288 | |||
289 | /* | ||
290 | * Just check if our card has been removed. | ||
291 | */ | ||
292 | err = mmc_send_status(host->card, NULL); | ||
293 | |||
294 | mmc_release_host(host); | ||
295 | |||
296 | if (err != MMC_ERR_NONE) { | ||
297 | mmc_remove_card(host->card); | ||
298 | host->card = NULL; | ||
299 | |||
300 | mmc_claim_host(host); | ||
301 | mmc_detach_bus(host); | ||
302 | mmc_release_host(host); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | static const struct mmc_bus_ops mmc_sd_ops = { | ||
307 | .remove = mmc_sd_remove, | ||
308 | .detect = mmc_sd_detect, | ||
309 | }; | ||
310 | |||
311 | /* | ||
312 | * Starting point for SD card init. | ||
313 | */ | 270 | */ |
314 | int mmc_attach_sd(struct mmc_host *host, u32 ocr) | 271 | static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, |
272 | struct mmc_card *oldcard) | ||
315 | { | 273 | { |
316 | struct mmc_card *card; | 274 | struct mmc_card *card; |
317 | int err; | 275 | int err; |
@@ -321,34 +279,6 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
321 | BUG_ON(!host); | 279 | BUG_ON(!host); |
322 | BUG_ON(!host->claimed); | 280 | BUG_ON(!host->claimed); |
323 | 281 | ||
324 | mmc_attach_bus(host, &mmc_sd_ops); | ||
325 | |||
326 | /* | ||
327 | * Sanity check the voltages that the card claims to | ||
328 | * support. | ||
329 | */ | ||
330 | if (ocr & 0x7F) { | ||
331 | printk(KERN_WARNING "%s: card claims to support voltages " | ||
332 | "below the defined range. These will be ignored.\n", | ||
333 | mmc_hostname(host)); | ||
334 | ocr &= ~0x7F; | ||
335 | } | ||
336 | |||
337 | if (ocr & MMC_VDD_165_195) { | ||
338 | printk(KERN_WARNING "%s: SD card claims to support the " | ||
339 | "incompletely defined 'low voltage range'. This " | ||
340 | "will be ignored.\n", mmc_hostname(host)); | ||
341 | ocr &= ~MMC_VDD_165_195; | ||
342 | } | ||
343 | |||
344 | host->ocr = mmc_select_voltage(host, ocr); | ||
345 | |||
346 | /* | ||
347 | * Can we support the voltage(s) of the card(s)? | ||
348 | */ | ||
349 | if (!host->ocr) | ||
350 | goto err; | ||
351 | |||
352 | /* | 282 | /* |
353 | * Since we're changing the OCR value, we seem to | 283 | * Since we're changing the OCR value, we seem to |
354 | * need to tell some cards to go back to the idle | 284 | * need to tell some cards to go back to the idle |
@@ -363,11 +293,13 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
363 | * of the ocr to indicate that we can handle | 293 | * of the ocr to indicate that we can handle |
364 | * block-addressed SDHC cards. | 294 | * block-addressed SDHC cards. |
365 | */ | 295 | */ |
366 | err = mmc_send_if_cond(host, host->ocr); | 296 | err = mmc_send_if_cond(host, ocr); |
367 | if (err == MMC_ERR_NONE) | 297 | if (err == MMC_ERR_NONE) |
368 | ocr = host->ocr | (1 << 30); | 298 | ocr |= 1 << 30; |
369 | 299 | ||
370 | mmc_send_app_op_cond(host, ocr, NULL); | 300 | err = mmc_send_app_op_cond(host, ocr, NULL); |
301 | if (err != MMC_ERR_NONE) | ||
302 | goto err; | ||
371 | 303 | ||
372 | /* | 304 | /* |
373 | * Fetch CID from card. | 305 | * Fetch CID from card. |
@@ -376,15 +308,22 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
376 | if (err != MMC_ERR_NONE) | 308 | if (err != MMC_ERR_NONE) |
377 | goto err; | 309 | goto err; |
378 | 310 | ||
379 | /* | 311 | if (oldcard) { |
380 | * Allocate card structure. | 312 | if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) |
381 | */ | 313 | goto err; |
382 | card = mmc_alloc_card(host); | ||
383 | if (IS_ERR(card)) | ||
384 | goto err; | ||
385 | 314 | ||
386 | card->type = MMC_TYPE_SD; | 315 | card = oldcard; |
387 | memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); | 316 | } else { |
317 | /* | ||
318 | * Allocate card structure. | ||
319 | */ | ||
320 | card = mmc_alloc_card(host); | ||
321 | if (IS_ERR(card)) | ||
322 | goto err; | ||
323 | |||
324 | card->type = MMC_TYPE_SD; | ||
325 | memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); | ||
326 | } | ||
388 | 327 | ||
389 | /* | 328 | /* |
390 | * Set card RCA. | 329 | * Set card RCA. |
@@ -395,35 +334,42 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
395 | 334 | ||
396 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | 335 | mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); |
397 | 336 | ||
398 | /* | 337 | if (!oldcard) { |
399 | * Fetch CSD from card. | 338 | /* |
400 | */ | 339 | * Fetch CSD from card. |
401 | err = mmc_send_csd(card, card->raw_csd); | 340 | */ |
402 | if (err != MMC_ERR_NONE) | 341 | err = mmc_send_csd(card, card->raw_csd); |
403 | goto free_card; | 342 | if (err != MMC_ERR_NONE) |
343 | goto free_card; | ||
404 | 344 | ||
405 | mmc_decode_csd(card); | 345 | mmc_decode_csd(card); |
406 | mmc_decode_cid(card); | 346 | mmc_decode_cid(card); |
347 | } | ||
407 | 348 | ||
408 | /* | 349 | /* |
409 | * Fetch SCR from card. | 350 | * Select card, as all following commands rely on that. |
410 | */ | 351 | */ |
411 | err = mmc_select_card(card); | 352 | err = mmc_select_card(card); |
412 | if (err != MMC_ERR_NONE) | 353 | if (err != MMC_ERR_NONE) |
413 | goto free_card; | 354 | goto free_card; |
414 | 355 | ||
415 | err = mmc_app_send_scr(card, card->raw_scr); | 356 | if (!oldcard) { |
416 | if (err != MMC_ERR_NONE) | 357 | /* |
417 | goto free_card; | 358 | * Fetch SCR from card. |
359 | */ | ||
360 | err = mmc_app_send_scr(card, card->raw_scr); | ||
361 | if (err != MMC_ERR_NONE) | ||
362 | goto free_card; | ||
418 | 363 | ||
419 | mmc_decode_scr(card); | 364 | mmc_decode_scr(card); |
420 | 365 | ||
421 | /* | 366 | /* |
422 | * Fetch switch information from card. | 367 | * Fetch switch information from card. |
423 | */ | 368 | */ |
424 | err = mmc_read_switch(card); | 369 | err = mmc_read_switch(card); |
425 | if (err != MMC_ERR_NONE) | 370 | if (err != MMC_ERR_NONE) |
426 | goto free_card; | 371 | goto free_card; |
372 | } | ||
427 | 373 | ||
428 | /* | 374 | /* |
429 | * Attempt to change to high-speed (if supported) | 375 | * Attempt to change to high-speed (if supported) |
@@ -458,11 +404,164 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
458 | mmc_set_bus_width(host, MMC_BUS_WIDTH_4); | 404 | mmc_set_bus_width(host, MMC_BUS_WIDTH_4); |
459 | } | 405 | } |
460 | 406 | ||
461 | host->card = card; | 407 | if (!oldcard) |
408 | host->card = card; | ||
409 | |||
410 | return MMC_ERR_NONE; | ||
411 | |||
412 | free_card: | ||
413 | if (!oldcard) | ||
414 | mmc_remove_card(card); | ||
415 | err: | ||
416 | |||
417 | return MMC_ERR_FAILED; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * Host is being removed. Free up the current card. | ||
422 | */ | ||
423 | static void mmc_sd_remove(struct mmc_host *host) | ||
424 | { | ||
425 | BUG_ON(!host); | ||
426 | BUG_ON(!host->card); | ||
427 | |||
428 | mmc_remove_card(host->card); | ||
429 | host->card = NULL; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Card detection callback from host. | ||
434 | */ | ||
435 | static void mmc_sd_detect(struct mmc_host *host) | ||
436 | { | ||
437 | int err; | ||
438 | |||
439 | BUG_ON(!host); | ||
440 | BUG_ON(!host->card); | ||
441 | |||
442 | mmc_claim_host(host); | ||
443 | |||
444 | /* | ||
445 | * Just check if our card has been removed. | ||
446 | */ | ||
447 | err = mmc_send_status(host->card, NULL); | ||
462 | 448 | ||
463 | mmc_release_host(host); | 449 | mmc_release_host(host); |
464 | 450 | ||
465 | err = mmc_register_card(card); | 451 | if (err != MMC_ERR_NONE) { |
452 | mmc_remove_card(host->card); | ||
453 | host->card = NULL; | ||
454 | |||
455 | mmc_claim_host(host); | ||
456 | mmc_detach_bus(host); | ||
457 | mmc_release_host(host); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | #ifdef CONFIG_MMC_UNSAFE_RESUME | ||
462 | |||
463 | /* | ||
464 | * Suspend callback from host. | ||
465 | */ | ||
466 | static void mmc_sd_suspend(struct mmc_host *host) | ||
467 | { | ||
468 | BUG_ON(!host); | ||
469 | BUG_ON(!host->card); | ||
470 | |||
471 | mmc_claim_host(host); | ||
472 | mmc_deselect_cards(host); | ||
473 | host->card->state &= ~MMC_STATE_HIGHSPEED; | ||
474 | mmc_release_host(host); | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Resume callback from host. | ||
479 | * | ||
480 | * This function tries to determine if the same card is still present | ||
481 | * and, if so, restore all state to it. | ||
482 | */ | ||
483 | static void mmc_sd_resume(struct mmc_host *host) | ||
484 | { | ||
485 | int err; | ||
486 | |||
487 | BUG_ON(!host); | ||
488 | BUG_ON(!host->card); | ||
489 | |||
490 | mmc_claim_host(host); | ||
491 | |||
492 | err = mmc_sd_init_card(host, host->ocr, host->card); | ||
493 | if (err != MMC_ERR_NONE) { | ||
494 | mmc_remove_card(host->card); | ||
495 | host->card = NULL; | ||
496 | |||
497 | mmc_detach_bus(host); | ||
498 | } | ||
499 | |||
500 | mmc_release_host(host); | ||
501 | } | ||
502 | |||
503 | #else | ||
504 | |||
505 | #define mmc_sd_suspend NULL | ||
506 | #define mmc_sd_resume NULL | ||
507 | |||
508 | #endif | ||
509 | |||
510 | static const struct mmc_bus_ops mmc_sd_ops = { | ||
511 | .remove = mmc_sd_remove, | ||
512 | .detect = mmc_sd_detect, | ||
513 | .suspend = mmc_sd_suspend, | ||
514 | .resume = mmc_sd_resume, | ||
515 | }; | ||
516 | |||
517 | /* | ||
518 | * Starting point for SD card init. | ||
519 | */ | ||
520 | int mmc_attach_sd(struct mmc_host *host, u32 ocr) | ||
521 | { | ||
522 | int err; | ||
523 | |||
524 | BUG_ON(!host); | ||
525 | BUG_ON(!host->claimed); | ||
526 | |||
527 | mmc_attach_bus(host, &mmc_sd_ops); | ||
528 | |||
529 | /* | ||
530 | * Sanity check the voltages that the card claims to | ||
531 | * support. | ||
532 | */ | ||
533 | if (ocr & 0x7F) { | ||
534 | printk(KERN_WARNING "%s: card claims to support voltages " | ||
535 | "below the defined range. These will be ignored.\n", | ||
536 | mmc_hostname(host)); | ||
537 | ocr &= ~0x7F; | ||
538 | } | ||
539 | |||
540 | if (ocr & MMC_VDD_165_195) { | ||
541 | printk(KERN_WARNING "%s: SD card claims to support the " | ||
542 | "incompletely defined 'low voltage range'. This " | ||
543 | "will be ignored.\n", mmc_hostname(host)); | ||
544 | ocr &= ~MMC_VDD_165_195; | ||
545 | } | ||
546 | |||
547 | host->ocr = mmc_select_voltage(host, ocr); | ||
548 | |||
549 | /* | ||
550 | * Can we support the voltage(s) of the card(s)? | ||
551 | */ | ||
552 | if (!host->ocr) | ||
553 | goto err; | ||
554 | |||
555 | /* | ||
556 | * Detect and init the card. | ||
557 | */ | ||
558 | err = mmc_sd_init_card(host, host->ocr, NULL); | ||
559 | if (err != MMC_ERR_NONE) | ||
560 | goto err; | ||
561 | |||
562 | mmc_release_host(host); | ||
563 | |||
564 | err = mmc_register_card(host->card); | ||
466 | if (err) | 565 | if (err) |
467 | goto reclaim_host; | 566 | goto reclaim_host; |
468 | 567 | ||
@@ -470,8 +569,7 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr) | |||
470 | 569 | ||
471 | reclaim_host: | 570 | reclaim_host: |
472 | mmc_claim_host(host); | 571 | mmc_claim_host(host); |
473 | free_card: | 572 | mmc_remove_card(host->card); |
474 | mmc_remove_card(card); | ||
475 | host->card = NULL; | 573 | host->card = NULL; |
476 | err: | 574 | err: |
477 | mmc_detach_bus(host); | 575 | mmc_detach_bus(host); |