Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: core: Allow card drive strength to be different to host

Initialization of UHS-I modes for SD and SDIO cards
employs a callback to allow the host driver to
choose a drive strength value. Currently that
assumes the card drive strength and host driver
type must be the same value. Change to let the
callback make that decision and return both the
card drive strength and host driver type.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Adrian Hunter and committed by
Ulf Hansson
b4f30a17 75e8a228

+33 -46
+13 -20
drivers/mmc/core/sd.c
··· 388 388 { 389 389 int host_drv_type = SD_DRIVER_TYPE_B; 390 390 int card_drv_type = SD_DRIVER_TYPE_B; 391 - int drive_strength; 391 + int drive_strength, drv_type; 392 392 int err; 393 - 394 - /* 395 - * If the host doesn't support any of the Driver Types A,C or D, 396 - * or there is no board specific handler then default Driver 397 - * Type B is used. 398 - */ 399 - if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C 400 - | MMC_CAP_DRIVER_TYPE_D))) 401 - return 0; 402 393 403 394 if (!card->host->ops->select_drive_strength) 404 395 return 0; ··· 421 430 mmc_host_clk_hold(card->host); 422 431 drive_strength = card->host->ops->select_drive_strength( 423 432 card->sw_caps.uhs_max_dtr, 424 - host_drv_type, card_drv_type); 433 + host_drv_type, card_drv_type, &drv_type); 425 434 mmc_host_clk_release(card->host); 426 435 427 - err = mmc_sd_switch(card, 1, 2, drive_strength, status); 428 - if (err) 429 - return err; 430 - 431 - if ((status[15] & 0xF) != drive_strength) { 432 - pr_warn("%s: Problem setting drive strength!\n", 433 - mmc_hostname(card->host)); 434 - return 0; 436 + if (drive_strength) { 437 + err = mmc_sd_switch(card, 1, 2, drive_strength, status); 438 + if (err) 439 + return err; 440 + if ((status[15] & 0xF) != drive_strength) { 441 + pr_warn("%s: Problem setting drive strength!\n", 442 + mmc_hostname(card->host)); 443 + return 0; 444 + } 435 445 } 436 446 437 - mmc_set_driver_type(card->host, drive_strength); 447 + if (drv_type) 448 + mmc_set_driver_type(card->host, drv_type); 438 449 439 450 return 0; 440 451 }
+18 -25
drivers/mmc/core/sdio.c
··· 404 404 { 405 405 int host_drv_type = SD_DRIVER_TYPE_B; 406 406 int card_drv_type = SD_DRIVER_TYPE_B; 407 - int drive_strength; 407 + int drive_strength, drv_type; 408 408 unsigned char card_strength; 409 409 int err; 410 - 411 - /* 412 - * If the host doesn't support any of the Driver Types A,C or D, 413 - * or there is no board specific handler then default Driver 414 - * Type B is used. 415 - */ 416 - if (!(card->host->caps & 417 - (MMC_CAP_DRIVER_TYPE_A | 418 - MMC_CAP_DRIVER_TYPE_C | 419 - MMC_CAP_DRIVER_TYPE_D))) 420 - return; 421 410 422 411 if (!card->host->ops->select_drive_strength) 423 412 return; ··· 437 448 */ 438 449 drive_strength = card->host->ops->select_drive_strength( 439 450 card->sw_caps.uhs_max_dtr, 440 - host_drv_type, card_drv_type); 451 + host_drv_type, card_drv_type, &drv_type); 441 452 442 - /* if error just use default for drive strength B */ 443 - err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, 444 - &card_strength); 445 - if (err) 446 - return; 453 + if (drive_strength) { 454 + /* if error just use default for drive strength B */ 455 + err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, 456 + &card_strength); 457 + if (err) 458 + return; 447 459 448 - card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); 449 - card_strength |= host_drive_to_sdio_drive(drive_strength); 460 + card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); 461 + card_strength |= host_drive_to_sdio_drive(drive_strength); 450 462 451 - err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, 452 - card_strength, NULL); 463 + /* if error default to drive strength B */ 464 + err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, 465 + card_strength, NULL); 466 + if (err) 467 + return; 468 + } 453 469 454 - /* if error default to drive strength B */ 455 - if (!err) 456 - mmc_set_driver_type(card->host, drive_strength); 470 + if (drv_type) 471 + mmc_set_driver_type(card->host, drv_type); 457 472 } 458 473 459 474
+2 -1
include/linux/mmc/host.h
··· 132 132 133 133 /* Prepare HS400 target operating frequency depending host driver */ 134 134 int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios); 135 - int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); 135 + int (*select_drive_strength)(unsigned int max_dtr, int host_drv, 136 + int card_drv, int *drv_type); 136 137 void (*hw_reset)(struct mmc_host *host); 137 138 void (*card_event)(struct mmc_host *host); 138 139