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

mmc: add mmc card sleep and awake support

Add support for the new MMC command SLEEP_AWAKE.

Signed-off-by: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
Acked-by: Matt Fleming <matt@console-pimps.org>
Cc: Ian Molton <ian@mnementh.co.uk>
Cc: "Roberto A. Foglietta" <roberto.foglietta@gmail.com>
Cc: Jarkko Lavinen <jarkko.lavinen@nokia.com>
Cc: Denis Karpov <ext-denis.2.karpov@nokia.com>
Cc: Pierre Ossman <pierre@ossman.eu>
Cc: Philip Langdale <philipl@overt.org>
Cc: "Madhusudhan" <madhu.cr@ti.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Jarkko Lavinen and committed by
Linus Torvalds
b1ebe384 eae1aeee

+137 -5
+40
drivers/mmc/core/core.c
··· 1185 1185 } 1186 1186 EXPORT_SYMBOL(mmc_power_restore_host); 1187 1187 1188 + int mmc_card_awake(struct mmc_host *host) 1189 + { 1190 + int err = -ENOSYS; 1191 + 1192 + mmc_bus_get(host); 1193 + 1194 + if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) 1195 + err = host->bus_ops->awake(host); 1196 + 1197 + mmc_bus_put(host); 1198 + 1199 + return err; 1200 + } 1201 + EXPORT_SYMBOL(mmc_card_awake); 1202 + 1203 + int mmc_card_sleep(struct mmc_host *host) 1204 + { 1205 + int err = -ENOSYS; 1206 + 1207 + mmc_bus_get(host); 1208 + 1209 + if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) 1210 + err = host->bus_ops->sleep(host); 1211 + 1212 + mmc_bus_put(host); 1213 + 1214 + return err; 1215 + } 1216 + EXPORT_SYMBOL(mmc_card_sleep); 1217 + 1218 + int mmc_card_can_sleep(struct mmc_host *host) 1219 + { 1220 + struct mmc_card *card = host->card; 1221 + 1222 + if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3) 1223 + return 1; 1224 + return 0; 1225 + } 1226 + EXPORT_SYMBOL(mmc_card_can_sleep); 1227 + 1188 1228 #ifdef CONFIG_PM 1189 1229 1190 1230 /**
+2
drivers/mmc/core/core.h
··· 16 16 #define MMC_CMD_RETRIES 3 17 17 18 18 struct mmc_bus_ops { 19 + int (*awake)(struct mmc_host *); 20 + int (*sleep)(struct mmc_host *); 19 21 void (*remove)(struct mmc_host *); 20 22 void (*detect)(struct mmc_host *); 21 23 void (*suspend)(struct mmc_host *);
+49 -5
drivers/mmc/core/mmc.c
··· 160 160 { 161 161 int err; 162 162 u8 *ext_csd; 163 - unsigned int ext_csd_struct; 164 163 165 164 BUG_ON(!card); 166 165 ··· 206 207 goto out; 207 208 } 208 209 209 - ext_csd_struct = ext_csd[EXT_CSD_REV]; 210 - if (ext_csd_struct > 3) { 210 + card->ext_csd.rev = ext_csd[EXT_CSD_REV]; 211 + if (card->ext_csd.rev > 3) { 211 212 printk(KERN_ERR "%s: unrecognised EXT_CSD structure " 212 213 "version %d\n", mmc_hostname(card->host), 213 - ext_csd_struct); 214 + card->ext_csd.rev); 214 215 err = -EINVAL; 215 216 goto out; 216 217 } 217 218 218 - if (ext_csd_struct >= 2) { 219 + if (card->ext_csd.rev >= 2) { 219 220 card->ext_csd.sectors = 220 221 ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | 221 222 ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | ··· 238 239 "support any high-speed modes.\n", 239 240 mmc_hostname(card->host)); 240 241 goto out; 242 + } 243 + 244 + if (card->ext_csd.rev >= 3) { 245 + u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; 246 + 247 + /* Sleep / awake timeout in 100ns units */ 248 + if (sa_shift > 0 && sa_shift <= 0x17) 249 + card->ext_csd.sa_timeout = 250 + 1 << ext_csd[EXT_CSD_S_A_TIMEOUT]; 241 251 } 242 252 243 253 out: ··· 565 557 mmc_release_host(host); 566 558 } 567 559 560 + static int mmc_sleep(struct mmc_host *host) 561 + { 562 + struct mmc_card *card = host->card; 563 + int err = -ENOSYS; 564 + 565 + if (card && card->ext_csd.rev >= 3) { 566 + err = mmc_card_sleepawake(host, 1); 567 + if (err < 0) 568 + pr_debug("%s: Error %d while putting card into sleep", 569 + mmc_hostname(host), err); 570 + } 571 + 572 + return err; 573 + } 574 + 575 + static int mmc_awake(struct mmc_host *host) 576 + { 577 + struct mmc_card *card = host->card; 578 + int err = -ENOSYS; 579 + 580 + if (card && card->ext_csd.rev >= 3) { 581 + err = mmc_card_sleepawake(host, 0); 582 + if (err < 0) 583 + pr_debug("%s: Error %d while awaking sleeping card", 584 + mmc_hostname(host), err); 585 + } 586 + 587 + return err; 588 + } 589 + 568 590 #ifdef CONFIG_MMC_UNSAFE_RESUME 569 591 570 592 static const struct mmc_bus_ops mmc_ops = { 593 + .awake = mmc_awake, 594 + .sleep = mmc_sleep, 571 595 .remove = mmc_remove, 572 596 .detect = mmc_detect, 573 597 .suspend = mmc_suspend, ··· 615 575 #else 616 576 617 577 static const struct mmc_bus_ops mmc_ops = { 578 + .awake = mmc_awake, 579 + .sleep = mmc_sleep, 618 580 .remove = mmc_remove, 619 581 .detect = mmc_detect, 620 582 .suspend = NULL, ··· 625 583 }; 626 584 627 585 static const struct mmc_bus_ops mmc_ops_unsafe = { 586 + .awake = mmc_awake, 587 + .sleep = mmc_sleep, 628 588 .remove = mmc_remove, 629 589 .detect = mmc_detect, 630 590 .suspend = mmc_suspend,
+36
drivers/mmc/core/mmc_ops.c
··· 57 57 return _mmc_select_card(host, NULL); 58 58 } 59 59 60 + int mmc_card_sleepawake(struct mmc_host *host, int sleep) 61 + { 62 + struct mmc_command cmd; 63 + struct mmc_card *card = host->card; 64 + int err; 65 + 66 + if (sleep) 67 + mmc_deselect_cards(host); 68 + 69 + memset(&cmd, 0, sizeof(struct mmc_command)); 70 + 71 + cmd.opcode = MMC_SLEEP_AWAKE; 72 + cmd.arg = card->rca << 16; 73 + if (sleep) 74 + cmd.arg |= 1 << 15; 75 + 76 + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; 77 + err = mmc_wait_for_cmd(host, &cmd, 0); 78 + if (err) 79 + return err; 80 + 81 + /* 82 + * If the host does not wait while the card signals busy, then we will 83 + * will have to wait the sleep/awake timeout. Note, we cannot use the 84 + * SEND_STATUS command to poll the status because that command (and most 85 + * others) is invalid while the card sleeps. 86 + */ 87 + if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY)) 88 + mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000)); 89 + 90 + if (!sleep) 91 + err = mmc_select_card(card); 92 + 93 + return err; 94 + } 95 + 60 96 int mmc_go_idle(struct mmc_host *host) 61 97 { 62 98 int err;
+1
drivers/mmc/core/mmc_ops.h
··· 25 25 int mmc_send_cid(struct mmc_host *host, u32 *cid); 26 26 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); 27 27 int mmc_spi_set_crc(struct mmc_host *host, int use_crc); 28 + int mmc_card_sleepawake(struct mmc_host *host, int sleep); 28 29 29 30 #endif 30 31
+2
include/linux/mmc/card.h
··· 40 40 }; 41 41 42 42 struct mmc_ext_csd { 43 + u8 rev; 44 + unsigned int sa_timeout; /* Units: 100ns */ 43 45 unsigned int hs_max_dtr; 44 46 unsigned int sectors; 45 47 };
+5
include/linux/mmc/host.h
··· 149 149 #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ 150 150 #define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */ 151 151 #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ 152 + #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */ 152 153 153 154 /* host specific block data */ 154 155 unsigned int max_seg_size; /* see blk_queue_max_segment_size */ ··· 240 239 241 240 int mmc_regulator_get_ocrmask(struct regulator *supply); 242 241 int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); 242 + 243 + int mmc_card_awake(struct mmc_host *host); 244 + int mmc_card_sleep(struct mmc_host *host); 245 + int mmc_card_can_sleep(struct mmc_host *host); 243 246 244 247 int mmc_host_enable(struct mmc_host *host); 245 248 int mmc_host_disable(struct mmc_host *host);
+2
include/linux/mmc/mmc.h
··· 31 31 #define MMC_ALL_SEND_CID 2 /* bcr R2 */ 32 32 #define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ 33 33 #define MMC_SET_DSR 4 /* bc [31:16] RCA */ 34 + #define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */ 34 35 #define MMC_SWITCH 6 /* ac [31:0] See below R1b */ 35 36 #define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ 36 37 #define MMC_SEND_EXT_CSD 8 /* adtc R1 */ ··· 255 254 #define EXT_CSD_CARD_TYPE 196 /* RO */ 256 255 #define EXT_CSD_REV 192 /* RO */ 257 256 #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ 257 + #define EXT_CSD_S_A_TIMEOUT 217 258 258 259 259 /* 260 260 * EXT_CSD field definitions