aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Lavinen <jarkko.lavinen@nokia.com>2009-09-22 19:44:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:33 -0400
commitb1ebe38456f7fe61a88af2844361e763ac6ea5ae (patch)
treeb45a2e7afe4f1f6d66d6d38dd1627fa2d6c0e7c7
parenteae1aeeed852aae37621b82a9e7f6c05096a18fd (diff)
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>
-rw-r--r--drivers/mmc/core/core.c40
-rw-r--r--drivers/mmc/core/core.h2
-rw-r--r--drivers/mmc/core/mmc.c54
-rw-r--r--drivers/mmc/core/mmc_ops.c36
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--include/linux/mmc/card.h2
-rw-r--r--include/linux/mmc/host.h5
-rw-r--r--include/linux/mmc/mmc.h2
8 files changed, 137 insertions, 5 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index be1fc013fbe9..828e60ea528c 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1185,6 +1185,46 @@ void mmc_power_restore_host(struct mmc_host *host)
1185} 1185}
1186EXPORT_SYMBOL(mmc_power_restore_host); 1186EXPORT_SYMBOL(mmc_power_restore_host);
1187 1187
1188int 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}
1201EXPORT_SYMBOL(mmc_card_awake);
1202
1203int 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}
1216EXPORT_SYMBOL(mmc_card_sleep);
1217
1218int 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}
1226EXPORT_SYMBOL(mmc_card_can_sleep);
1227
1188#ifdef CONFIG_PM 1228#ifdef CONFIG_PM
1189 1229
1190/** 1230/**
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index f7eb4c4ca014..c386348f5f73 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -16,6 +16,8 @@
16#define MMC_CMD_RETRIES 3 16#define MMC_CMD_RETRIES 3
17 17
18struct mmc_bus_ops { 18struct mmc_bus_ops {
19 int (*awake)(struct mmc_host *);
20 int (*sleep)(struct mmc_host *);
19 void (*remove)(struct mmc_host *); 21 void (*remove)(struct mmc_host *);
20 void (*detect)(struct mmc_host *); 22 void (*detect)(struct mmc_host *);
21 void (*suspend)(struct mmc_host *); 23 void (*suspend)(struct mmc_host *);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 27e842df6a6f..e0bfa9515c8a 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -160,7 +160,6 @@ static int mmc_read_ext_csd(struct mmc_card *card)
160{ 160{
161 int err; 161 int err;
162 u8 *ext_csd; 162 u8 *ext_csd;
163 unsigned int ext_csd_struct;
164 163
165 BUG_ON(!card); 164 BUG_ON(!card);
166 165
@@ -207,16 +206,16 @@ static int mmc_read_ext_csd(struct mmc_card *card)
207 goto out; 206 goto out;
208 } 207 }
209 208
210 ext_csd_struct = ext_csd[EXT_CSD_REV]; 209 card->ext_csd.rev = ext_csd[EXT_CSD_REV];
211 if (ext_csd_struct > 3) { 210 if (card->ext_csd.rev > 3) {
212 printk(KERN_ERR "%s: unrecognised EXT_CSD structure " 211 printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
213 "version %d\n", mmc_hostname(card->host), 212 "version %d\n", mmc_hostname(card->host),
214 ext_csd_struct); 213 card->ext_csd.rev);
215 err = -EINVAL; 214 err = -EINVAL;
216 goto out; 215 goto out;
217 } 216 }
218 217
219 if (ext_csd_struct >= 2) { 218 if (card->ext_csd.rev >= 2) {
220 card->ext_csd.sectors = 219 card->ext_csd.sectors =
221 ext_csd[EXT_CSD_SEC_CNT + 0] << 0 | 220 ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
222 ext_csd[EXT_CSD_SEC_CNT + 1] << 8 | 221 ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
@@ -241,6 +240,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
241 goto out; 240 goto out;
242 } 241 }
243 242
243 if (card->ext_csd.rev >= 3) {
244 u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
245
246 /* Sleep / awake timeout in 100ns units */
247 if (sa_shift > 0 && sa_shift <= 0x17)
248 card->ext_csd.sa_timeout =
249 1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
250 }
251
244out: 252out:
245 kfree(ext_csd); 253 kfree(ext_csd);
246 254
@@ -557,9 +565,41 @@ static void mmc_power_restore(struct mmc_host *host)
557 mmc_release_host(host); 565 mmc_release_host(host);
558} 566}
559 567
568static int mmc_sleep(struct mmc_host *host)
569{
570 struct mmc_card *card = host->card;
571 int err = -ENOSYS;
572
573 if (card && card->ext_csd.rev >= 3) {
574 err = mmc_card_sleepawake(host, 1);
575 if (err < 0)
576 pr_debug("%s: Error %d while putting card into sleep",
577 mmc_hostname(host), err);
578 }
579
580 return err;
581}
582
583static int mmc_awake(struct mmc_host *host)
584{
585 struct mmc_card *card = host->card;
586 int err = -ENOSYS;
587
588 if (card && card->ext_csd.rev >= 3) {
589 err = mmc_card_sleepawake(host, 0);
590 if (err < 0)
591 pr_debug("%s: Error %d while awaking sleeping card",
592 mmc_hostname(host), err);
593 }
594
595 return err;
596}
597
560#ifdef CONFIG_MMC_UNSAFE_RESUME 598#ifdef CONFIG_MMC_UNSAFE_RESUME
561 599
562static const struct mmc_bus_ops mmc_ops = { 600static const struct mmc_bus_ops mmc_ops = {
601 .awake = mmc_awake,
602 .sleep = mmc_sleep,
563 .remove = mmc_remove, 603 .remove = mmc_remove,
564 .detect = mmc_detect, 604 .detect = mmc_detect,
565 .suspend = mmc_suspend, 605 .suspend = mmc_suspend,
@@ -575,6 +615,8 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
575#else 615#else
576 616
577static const struct mmc_bus_ops mmc_ops = { 617static const struct mmc_bus_ops mmc_ops = {
618 .awake = mmc_awake,
619 .sleep = mmc_sleep,
578 .remove = mmc_remove, 620 .remove = mmc_remove,
579 .detect = mmc_detect, 621 .detect = mmc_detect,
580 .suspend = NULL, 622 .suspend = NULL,
@@ -583,6 +625,8 @@ static const struct mmc_bus_ops mmc_ops = {
583}; 625};
584 626
585static const struct mmc_bus_ops mmc_ops_unsafe = { 627static const struct mmc_bus_ops mmc_ops_unsafe = {
628 .awake = mmc_awake,
629 .sleep = mmc_sleep,
586 .remove = mmc_remove, 630 .remove = mmc_remove,
587 .detect = mmc_detect, 631 .detect = mmc_detect,
588 .suspend = mmc_suspend, 632 .suspend = mmc_suspend,
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 34ce2703d29a..355c6042cf65 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -57,6 +57,42 @@ int mmc_deselect_cards(struct mmc_host *host)
57 return _mmc_select_card(host, NULL); 57 return _mmc_select_card(host, NULL);
58} 58}
59 59
60int 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
60int mmc_go_idle(struct mmc_host *host) 96int mmc_go_idle(struct mmc_host *host)
61{ 97{
62 int err; 98 int err;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 17854bf7cf0d..653eb8e84178 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -25,6 +25,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
25int mmc_send_cid(struct mmc_host *host, u32 *cid); 25int mmc_send_cid(struct mmc_host *host, u32 *cid);
26int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); 26int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
27int mmc_spi_set_crc(struct mmc_host *host, int use_crc); 27int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
28int mmc_card_sleepawake(struct mmc_host *host, int sleep);
28 29
29#endif 30#endif
30 31
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 403aa505f27e..58f59174c64b 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -40,6 +40,8 @@ struct mmc_csd {
40}; 40};
41 41
42struct mmc_ext_csd { 42struct mmc_ext_csd {
43 u8 rev;
44 unsigned int sa_timeout; /* Units: 100ns */
43 unsigned int hs_max_dtr; 45 unsigned int hs_max_dtr;
44 unsigned int sectors; 46 unsigned int sectors;
45}; 47};
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index c1cbe598d470..81bb42358595 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -149,6 +149,7 @@ struct mmc_host {
149#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */ 149#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
150#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */ 150#define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
151#define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */ 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 /* host specific block data */ 154 /* host specific block data */
154 unsigned int max_seg_size; /* see blk_queue_max_segment_size */ 155 unsigned int max_seg_size; /* see blk_queue_max_segment_size */
@@ -240,6 +241,10 @@ struct regulator;
240int mmc_regulator_get_ocrmask(struct regulator *supply); 241int mmc_regulator_get_ocrmask(struct regulator *supply);
241int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit); 242int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
242 243
244int mmc_card_awake(struct mmc_host *host);
245int mmc_card_sleep(struct mmc_host *host);
246int mmc_card_can_sleep(struct mmc_host *host);
247
243int mmc_host_enable(struct mmc_host *host); 248int mmc_host_enable(struct mmc_host *host);
244int mmc_host_disable(struct mmc_host *host); 249int mmc_host_disable(struct mmc_host *host);
245int mmc_host_lazy_disable(struct mmc_host *host); 250int mmc_host_lazy_disable(struct mmc_host *host);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 14b81f3e5232..b2b40951c16c 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -31,6 +31,7 @@
31#define MMC_ALL_SEND_CID 2 /* bcr R2 */ 31#define MMC_ALL_SEND_CID 2 /* bcr R2 */
32#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ 32#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
33#define MMC_SET_DSR 4 /* bc [31:16] RCA */ 33#define MMC_SET_DSR 4 /* bc [31:16] RCA */
34#define MMC_SLEEP_AWAKE 5 /* ac [31:16] RCA 15:flg R1b */
34#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ 35#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
35#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ 36#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
36#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ 37#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
@@ -254,6 +255,7 @@ struct _mmc_csd {
254#define EXT_CSD_CARD_TYPE 196 /* RO */ 255#define EXT_CSD_CARD_TYPE 196 /* RO */
255#define EXT_CSD_REV 192 /* RO */ 256#define EXT_CSD_REV 192 /* RO */
256#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ 257#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
258#define EXT_CSD_S_A_TIMEOUT 217
257 259
258/* 260/*
259 * EXT_CSD field definitions 261 * EXT_CSD field definitions