mmc: core: Allow card drive strength to be different to host
authorAdrian Hunter <adrian.hunter@intel.com>
Fri, 6 Feb 2015 12:12:52 +0000 (14:12 +0200)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 1 Jun 2015 07:07:11 +0000 (09:07 +0200)
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>
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
include/linux/mmc/host.h

index 8f6864a2a05504757375232696cf0ecb51b1a10d..5edd7d8b033e9941d2a7a17c232da42cbc5ffd9e 100644 (file)
@@ -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 card_drv_type = SD_DRIVER_TYPE_B;
-       int drive_strength;
+       int drive_strength, drv_type;
        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)
                return 0;
 
@@ -430,20 +421,22 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
        mmc_host_clk_hold(card->host);
        drive_strength = card->host->ops->select_drive_strength(
                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);
 
-       err = mmc_sd_switch(card, 1, 2, drive_strength, status);
-       if (err)
-               return err;
-
-       if ((status[15] & 0xF) != drive_strength) {
-               pr_warn("%s: Problem setting drive strength!\n",
-                       mmc_hostname(card->host));
-               return 0;
+       if (drive_strength) {
+               err = mmc_sd_switch(card, 1, 2, drive_strength, status);
+               if (err)
+                       return err;
+               if ((status[15] & 0xF) != drive_strength) {
+                       pr_warn("%s: Problem setting drive strength!\n",
+                               mmc_hostname(card->host));
+                       return 0;
+               }
        }
 
-       mmc_set_driver_type(card->host, drive_strength);
+       if (drv_type)
+               mmc_set_driver_type(card->host, drv_type);
 
        return 0;
 }
index 5c1423a3e7d74295df0e6abe677803261f6e4d65..9d87aeb7c75259778f7b8a0720eea641f659bad8 100644 (file)
@@ -404,21 +404,10 @@ static void sdio_select_driver_type(struct mmc_card *card)
 {
        int host_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;
        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)
                return;
 
@@ -448,23 +437,27 @@ static void sdio_select_driver_type(struct mmc_card *card)
         */
        drive_strength = card->host->ops->select_drive_strength(
                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 */
-       err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
-               &card_strength);
-       if (err)
-               return;
+       if (drive_strength) {
+               /* if error just use default for drive strength B */
+               err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
+                                      &card_strength);
+               if (err)
+                       return;
 
-       card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
-       card_strength |= host_drive_to_sdio_drive(drive_strength);
+               card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
+               card_strength |= host_drive_to_sdio_drive(drive_strength);
 
-       err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH,
-               card_strength, NULL);
+               /* if error default to drive strength B */
+               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 (!err)
-               mmc_set_driver_type(card->host, drive_strength);
+       if (drv_type)
+               mmc_set_driver_type(card->host, drv_type);
 }
 
 
index 433eccb50838e9c2b20510e062313932a4d50fc7..da33d18c66c8872114bf05db90949fd9cb7d5371 100644 (file)
@@ -132,7 +132,8 @@ struct mmc_host_ops {
 
        /* Prepare HS400 target operating frequency depending host driver */
        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    (*card_event)(struct mmc_host *host);