Commit b4f30a17 authored by Adrian Hunter's avatar Adrian Hunter Committed by Ulf Hansson

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: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 75e8a228
...@@ -388,18 +388,9 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) ...@@ -388,18 +388,9 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
{ {
int host_drv_type = SD_DRIVER_TYPE_B; int host_drv_type = SD_DRIVER_TYPE_B;
int card_drv_type = SD_DRIVER_TYPE_B; int card_drv_type = SD_DRIVER_TYPE_B;
int drive_strength; int drive_strength, drv_type;
int err; int err;
/*
* If the host doesn't support any of the Driver Types A,C or D,
* or there is no board specific handler then default Driver
* Type B is used.
*/
if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
| MMC_CAP_DRIVER_TYPE_D)))
return 0;
if (!card->host->ops->select_drive_strength) if (!card->host->ops->select_drive_strength)
return 0; return 0;
...@@ -430,20 +421,22 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) ...@@ -430,20 +421,22 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
mmc_host_clk_hold(card->host); mmc_host_clk_hold(card->host);
drive_strength = card->host->ops->select_drive_strength( drive_strength = card->host->ops->select_drive_strength(
card->sw_caps.uhs_max_dtr, card->sw_caps.uhs_max_dtr,
host_drv_type, card_drv_type); host_drv_type, card_drv_type, &drv_type);
mmc_host_clk_release(card->host); mmc_host_clk_release(card->host);
err = mmc_sd_switch(card, 1, 2, drive_strength, status); if (drive_strength) {
if (err) err = mmc_sd_switch(card, 1, 2, drive_strength, status);
return err; if (err)
return err;
if ((status[15] & 0xF) != drive_strength) { if ((status[15] & 0xF) != drive_strength) {
pr_warn("%s: Problem setting drive strength!\n", pr_warn("%s: Problem setting drive strength!\n",
mmc_hostname(card->host)); mmc_hostname(card->host));
return 0; return 0;
}
} }
mmc_set_driver_type(card->host, drive_strength); if (drv_type)
mmc_set_driver_type(card->host, drv_type);
return 0; return 0;
} }
......
...@@ -404,21 +404,10 @@ static void sdio_select_driver_type(struct mmc_card *card) ...@@ -404,21 +404,10 @@ static void sdio_select_driver_type(struct mmc_card *card)
{ {
int host_drv_type = SD_DRIVER_TYPE_B; int host_drv_type = SD_DRIVER_TYPE_B;
int card_drv_type = SD_DRIVER_TYPE_B; int card_drv_type = SD_DRIVER_TYPE_B;
int drive_strength; int drive_strength, drv_type;
unsigned char card_strength; unsigned char card_strength;
int err; int err;
/*
* If the host doesn't support any of the Driver Types A,C or D,
* or there is no board specific handler then default Driver
* Type B is used.
*/
if (!(card->host->caps &
(MMC_CAP_DRIVER_TYPE_A |
MMC_CAP_DRIVER_TYPE_C |
MMC_CAP_DRIVER_TYPE_D)))
return;
if (!card->host->ops->select_drive_strength) if (!card->host->ops->select_drive_strength)
return; return;
...@@ -448,23 +437,27 @@ static void sdio_select_driver_type(struct mmc_card *card) ...@@ -448,23 +437,27 @@ static void sdio_select_driver_type(struct mmc_card *card)
*/ */
drive_strength = card->host->ops->select_drive_strength( drive_strength = card->host->ops->select_drive_strength(
card->sw_caps.uhs_max_dtr, card->sw_caps.uhs_max_dtr,
host_drv_type, card_drv_type); host_drv_type, card_drv_type, &drv_type);
/* if error just use default for drive strength B */ if (drive_strength) {
err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, /* if error just use default for drive strength B */
&card_strength); err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
if (err) &card_strength);
return; if (err)
return;
card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
card_strength |= host_drive_to_sdio_drive(drive_strength); card_strength |= host_drive_to_sdio_drive(drive_strength);
err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, /* if error default to drive strength B */
card_strength, NULL); err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH,
card_strength, NULL);
if (err)
return;
}
/* if error default to drive strength B */ if (drv_type)
if (!err) mmc_set_driver_type(card->host, drv_type);
mmc_set_driver_type(card->host, drive_strength);
} }
......
...@@ -132,7 +132,8 @@ struct mmc_host_ops { ...@@ -132,7 +132,8 @@ struct mmc_host_ops {
/* Prepare HS400 target operating frequency depending host driver */ /* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios); int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); int (*select_drive_strength)(unsigned int max_dtr, int host_drv,
int card_drv, int *drv_type);
void (*hw_reset)(struct mmc_host *host); void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host); void (*card_event)(struct mmc_host *host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment