|
@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
|
|
{
|
|
|
int err;
|
|
|
u8 *ext_csd;
|
|
|
- unsigned int ext_csd_struct;
|
|
|
|
|
|
BUG_ON(!card);
|
|
|
|
|
@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ext_csd_struct = ext_csd[EXT_CSD_REV];
|
|
|
- if (ext_csd_struct > 3) {
|
|
|
+ card->ext_csd.rev = ext_csd[EXT_CSD_REV];
|
|
|
+ if (card->ext_csd.rev > 3) {
|
|
|
printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
|
|
|
"version %d\n", mmc_hostname(card->host),
|
|
|
- ext_csd_struct);
|
|
|
+ card->ext_csd.rev);
|
|
|
err = -EINVAL;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- if (ext_csd_struct >= 2) {
|
|
|
+ if (card->ext_csd.rev >= 2) {
|
|
|
card->ext_csd.sectors =
|
|
|
ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
|
|
|
ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
|
|
@@ -241,6 +240,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ if (card->ext_csd.rev >= 3) {
|
|
|
+ u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
|
|
|
+
|
|
|
+ /* Sleep / awake timeout in 100ns units */
|
|
|
+ if (sa_shift > 0 && sa_shift <= 0x17)
|
|
|
+ card->ext_csd.sa_timeout =
|
|
|
+ 1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
|
|
|
+ }
|
|
|
+
|
|
|
out:
|
|
|
kfree(ext_csd);
|
|
|
|
|
@@ -557,9 +565,41 @@ static void mmc_power_restore(struct mmc_host *host)
|
|
|
mmc_release_host(host);
|
|
|
}
|
|
|
|
|
|
+static int mmc_sleep(struct mmc_host *host)
|
|
|
+{
|
|
|
+ struct mmc_card *card = host->card;
|
|
|
+ int err = -ENOSYS;
|
|
|
+
|
|
|
+ if (card && card->ext_csd.rev >= 3) {
|
|
|
+ err = mmc_card_sleepawake(host, 1);
|
|
|
+ if (err < 0)
|
|
|
+ pr_debug("%s: Error %d while putting card into sleep",
|
|
|
+ mmc_hostname(host), err);
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+static int mmc_awake(struct mmc_host *host)
|
|
|
+{
|
|
|
+ struct mmc_card *card = host->card;
|
|
|
+ int err = -ENOSYS;
|
|
|
+
|
|
|
+ if (card && card->ext_csd.rev >= 3) {
|
|
|
+ err = mmc_card_sleepawake(host, 0);
|
|
|
+ if (err < 0)
|
|
|
+ pr_debug("%s: Error %d while awaking sleeping card",
|
|
|
+ mmc_hostname(host), err);
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_MMC_UNSAFE_RESUME
|
|
|
|
|
|
static const struct mmc_bus_ops mmc_ops = {
|
|
|
+ .awake = mmc_awake,
|
|
|
+ .sleep = mmc_sleep,
|
|
|
.remove = mmc_remove,
|
|
|
.detect = mmc_detect,
|
|
|
.suspend = mmc_suspend,
|
|
@@ -575,6 +615,8 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
|
|
|
#else
|
|
|
|
|
|
static const struct mmc_bus_ops mmc_ops = {
|
|
|
+ .awake = mmc_awake,
|
|
|
+ .sleep = mmc_sleep,
|
|
|
.remove = mmc_remove,
|
|
|
.detect = mmc_detect,
|
|
|
.suspend = NULL,
|
|
@@ -583,6 +625,8 @@ static const struct mmc_bus_ops mmc_ops = {
|
|
|
};
|
|
|
|
|
|
static const struct mmc_bus_ops mmc_ops_unsafe = {
|
|
|
+ .awake = mmc_awake,
|
|
|
+ .sleep = mmc_sleep,
|
|
|
.remove = mmc_remove,
|
|
|
.detect = mmc_detect,
|
|
|
.suspend = mmc_suspend,
|