diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/block.c | 4 | ||||
-rw-r--r-- | drivers/mmc/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/mmc/core/core.c | 511 | ||||
-rw-r--r-- | drivers/mmc/core/core.h | 32 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 276 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.h | 27 | ||||
-rw-r--r-- | drivers/mmc/core/sd_ops.c | 316 | ||||
-rw-r--r-- | drivers/mmc/core/sd_ops.h | 25 | ||||
-rw-r--r-- | drivers/mmc/core/sysfs.c | 2 | ||||
-rw-r--r-- | drivers/mmc/core/sysfs.h | 27 |
10 files changed, 758 insertions, 464 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 8a84e4dc1b2a..d24ab234394c 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -32,8 +32,8 @@ | |||
32 | 32 | ||
33 | #include <linux/mmc/card.h> | 33 | #include <linux/mmc/card.h> |
34 | #include <linux/mmc/host.h> | 34 | #include <linux/mmc/host.h> |
35 | #include <linux/mmc/protocol.h> | 35 | #include <linux/mmc/mmc.h> |
36 | #include <linux/mmc/host.h> | 36 | #include <linux/mmc/sd.h> |
37 | 37 | ||
38 | #include <asm/system.h> | 38 | #include <asm/system.h> |
39 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index f911fbd2845b..5977abf3e41b 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile | |||
@@ -7,5 +7,5 @@ ifeq ($(CONFIG_MMC_DEBUG),y) | |||
7 | endif | 7 | endif |
8 | 8 | ||
9 | obj-$(CONFIG_MMC) += mmc_core.o | 9 | obj-$(CONFIG_MMC) += mmc_core.o |
10 | mmc_core-y := core.o sysfs.o | 10 | mmc_core-y := core.o sysfs.o mmc_ops.o sd_ops.o |
11 | 11 | ||
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 334e663e465b..310be2fe1944 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -23,9 +23,14 @@ | |||
23 | 23 | ||
24 | #include <linux/mmc/card.h> | 24 | #include <linux/mmc/card.h> |
25 | #include <linux/mmc/host.h> | 25 | #include <linux/mmc/host.h> |
26 | #include <linux/mmc/protocol.h> | 26 | #include <linux/mmc/mmc.h> |
27 | #include <linux/mmc/sd.h> | ||
27 | 28 | ||
28 | #include "core.h" | 29 | #include "core.h" |
30 | #include "sysfs.h" | ||
31 | |||
32 | #include "mmc_ops.h" | ||
33 | #include "sd_ops.h" | ||
29 | 34 | ||
30 | #define CMD_RETRIES 3 | 35 | #define CMD_RETRIES 3 |
31 | 36 | ||
@@ -191,80 +196,6 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries | |||
191 | EXPORT_SYMBOL(mmc_wait_for_cmd); | 196 | EXPORT_SYMBOL(mmc_wait_for_cmd); |
192 | 197 | ||
193 | /** | 198 | /** |
194 | * mmc_wait_for_app_cmd - start an application command and wait for | ||
195 | completion | ||
196 | * @host: MMC host to start command | ||
197 | * @rca: RCA to send MMC_APP_CMD to | ||
198 | * @cmd: MMC command to start | ||
199 | * @retries: maximum number of retries | ||
200 | * | ||
201 | * Sends a MMC_APP_CMD, checks the card response, sends the command | ||
202 | * in the parameter and waits for it to complete. Return any error | ||
203 | * that occurred while the command was executing. Do not attempt to | ||
204 | * parse the response. | ||
205 | */ | ||
206 | int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca, | ||
207 | struct mmc_command *cmd, int retries) | ||
208 | { | ||
209 | struct mmc_request mrq; | ||
210 | struct mmc_command appcmd; | ||
211 | |||
212 | int i, err; | ||
213 | |||
214 | BUG_ON(!host->claimed); | ||
215 | BUG_ON(retries < 0); | ||
216 | |||
217 | err = MMC_ERR_INVALID; | ||
218 | |||
219 | /* | ||
220 | * We have to resend MMC_APP_CMD for each attempt so | ||
221 | * we cannot use the retries field in mmc_command. | ||
222 | */ | ||
223 | for (i = 0;i <= retries;i++) { | ||
224 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
225 | |||
226 | appcmd.opcode = MMC_APP_CMD; | ||
227 | appcmd.arg = rca << 16; | ||
228 | appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
229 | appcmd.retries = 0; | ||
230 | memset(appcmd.resp, 0, sizeof(appcmd.resp)); | ||
231 | appcmd.data = NULL; | ||
232 | |||
233 | mrq.cmd = &appcmd; | ||
234 | appcmd.data = NULL; | ||
235 | |||
236 | mmc_wait_for_req(host, &mrq); | ||
237 | |||
238 | if (appcmd.error) { | ||
239 | err = appcmd.error; | ||
240 | continue; | ||
241 | } | ||
242 | |||
243 | /* Check that card supported application commands */ | ||
244 | if (!(appcmd.resp[0] & R1_APP_CMD)) | ||
245 | return MMC_ERR_FAILED; | ||
246 | |||
247 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
248 | |||
249 | memset(cmd->resp, 0, sizeof(cmd->resp)); | ||
250 | cmd->retries = 0; | ||
251 | |||
252 | mrq.cmd = cmd; | ||
253 | cmd->data = NULL; | ||
254 | |||
255 | mmc_wait_for_req(host, &mrq); | ||
256 | |||
257 | err = cmd->error; | ||
258 | if (cmd->error == MMC_ERR_NONE) | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | return err; | ||
263 | } | ||
264 | |||
265 | EXPORT_SYMBOL(mmc_wait_for_app_cmd); | ||
266 | |||
267 | /** | ||
268 | * mmc_set_data_timeout - set the timeout for a data command | 199 | * mmc_set_data_timeout - set the timeout for a data command |
269 | * @data: data phase for command | 200 | * @data: data phase for command |
270 | * @card: the MMC card associated with the data transfer | 201 | * @card: the MMC card associated with the data transfer |
@@ -385,60 +316,10 @@ static inline void mmc_set_ios(struct mmc_host *host) | |||
385 | host->ops->set_ios(host, ios); | 316 | host->ops->set_ios(host, ios); |
386 | } | 317 | } |
387 | 318 | ||
388 | static int mmc_select_card(struct mmc_card *card) | 319 | void mmc_set_chip_select(struct mmc_host *host, int mode) |
389 | { | ||
390 | int err; | ||
391 | struct mmc_command cmd; | ||
392 | |||
393 | BUG_ON(!card->host->claimed); | ||
394 | |||
395 | cmd.opcode = MMC_SELECT_CARD; | ||
396 | cmd.arg = card->rca << 16; | ||
397 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
398 | |||
399 | err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES); | ||
400 | if (err != MMC_ERR_NONE) | ||
401 | return err; | ||
402 | |||
403 | /* | ||
404 | * We can only change the bus width of SD cards when | ||
405 | * they are selected so we have to put the handling | ||
406 | * here. | ||
407 | * | ||
408 | * The card is in 1 bit mode by default so | ||
409 | * we only need to change if it supports the | ||
410 | * wider version. | ||
411 | */ | ||
412 | if (mmc_card_sd(card) && | ||
413 | (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) && | ||
414 | (card->host->caps & MMC_CAP_4_BIT_DATA)) { | ||
415 | |||
416 | struct mmc_command cmd; | ||
417 | cmd.opcode = SD_APP_SET_BUS_WIDTH; | ||
418 | cmd.arg = SD_BUS_WIDTH_4; | ||
419 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
420 | |||
421 | err = mmc_wait_for_app_cmd(card->host, card->rca, | ||
422 | &cmd, CMD_RETRIES); | ||
423 | if (err != MMC_ERR_NONE) | ||
424 | return err; | ||
425 | |||
426 | card->host->ios.bus_width = MMC_BUS_WIDTH_4; | ||
427 | mmc_set_ios(card->host); | ||
428 | } | ||
429 | |||
430 | return MMC_ERR_NONE; | ||
431 | } | ||
432 | |||
433 | |||
434 | static inline void mmc_delay(unsigned int ms) | ||
435 | { | 320 | { |
436 | if (ms < 1000 / HZ) { | 321 | host->ios.chip_select = mode; |
437 | cond_resched(); | 322 | mmc_set_ios(host); |
438 | mdelay(ms); | ||
439 | } else { | ||
440 | msleep(ms); | ||
441 | } | ||
442 | } | 323 | } |
443 | 324 | ||
444 | /* | 325 | /* |
@@ -709,32 +590,6 @@ mmc_alloc_card(struct mmc_host *host, u32 *raw_cid) | |||
709 | } | 590 | } |
710 | 591 | ||
711 | /* | 592 | /* |
712 | * Tell attached cards to go to IDLE state | ||
713 | */ | ||
714 | static void mmc_idle_cards(struct mmc_host *host) | ||
715 | { | ||
716 | struct mmc_command cmd; | ||
717 | |||
718 | host->ios.chip_select = MMC_CS_HIGH; | ||
719 | mmc_set_ios(host); | ||
720 | |||
721 | mmc_delay(1); | ||
722 | |||
723 | cmd.opcode = MMC_GO_IDLE_STATE; | ||
724 | cmd.arg = 0; | ||
725 | cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; | ||
726 | |||
727 | mmc_wait_for_cmd(host, &cmd, 0); | ||
728 | |||
729 | mmc_delay(1); | ||
730 | |||
731 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
732 | mmc_set_ios(host); | ||
733 | |||
734 | mmc_delay(1); | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | * Apply power to the MMC stack. This is a two-stage process. | 593 | * Apply power to the MMC stack. This is a two-stage process. |
739 | * First, we enable power to the card without the clock running. | 594 | * First, we enable power to the card without the clock running. |
740 | * We then wait a bit for the power to stabilise. Finally, | 595 | * We then wait a bit for the power to stabilise. Finally, |
@@ -778,97 +633,6 @@ static void mmc_power_off(struct mmc_host *host) | |||
778 | mmc_set_ios(host); | 633 | mmc_set_ios(host); |
779 | } | 634 | } |
780 | 635 | ||
781 | static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | ||
782 | { | ||
783 | struct mmc_command cmd; | ||
784 | int i, err = 0; | ||
785 | |||
786 | cmd.opcode = MMC_SEND_OP_COND; | ||
787 | cmd.arg = ocr; | ||
788 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | ||
789 | |||
790 | for (i = 100; i; i--) { | ||
791 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
792 | if (err != MMC_ERR_NONE) | ||
793 | break; | ||
794 | |||
795 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | ||
796 | break; | ||
797 | |||
798 | err = MMC_ERR_TIMEOUT; | ||
799 | |||
800 | mmc_delay(10); | ||
801 | } | ||
802 | |||
803 | if (rocr) | ||
804 | *rocr = cmd.resp[0]; | ||
805 | |||
806 | return err; | ||
807 | } | ||
808 | |||
809 | static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | ||
810 | { | ||
811 | struct mmc_command cmd; | ||
812 | int i, err = 0; | ||
813 | |||
814 | cmd.opcode = SD_APP_OP_COND; | ||
815 | cmd.arg = ocr; | ||
816 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | ||
817 | |||
818 | for (i = 100; i; i--) { | ||
819 | err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES); | ||
820 | if (err != MMC_ERR_NONE) | ||
821 | break; | ||
822 | |||
823 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | ||
824 | break; | ||
825 | |||
826 | err = MMC_ERR_TIMEOUT; | ||
827 | |||
828 | mmc_delay(10); | ||
829 | } | ||
830 | |||
831 | if (rocr) | ||
832 | *rocr = cmd.resp[0]; | ||
833 | |||
834 | return err; | ||
835 | } | ||
836 | |||
837 | static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) | ||
838 | { | ||
839 | struct mmc_command cmd; | ||
840 | int err, sd2; | ||
841 | static const u8 test_pattern = 0xAA; | ||
842 | |||
843 | /* | ||
844 | * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND | ||
845 | * before SD_APP_OP_COND. This command will harmlessly fail for | ||
846 | * SD 1.0 cards. | ||
847 | */ | ||
848 | cmd.opcode = SD_SEND_IF_COND; | ||
849 | cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; | ||
850 | cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; | ||
851 | |||
852 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
853 | if (err == MMC_ERR_NONE) { | ||
854 | if ((cmd.resp[0] & 0xFF) == test_pattern) { | ||
855 | sd2 = 1; | ||
856 | } else { | ||
857 | sd2 = 0; | ||
858 | err = MMC_ERR_FAILED; | ||
859 | } | ||
860 | } else { | ||
861 | /* | ||
862 | * Treat errors as SD 1.0 card. | ||
863 | */ | ||
864 | sd2 = 0; | ||
865 | err = MMC_ERR_NONE; | ||
866 | } | ||
867 | if (rsd2) | ||
868 | *rsd2 = sd2; | ||
869 | return err; | ||
870 | } | ||
871 | |||
872 | /* | 636 | /* |
873 | * Discover the card by requesting its CID. | 637 | * Discover the card by requesting its CID. |
874 | * | 638 | * |
@@ -878,27 +642,18 @@ static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) | |||
878 | static void mmc_discover_card(struct mmc_host *host) | 642 | static void mmc_discover_card(struct mmc_host *host) |
879 | { | 643 | { |
880 | unsigned int err; | 644 | unsigned int err; |
881 | 645 | u32 cid[4]; | |
882 | struct mmc_command cmd; | ||
883 | 646 | ||
884 | BUG_ON(host->card); | 647 | BUG_ON(host->card); |
885 | 648 | ||
886 | cmd.opcode = MMC_ALL_SEND_CID; | 649 | err = mmc_all_send_cid(host, cid); |
887 | cmd.arg = 0; | ||
888 | cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; | ||
889 | |||
890 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
891 | if (err == MMC_ERR_TIMEOUT) { | ||
892 | err = MMC_ERR_NONE; | ||
893 | return; | ||
894 | } | ||
895 | if (err != MMC_ERR_NONE) { | 650 | if (err != MMC_ERR_NONE) { |
896 | printk(KERN_ERR "%s: error requesting CID: %d\n", | 651 | printk(KERN_ERR "%s: error requesting CID: %d\n", |
897 | mmc_hostname(host), err); | 652 | mmc_hostname(host), err); |
898 | return; | 653 | return; |
899 | } | 654 | } |
900 | 655 | ||
901 | host->card = mmc_alloc_card(host, cmd.resp); | 656 | host->card = mmc_alloc_card(host, cid); |
902 | if (IS_ERR(host->card)) { | 657 | if (IS_ERR(host->card)) { |
903 | err = PTR_ERR(host->card); | 658 | err = PTR_ERR(host->card); |
904 | host->card = NULL; | 659 | host->card = NULL; |
@@ -908,16 +663,10 @@ static void mmc_discover_card(struct mmc_host *host) | |||
908 | if (host->mode == MMC_MODE_SD) { | 663 | if (host->mode == MMC_MODE_SD) { |
909 | host->card->type = MMC_TYPE_SD; | 664 | host->card->type = MMC_TYPE_SD; |
910 | 665 | ||
911 | cmd.opcode = SD_SEND_RELATIVE_ADDR; | 666 | err = mmc_send_relative_addr(host, &host->card->rca); |
912 | cmd.arg = 0; | ||
913 | cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; | ||
914 | |||
915 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
916 | if (err != MMC_ERR_NONE) | 667 | if (err != MMC_ERR_NONE) |
917 | mmc_card_set_dead(host->card); | 668 | mmc_card_set_dead(host->card); |
918 | else { | 669 | else { |
919 | host->card->rca = cmd.resp[0] >> 16; | ||
920 | |||
921 | if (!host->ops->get_ro) { | 670 | if (!host->ops->get_ro) { |
922 | printk(KERN_WARNING "%s: host does not " | 671 | printk(KERN_WARNING "%s: host does not " |
923 | "support reading read-only " | 672 | "support reading read-only " |
@@ -932,11 +681,7 @@ static void mmc_discover_card(struct mmc_host *host) | |||
932 | host->card->type = MMC_TYPE_MMC; | 681 | host->card->type = MMC_TYPE_MMC; |
933 | host->card->rca = 1; | 682 | host->card->rca = 1; |
934 | 683 | ||
935 | cmd.opcode = MMC_SET_RELATIVE_ADDR; | 684 | err = mmc_set_relative_addr(host->card); |
936 | cmd.arg = host->card->rca << 16; | ||
937 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
938 | |||
939 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
940 | if (err != MMC_ERR_NONE) | 685 | if (err != MMC_ERR_NONE) |
941 | mmc_card_set_dead(host->card); | 686 | mmc_card_set_dead(host->card); |
942 | } | 687 | } |
@@ -944,7 +689,6 @@ static void mmc_discover_card(struct mmc_host *host) | |||
944 | 689 | ||
945 | static void mmc_read_csd(struct mmc_host *host) | 690 | static void mmc_read_csd(struct mmc_host *host) |
946 | { | 691 | { |
947 | struct mmc_command cmd; | ||
948 | int err; | 692 | int err; |
949 | 693 | ||
950 | if (!host->card) | 694 | if (!host->card) |
@@ -952,18 +696,12 @@ static void mmc_read_csd(struct mmc_host *host) | |||
952 | if (mmc_card_dead(host->card)) | 696 | if (mmc_card_dead(host->card)) |
953 | return; | 697 | return; |
954 | 698 | ||
955 | cmd.opcode = MMC_SEND_CSD; | 699 | err = mmc_send_csd(host->card, host->card->raw_csd); |
956 | cmd.arg = host->card->rca << 16; | ||
957 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; | ||
958 | |||
959 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
960 | if (err != MMC_ERR_NONE) { | 700 | if (err != MMC_ERR_NONE) { |
961 | mmc_card_set_dead(host->card); | 701 | mmc_card_set_dead(host->card); |
962 | return; | 702 | return; |
963 | } | 703 | } |
964 | 704 | ||
965 | memcpy(host->card->raw_csd, cmd.resp, sizeof(host->card->raw_csd)); | ||
966 | |||
967 | mmc_decode_csd(host->card); | 705 | mmc_decode_csd(host->card); |
968 | mmc_decode_cid(host->card); | 706 | mmc_decode_cid(host->card); |
969 | } | 707 | } |
@@ -971,13 +709,7 @@ static void mmc_read_csd(struct mmc_host *host) | |||
971 | static void mmc_process_ext_csd(struct mmc_host *host) | 709 | static void mmc_process_ext_csd(struct mmc_host *host) |
972 | { | 710 | { |
973 | int err; | 711 | int err; |
974 | |||
975 | struct mmc_request mrq; | ||
976 | struct mmc_command cmd; | ||
977 | struct mmc_data data; | ||
978 | |||
979 | u8 *ext_csd; | 712 | u8 *ext_csd; |
980 | struct scatterlist sg; | ||
981 | 713 | ||
982 | if (!host->card) | 714 | if (!host->card) |
983 | return; | 715 | return; |
@@ -1000,32 +732,8 @@ static void mmc_process_ext_csd(struct mmc_host *host) | |||
1000 | return; | 732 | return; |
1001 | } | 733 | } |
1002 | 734 | ||
1003 | memset(&cmd, 0, sizeof(struct mmc_command)); | 735 | err = mmc_send_ext_csd(host->card, ext_csd); |
1004 | 736 | if (err != MMC_ERR_NONE) { | |
1005 | cmd.opcode = MMC_SEND_EXT_CSD; | ||
1006 | cmd.arg = 0; | ||
1007 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1008 | |||
1009 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1010 | |||
1011 | mmc_set_data_timeout(&data, host->card, 0); | ||
1012 | |||
1013 | data.blksz = 512; | ||
1014 | data.blocks = 1; | ||
1015 | data.flags = MMC_DATA_READ; | ||
1016 | data.sg = &sg; | ||
1017 | data.sg_len = 1; | ||
1018 | |||
1019 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1020 | |||
1021 | mrq.cmd = &cmd; | ||
1022 | mrq.data = &data; | ||
1023 | |||
1024 | sg_init_one(&sg, ext_csd, 512); | ||
1025 | |||
1026 | mmc_wait_for_req(host, &mrq); | ||
1027 | |||
1028 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1029 | if (host->card->csd.capacity == (4096 * 512)) { | 737 | if (host->card->csd.capacity == (4096 * 512)) { |
1030 | printk(KERN_ERR "%s: unable to read EXT_CSD " | 738 | printk(KERN_ERR "%s: unable to read EXT_CSD " |
1031 | "on a possible high capacity card. " | 739 | "on a possible high capacity card. " |
@@ -1066,14 +774,8 @@ static void mmc_process_ext_csd(struct mmc_host *host) | |||
1066 | 774 | ||
1067 | if (host->caps & MMC_CAP_MMC_HIGHSPEED) { | 775 | if (host->caps & MMC_CAP_MMC_HIGHSPEED) { |
1068 | /* Activate highspeed support. */ | 776 | /* Activate highspeed support. */ |
1069 | cmd.opcode = MMC_SWITCH; | 777 | err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE, |
1070 | cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | 778 | EXT_CSD_HS_TIMING, 1); |
1071 | (EXT_CSD_HS_TIMING << 16) | | ||
1072 | (1 << 8) | | ||
1073 | EXT_CSD_CMD_SET_NORMAL; | ||
1074 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | ||
1075 | |||
1076 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
1077 | if (err != MMC_ERR_NONE) { | 779 | if (err != MMC_ERR_NONE) { |
1078 | printk("%s: failed to switch card to mmc v4 " | 780 | printk("%s: failed to switch card to mmc v4 " |
1079 | "high-speed mode.\n", | 781 | "high-speed mode.\n", |
@@ -1090,14 +792,9 @@ static void mmc_process_ext_csd(struct mmc_host *host) | |||
1090 | /* Check for host support for wide-bus modes. */ | 792 | /* Check for host support for wide-bus modes. */ |
1091 | if (host->caps & MMC_CAP_4_BIT_DATA) { | 793 | if (host->caps & MMC_CAP_4_BIT_DATA) { |
1092 | /* Activate 4-bit support. */ | 794 | /* Activate 4-bit support. */ |
1093 | cmd.opcode = MMC_SWITCH; | 795 | err = mmc_switch(host->card, MMC_SWITCH_MODE_WRITE_BYTE, |
1094 | cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | 796 | EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4 | |
1095 | (EXT_CSD_BUS_WIDTH << 16) | | 797 | EXT_CSD_CMD_SET_NORMAL); |
1096 | (EXT_CSD_BUS_WIDTH_4 << 8) | | ||
1097 | EXT_CSD_CMD_SET_NORMAL; | ||
1098 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | ||
1099 | |||
1100 | err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); | ||
1101 | if (err != MMC_ERR_NONE) { | 798 | if (err != MMC_ERR_NONE) { |
1102 | printk("%s: failed to switch card to " | 799 | printk("%s: failed to switch card to " |
1103 | "mmc v4 4-bit bus mode.\n", | 800 | "mmc v4 4-bit bus mode.\n", |
@@ -1116,10 +813,6 @@ out: | |||
1116 | static void mmc_read_scr(struct mmc_host *host) | 813 | static void mmc_read_scr(struct mmc_host *host) |
1117 | { | 814 | { |
1118 | int err; | 815 | int err; |
1119 | struct mmc_request mrq; | ||
1120 | struct mmc_command cmd; | ||
1121 | struct mmc_data data; | ||
1122 | struct scatterlist sg; | ||
1123 | 816 | ||
1124 | if (!host->card) | 817 | if (!host->card) |
1125 | return; | 818 | return; |
@@ -1128,61 +821,19 @@ static void mmc_read_scr(struct mmc_host *host) | |||
1128 | if (!mmc_card_sd(host->card)) | 821 | if (!mmc_card_sd(host->card)) |
1129 | return; | 822 | return; |
1130 | 823 | ||
1131 | memset(&cmd, 0, sizeof(struct mmc_command)); | 824 | err = mmc_app_send_scr(host->card, host->card->raw_scr); |
1132 | 825 | if (err != MMC_ERR_NONE) { | |
1133 | cmd.opcode = MMC_APP_CMD; | ||
1134 | cmd.arg = host->card->rca << 16; | ||
1135 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
1136 | |||
1137 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
1138 | if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { | ||
1139 | mmc_card_set_dead(host->card); | ||
1140 | return; | ||
1141 | } | ||
1142 | |||
1143 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
1144 | |||
1145 | cmd.opcode = SD_APP_SEND_SCR; | ||
1146 | cmd.arg = 0; | ||
1147 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1148 | |||
1149 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1150 | |||
1151 | mmc_set_data_timeout(&data, host->card, 0); | ||
1152 | |||
1153 | data.blksz = 1 << 3; | ||
1154 | data.blocks = 1; | ||
1155 | data.flags = MMC_DATA_READ; | ||
1156 | data.sg = &sg; | ||
1157 | data.sg_len = 1; | ||
1158 | |||
1159 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1160 | |||
1161 | mrq.cmd = &cmd; | ||
1162 | mrq.data = &data; | ||
1163 | |||
1164 | sg_init_one(&sg, (u8*)host->card->raw_scr, 8); | ||
1165 | |||
1166 | mmc_wait_for_req(host, &mrq); | ||
1167 | |||
1168 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1169 | mmc_card_set_dead(host->card); | 826 | mmc_card_set_dead(host->card); |
1170 | return; | 827 | return; |
1171 | } | 828 | } |
1172 | 829 | ||
1173 | host->card->raw_scr[0] = ntohl(host->card->raw_scr[0]); | ||
1174 | host->card->raw_scr[1] = ntohl(host->card->raw_scr[1]); | ||
1175 | |||
1176 | mmc_decode_scr(host->card); | 830 | mmc_decode_scr(host->card); |
1177 | } | 831 | } |
1178 | 832 | ||
1179 | static void mmc_read_switch_caps(struct mmc_host *host) | 833 | static void mmc_read_switch_caps(struct mmc_host *host) |
1180 | { | 834 | { |
1181 | struct mmc_request mrq; | 835 | int err; |
1182 | struct mmc_command cmd; | ||
1183 | struct mmc_data data; | ||
1184 | unsigned char *status; | 836 | unsigned char *status; |
1185 | struct scatterlist sg; | ||
1186 | 837 | ||
1187 | if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) | 838 | if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) |
1188 | return; | 839 | return; |
@@ -1204,32 +855,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) | |||
1204 | return; | 855 | return; |
1205 | } | 856 | } |
1206 | 857 | ||
1207 | memset(&cmd, 0, sizeof(struct mmc_command)); | 858 | err = mmc_sd_switch(host->card, SD_SWITCH_CHECK, |
1208 | 859 | SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status); | |
1209 | cmd.opcode = SD_SWITCH; | 860 | if (err != MMC_ERR_NONE) { |
1210 | cmd.arg = 0x00FFFFF1; | ||
1211 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1212 | |||
1213 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1214 | |||
1215 | mmc_set_data_timeout(&data, host->card, 0); | ||
1216 | |||
1217 | data.blksz = 64; | ||
1218 | data.blocks = 1; | ||
1219 | data.flags = MMC_DATA_READ; | ||
1220 | data.sg = &sg; | ||
1221 | data.sg_len = 1; | ||
1222 | |||
1223 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1224 | |||
1225 | mrq.cmd = &cmd; | ||
1226 | mrq.data = &data; | ||
1227 | |||
1228 | sg_init_one(&sg, status, 64); | ||
1229 | |||
1230 | mmc_wait_for_req(host, &mrq); | ||
1231 | |||
1232 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { | ||
1233 | printk("%s: unable to read switch capabilities, " | 861 | printk("%s: unable to read switch capabilities, " |
1234 | "performance might suffer.\n", | 862 | "performance might suffer.\n", |
1235 | mmc_hostname(host)); | 863 | mmc_hostname(host)); |
@@ -1239,33 +867,9 @@ static void mmc_read_switch_caps(struct mmc_host *host) | |||
1239 | if (status[13] & 0x02) | 867 | if (status[13] & 0x02) |
1240 | host->card->sw_caps.hs_max_dtr = 50000000; | 868 | host->card->sw_caps.hs_max_dtr = 50000000; |
1241 | 869 | ||
1242 | memset(&cmd, 0, sizeof(struct mmc_command)); | 870 | err = mmc_sd_switch(host->card, SD_SWITCH_SET, |
1243 | 871 | SD_SWITCH_GRP_ACCESS, SD_SWITCH_ACCESS_HS, status); | |
1244 | cmd.opcode = SD_SWITCH; | 872 | if (err != MMC_ERR_NONE || (status[16] & 0xF) != 1) { |
1245 | cmd.arg = 0x80FFFFF1; | ||
1246 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
1247 | |||
1248 | memset(&data, 0, sizeof(struct mmc_data)); | ||
1249 | |||
1250 | mmc_set_data_timeout(&data, host->card, 0); | ||
1251 | |||
1252 | data.blksz = 64; | ||
1253 | data.blocks = 1; | ||
1254 | data.flags = MMC_DATA_READ; | ||
1255 | data.sg = &sg; | ||
1256 | data.sg_len = 1; | ||
1257 | |||
1258 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
1259 | |||
1260 | mrq.cmd = &cmd; | ||
1261 | mrq.data = &data; | ||
1262 | |||
1263 | sg_init_one(&sg, status, 64); | ||
1264 | |||
1265 | mmc_wait_for_req(host, &mrq); | ||
1266 | |||
1267 | if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || | ||
1268 | (status[16] & 0xF) != 1) { | ||
1269 | printk(KERN_WARNING "%s: Problem switching card " | 873 | printk(KERN_WARNING "%s: Problem switching card " |
1270 | "into high-speed mode!\n", | 874 | "into high-speed mode!\n", |
1271 | mmc_hostname(host)); | 875 | mmc_hostname(host)); |
@@ -1314,16 +918,11 @@ static unsigned int mmc_calculate_clock(struct mmc_host *host) | |||
1314 | */ | 918 | */ |
1315 | static void mmc_check_card(struct mmc_card *card) | 919 | static void mmc_check_card(struct mmc_card *card) |
1316 | { | 920 | { |
1317 | struct mmc_command cmd; | ||
1318 | int err; | 921 | int err; |
1319 | 922 | ||
1320 | BUG_ON(!card); | 923 | BUG_ON(!card); |
1321 | 924 | ||
1322 | cmd.opcode = MMC_SEND_STATUS; | 925 | err = mmc_send_status(card, NULL); |
1323 | cmd.arg = card->rca << 16; | ||
1324 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
1325 | |||
1326 | err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES); | ||
1327 | if (err == MMC_ERR_NONE) | 926 | if (err == MMC_ERR_NONE) |
1328 | return; | 927 | return; |
1329 | 928 | ||
@@ -1338,9 +937,9 @@ static void mmc_setup(struct mmc_host *host) | |||
1338 | host->mode = MMC_MODE_SD; | 937 | host->mode = MMC_MODE_SD; |
1339 | 938 | ||
1340 | mmc_power_up(host); | 939 | mmc_power_up(host); |
1341 | mmc_idle_cards(host); | 940 | mmc_go_idle(host); |
1342 | 941 | ||
1343 | err = mmc_send_if_cond(host, host->ocr_avail, NULL); | 942 | err = mmc_send_if_cond(host, host->ocr_avail); |
1344 | if (err != MMC_ERR_NONE) { | 943 | if (err != MMC_ERR_NONE) { |
1345 | return; | 944 | return; |
1346 | } | 945 | } |
@@ -1369,7 +968,7 @@ static void mmc_setup(struct mmc_host *host) | |||
1369 | * state. We wait 1ms to give cards time to | 968 | * state. We wait 1ms to give cards time to |
1370 | * respond. | 969 | * respond. |
1371 | */ | 970 | */ |
1372 | mmc_idle_cards(host); | 971 | mmc_go_idle(host); |
1373 | 972 | ||
1374 | /* | 973 | /* |
1375 | * Send the selected OCR multiple times... until the cards | 974 | * Send the selected OCR multiple times... until the cards |
@@ -1377,17 +976,17 @@ static void mmc_setup(struct mmc_host *host) | |||
1377 | * (My SanDisk card seems to need this.) | 976 | * (My SanDisk card seems to need this.) |
1378 | */ | 977 | */ |
1379 | if (host->mode == MMC_MODE_SD) { | 978 | if (host->mode == MMC_MODE_SD) { |
1380 | int err, sd2; | 979 | /* |
1381 | err = mmc_send_if_cond(host, host->ocr, &sd2); | 980 | * If SD_SEND_IF_COND indicates an SD 2.0 |
1382 | if (err == MMC_ERR_NONE) { | 981 | * compliant card and we should set bit 30 |
1383 | /* | 982 | * of the ocr to indicate that we can handle |
1384 | * If SD_SEND_IF_COND indicates an SD 2.0 | 983 | * block-addressed SDHC cards. |
1385 | * compliant card and we should set bit 30 | 984 | */ |
1386 | * of the ocr to indicate that we can handle | 985 | err = mmc_send_if_cond(host, host->ocr); |
1387 | * block-addressed SDHC cards. | 986 | if (err == MMC_ERR_NONE) |
1388 | */ | 987 | ocr = host->ocr | (1 << 30); |
1389 | mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); | 988 | |
1390 | } | 989 | mmc_send_app_op_cond(host, ocr, NULL); |
1391 | } else { | 990 | } else { |
1392 | /* The extra bit indicates that we support high capacity */ | 991 | /* The extra bit indicates that we support high capacity */ |
1393 | mmc_send_op_cond(host, host->ocr | (1 << 30), NULL); | 992 | mmc_send_op_cond(host, host->ocr | (1 << 30), NULL); |
@@ -1409,6 +1008,24 @@ static void mmc_setup(struct mmc_host *host) | |||
1409 | mmc_card_set_dead(host->card); | 1008 | mmc_card_set_dead(host->card); |
1410 | } | 1009 | } |
1411 | 1010 | ||
1011 | /* | ||
1012 | * The card is in 1 bit mode by default so | ||
1013 | * we only need to change if it supports the | ||
1014 | * wider version. | ||
1015 | */ | ||
1016 | if (host->card && !mmc_card_dead(host->card) && | ||
1017 | mmc_card_sd(host->card) && | ||
1018 | (host->card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) && | ||
1019 | (host->card->host->caps & MMC_CAP_4_BIT_DATA)) { | ||
1020 | err = mmc_app_set_bus_width(host->card, SD_BUS_WIDTH_4); | ||
1021 | if (err != MMC_ERR_NONE) | ||
1022 | mmc_card_set_dead(host->card); | ||
1023 | else { | ||
1024 | host->ios.bus_width = MMC_BUS_WIDTH_4; | ||
1025 | mmc_set_ios(host); | ||
1026 | } | ||
1027 | } | ||
1028 | |||
1412 | if (host->mode == MMC_MODE_SD) { | 1029 | if (host->mode == MMC_MODE_SD) { |
1413 | mmc_read_scr(host); | 1030 | mmc_read_scr(host); |
1414 | mmc_read_switch_caps(host); | 1031 | mmc_read_switch_caps(host); |
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 076cb2f49a0f..1c1066342fba 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h | |||
@@ -2,24 +2,30 @@ | |||
2 | * linux/drivers/mmc/core/core.h | 2 | * linux/drivers/mmc/core/core.h |
3 | * | 3 | * |
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | 4 | * Copyright (C) 2003 Russell King, All Rights Reserved. |
5 | * Copyright 2007 Pierre Ossman | ||
5 | * | 6 | * |
6 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
9 | */ | 10 | */ |
10 | #ifndef _MMC_CORE_H | 11 | #ifndef _MMC_CORE_CORE_H |
11 | #define _MMC_CORE_H | 12 | #define _MMC_CORE_CORE_H |
12 | /* core-internal functions */ | ||
13 | void mmc_init_card(struct mmc_card *card, struct mmc_host *host); | ||
14 | int mmc_register_card(struct mmc_card *card); | ||
15 | void mmc_remove_card(struct mmc_card *card); | ||
16 | 13 | ||
17 | struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); | 14 | #include <linux/delay.h> |
18 | int mmc_add_host_sysfs(struct mmc_host *host); | 15 | |
19 | void mmc_remove_host_sysfs(struct mmc_host *host); | 16 | #define MMC_CMD_RETRIES 3 |
20 | void mmc_free_host_sysfs(struct mmc_host *host); | 17 | |
18 | void mmc_set_chip_select(struct mmc_host *host, int mode); | ||
19 | |||
20 | static inline void mmc_delay(unsigned int ms) | ||
21 | { | ||
22 | if (ms < 1000 / HZ) { | ||
23 | cond_resched(); | ||
24 | mdelay(ms); | ||
25 | } else { | ||
26 | msleep(ms); | ||
27 | } | ||
28 | } | ||
21 | 29 | ||
22 | int mmc_schedule_work(struct work_struct *work); | ||
23 | int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); | ||
24 | void mmc_flush_scheduled_work(void); | ||
25 | #endif | 30 | #endif |
31 | |||
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c new file mode 100644 index 000000000000..7dd720fa5895 --- /dev/null +++ b/drivers/mmc/core/mmc_ops.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/mmc_ops.h | ||
3 | * | ||
4 | * Copyright 2006-2007 Pierre Ossman | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
9 | * your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <asm/scatterlist.h> | ||
14 | #include <linux/scatterlist.h> | ||
15 | |||
16 | #include <linux/mmc/host.h> | ||
17 | #include <linux/mmc/card.h> | ||
18 | #include <linux/mmc/mmc.h> | ||
19 | |||
20 | #include "core.h" | ||
21 | #include "mmc_ops.h" | ||
22 | |||
23 | static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) | ||
24 | { | ||
25 | int err; | ||
26 | struct mmc_command cmd; | ||
27 | |||
28 | BUG_ON(!host); | ||
29 | |||
30 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
31 | |||
32 | cmd.opcode = MMC_SELECT_CARD; | ||
33 | |||
34 | if (card) { | ||
35 | cmd.arg = card->rca << 16; | ||
36 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
37 | } else { | ||
38 | cmd.arg = 0; | ||
39 | cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; | ||
40 | } | ||
41 | |||
42 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | ||
43 | if (err != MMC_ERR_NONE) | ||
44 | return err; | ||
45 | |||
46 | return MMC_ERR_NONE; | ||
47 | } | ||
48 | |||
49 | int mmc_select_card(struct mmc_card *card) | ||
50 | { | ||
51 | BUG_ON(!card); | ||
52 | |||
53 | return _mmc_select_card(card->host, card); | ||
54 | } | ||
55 | |||
56 | int mmc_deselect_cards(struct mmc_host *host) | ||
57 | { | ||
58 | return _mmc_select_card(host, NULL); | ||
59 | } | ||
60 | |||
61 | int mmc_go_idle(struct mmc_host *host) | ||
62 | { | ||
63 | int err; | ||
64 | struct mmc_command cmd; | ||
65 | |||
66 | mmc_set_chip_select(host, MMC_CS_HIGH); | ||
67 | |||
68 | mmc_delay(1); | ||
69 | |||
70 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
71 | |||
72 | cmd.opcode = MMC_GO_IDLE_STATE; | ||
73 | cmd.arg = 0; | ||
74 | cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; | ||
75 | |||
76 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
77 | |||
78 | mmc_delay(1); | ||
79 | |||
80 | mmc_set_chip_select(host, MMC_CS_DONTCARE); | ||
81 | |||
82 | mmc_delay(1); | ||
83 | |||
84 | return err; | ||
85 | } | ||
86 | |||
87 | int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | ||
88 | { | ||
89 | struct mmc_command cmd; | ||
90 | int i, err = 0; | ||
91 | |||
92 | BUG_ON(!host); | ||
93 | |||
94 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
95 | |||
96 | cmd.opcode = MMC_SEND_OP_COND; | ||
97 | cmd.arg = ocr; | ||
98 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | ||
99 | |||
100 | for (i = 100; i; i--) { | ||
101 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
102 | if (err != MMC_ERR_NONE) | ||
103 | break; | ||
104 | |||
105 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | ||
106 | break; | ||
107 | |||
108 | err = MMC_ERR_TIMEOUT; | ||
109 | |||
110 | mmc_delay(10); | ||
111 | } | ||
112 | |||
113 | if (rocr) | ||
114 | *rocr = cmd.resp[0]; | ||
115 | |||
116 | return err; | ||
117 | } | ||
118 | |||
119 | int mmc_all_send_cid(struct mmc_host *host, u32 *cid) | ||
120 | { | ||
121 | int err; | ||
122 | struct mmc_command cmd; | ||
123 | |||
124 | BUG_ON(!host); | ||
125 | BUG_ON(!cid); | ||
126 | |||
127 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
128 | |||
129 | cmd.opcode = MMC_ALL_SEND_CID; | ||
130 | cmd.arg = 0; | ||
131 | cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; | ||
132 | |||
133 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | ||
134 | if (err != MMC_ERR_NONE) | ||
135 | return err; | ||
136 | |||
137 | memcpy(cid, cmd.resp, sizeof(u32) * 4); | ||
138 | |||
139 | return MMC_ERR_NONE; | ||
140 | } | ||
141 | |||
142 | int mmc_set_relative_addr(struct mmc_card *card) | ||
143 | { | ||
144 | int err; | ||
145 | struct mmc_command cmd; | ||
146 | |||
147 | BUG_ON(!card); | ||
148 | BUG_ON(!card->host); | ||
149 | |||
150 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
151 | |||
152 | cmd.opcode = MMC_SET_RELATIVE_ADDR; | ||
153 | cmd.arg = card->rca << 16; | ||
154 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
155 | |||
156 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | ||
157 | if (err != MMC_ERR_NONE) | ||
158 | return err; | ||
159 | |||
160 | return MMC_ERR_NONE; | ||
161 | } | ||
162 | |||
163 | int mmc_send_csd(struct mmc_card *card, u32 *csd) | ||
164 | { | ||
165 | int err; | ||
166 | struct mmc_command cmd; | ||
167 | |||
168 | BUG_ON(!card); | ||
169 | BUG_ON(!card->host); | ||
170 | BUG_ON(!csd); | ||
171 | |||
172 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
173 | |||
174 | cmd.opcode = MMC_SEND_CSD; | ||
175 | cmd.arg = card->rca << 16; | ||
176 | cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; | ||
177 | |||
178 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | ||
179 | if (err != MMC_ERR_NONE) | ||
180 | return err; | ||
181 | |||
182 | memcpy(csd, cmd.resp, sizeof(u32) * 4); | ||
183 | |||
184 | return MMC_ERR_NONE; | ||
185 | } | ||
186 | |||
187 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) | ||
188 | { | ||
189 | struct mmc_request mrq; | ||
190 | struct mmc_command cmd; | ||
191 | struct mmc_data data; | ||
192 | struct scatterlist sg; | ||
193 | |||
194 | BUG_ON(!card); | ||
195 | BUG_ON(!card->host); | ||
196 | BUG_ON(!ext_csd); | ||
197 | |||
198 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
199 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
200 | memset(&data, 0, sizeof(struct mmc_data)); | ||
201 | |||
202 | mrq.cmd = &cmd; | ||
203 | mrq.data = &data; | ||
204 | |||
205 | cmd.opcode = MMC_SEND_EXT_CSD; | ||
206 | cmd.arg = 0; | ||
207 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
208 | |||
209 | data.blksz = 512; | ||
210 | data.blocks = 1; | ||
211 | data.flags = MMC_DATA_READ; | ||
212 | data.sg = &sg; | ||
213 | data.sg_len = 1; | ||
214 | |||
215 | sg_init_one(&sg, ext_csd, 512); | ||
216 | |||
217 | mmc_set_data_timeout(&data, card, 0); | ||
218 | |||
219 | mmc_wait_for_req(card->host, &mrq); | ||
220 | |||
221 | if (cmd.error != MMC_ERR_NONE) | ||
222 | return cmd.error; | ||
223 | if (data.error != MMC_ERR_NONE) | ||
224 | return data.error; | ||
225 | |||
226 | return MMC_ERR_NONE; | ||
227 | } | ||
228 | |||
229 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) | ||
230 | { | ||
231 | int err; | ||
232 | struct mmc_command cmd; | ||
233 | |||
234 | BUG_ON(!card); | ||
235 | BUG_ON(!card->host); | ||
236 | |||
237 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
238 | |||
239 | cmd.opcode = MMC_SWITCH; | ||
240 | cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | | ||
241 | (index << 16) | | ||
242 | (value << 8) | | ||
243 | set; | ||
244 | cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; | ||
245 | |||
246 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | ||
247 | if (err != MMC_ERR_NONE) | ||
248 | return err; | ||
249 | |||
250 | return MMC_ERR_NONE; | ||
251 | } | ||
252 | |||
253 | int mmc_send_status(struct mmc_card *card, u32 *status) | ||
254 | { | ||
255 | int err; | ||
256 | struct mmc_command cmd; | ||
257 | |||
258 | BUG_ON(!card); | ||
259 | BUG_ON(!card->host); | ||
260 | |||
261 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
262 | |||
263 | cmd.opcode = MMC_SEND_STATUS; | ||
264 | cmd.arg = card->rca << 16; | ||
265 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
266 | |||
267 | err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); | ||
268 | if (err != MMC_ERR_NONE) | ||
269 | return err; | ||
270 | |||
271 | if (status) | ||
272 | *status = cmd.resp[0]; | ||
273 | |||
274 | return MMC_ERR_NONE; | ||
275 | } | ||
276 | |||
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h new file mode 100644 index 000000000000..7a481e8ca5ea --- /dev/null +++ b/drivers/mmc/core/mmc_ops.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/mmc_ops.h | ||
3 | * | ||
4 | * Copyright 2006-2007 Pierre Ossman | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
9 | * your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _MMC_MMC_OPS_H | ||
13 | #define _MMC_MMC_OPS_H | ||
14 | |||
15 | int mmc_select_card(struct mmc_card *card); | ||
16 | int mmc_deselect_cards(struct mmc_host *host); | ||
17 | int mmc_go_idle(struct mmc_host *host); | ||
18 | int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); | ||
19 | int mmc_all_send_cid(struct mmc_host *host, u32 *cid); | ||
20 | int mmc_set_relative_addr(struct mmc_card *card); | ||
21 | int mmc_send_csd(struct mmc_card *card, u32 *csd); | ||
22 | int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); | ||
23 | int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value); | ||
24 | int mmc_send_status(struct mmc_card *card, u32 *status); | ||
25 | |||
26 | #endif | ||
27 | |||
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c new file mode 100644 index 000000000000..9697ce581101 --- /dev/null +++ b/drivers/mmc/core/sd_ops.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/sd_ops.h | ||
3 | * | ||
4 | * Copyright 2006-2007 Pierre Ossman | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
9 | * your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/types.h> | ||
13 | #include <asm/scatterlist.h> | ||
14 | #include <linux/scatterlist.h> | ||
15 | |||
16 | #include <linux/mmc/host.h> | ||
17 | #include <linux/mmc/card.h> | ||
18 | #include <linux/mmc/mmc.h> | ||
19 | #include <linux/mmc/sd.h> | ||
20 | |||
21 | #include "core.h" | ||
22 | #include "sd_ops.h" | ||
23 | |||
24 | /** | ||
25 | * mmc_wait_for_app_cmd - start an application command and wait for | ||
26 | completion | ||
27 | * @host: MMC host to start command | ||
28 | * @rca: RCA to send MMC_APP_CMD to | ||
29 | * @cmd: MMC command to start | ||
30 | * @retries: maximum number of retries | ||
31 | * | ||
32 | * Sends a MMC_APP_CMD, checks the card response, sends the command | ||
33 | * in the parameter and waits for it to complete. Return any error | ||
34 | * that occurred while the command was executing. Do not attempt to | ||
35 | * parse the response. | ||
36 | */ | ||
37 | int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, | ||
38 | struct mmc_command *cmd, int retries) | ||
39 | { | ||
40 | struct mmc_request mrq; | ||
41 | |||
42 | int i, err; | ||
43 | |||
44 | BUG_ON(!cmd); | ||
45 | BUG_ON(retries < 0); | ||
46 | |||
47 | err = MMC_ERR_INVALID; | ||
48 | |||
49 | /* | ||
50 | * We have to resend MMC_APP_CMD for each attempt so | ||
51 | * we cannot use the retries field in mmc_command. | ||
52 | */ | ||
53 | for (i = 0;i <= retries;i++) { | ||
54 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
55 | |||
56 | err = mmc_app_cmd(host, card); | ||
57 | if (err != MMC_ERR_NONE) | ||
58 | continue; | ||
59 | |||
60 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
61 | |||
62 | memset(cmd->resp, 0, sizeof(cmd->resp)); | ||
63 | cmd->retries = 0; | ||
64 | |||
65 | mrq.cmd = cmd; | ||
66 | cmd->data = NULL; | ||
67 | |||
68 | mmc_wait_for_req(host, &mrq); | ||
69 | |||
70 | err = cmd->error; | ||
71 | if (cmd->error == MMC_ERR_NONE) | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return err; | ||
76 | } | ||
77 | |||
78 | EXPORT_SYMBOL(mmc_wait_for_app_cmd); | ||
79 | |||
80 | int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) | ||
81 | { | ||
82 | int err; | ||
83 | struct mmc_command cmd; | ||
84 | |||
85 | BUG_ON(!host); | ||
86 | BUG_ON(card && (card->host != host)); | ||
87 | |||
88 | cmd.opcode = MMC_APP_CMD; | ||
89 | |||
90 | if (card) { | ||
91 | cmd.arg = card->rca << 16; | ||
92 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
93 | } else { | ||
94 | cmd.arg = 0; | ||
95 | cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; | ||
96 | } | ||
97 | |||
98 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
99 | if (err != MMC_ERR_NONE) | ||
100 | return err; | ||
101 | |||
102 | /* Check that card supported application commands */ | ||
103 | if (!(cmd.resp[0] & R1_APP_CMD)) | ||
104 | return MMC_ERR_FAILED; | ||
105 | |||
106 | return MMC_ERR_NONE; | ||
107 | } | ||
108 | |||
109 | int mmc_app_set_bus_width(struct mmc_card *card, int width) | ||
110 | { | ||
111 | int err; | ||
112 | struct mmc_command cmd; | ||
113 | |||
114 | BUG_ON(!card); | ||
115 | BUG_ON(!card->host); | ||
116 | |||
117 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
118 | |||
119 | cmd.opcode = SD_APP_SET_BUS_WIDTH; | ||
120 | cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; | ||
121 | |||
122 | switch (width) { | ||
123 | case MMC_BUS_WIDTH_1: | ||
124 | cmd.arg = SD_BUS_WIDTH_1; | ||
125 | break; | ||
126 | case MMC_BUS_WIDTH_4: | ||
127 | cmd.arg = SD_BUS_WIDTH_4; | ||
128 | break; | ||
129 | default: | ||
130 | return MMC_ERR_INVALID; | ||
131 | } | ||
132 | |||
133 | err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); | ||
134 | if (err != MMC_ERR_NONE) | ||
135 | return err; | ||
136 | |||
137 | return MMC_ERR_NONE; | ||
138 | } | ||
139 | |||
140 | int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) | ||
141 | { | ||
142 | struct mmc_command cmd; | ||
143 | int i, err = 0; | ||
144 | |||
145 | BUG_ON(!host); | ||
146 | |||
147 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
148 | |||
149 | cmd.opcode = SD_APP_OP_COND; | ||
150 | cmd.arg = ocr; | ||
151 | cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; | ||
152 | |||
153 | for (i = 100; i; i--) { | ||
154 | err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); | ||
155 | if (err != MMC_ERR_NONE) | ||
156 | break; | ||
157 | |||
158 | if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) | ||
159 | break; | ||
160 | |||
161 | err = MMC_ERR_TIMEOUT; | ||
162 | |||
163 | mmc_delay(10); | ||
164 | } | ||
165 | |||
166 | if (rocr) | ||
167 | *rocr = cmd.resp[0]; | ||
168 | |||
169 | return err; | ||
170 | } | ||
171 | |||
172 | int mmc_send_if_cond(struct mmc_host *host, u32 ocr) | ||
173 | { | ||
174 | struct mmc_command cmd; | ||
175 | int err; | ||
176 | static const u8 test_pattern = 0xAA; | ||
177 | |||
178 | /* | ||
179 | * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND | ||
180 | * before SD_APP_OP_COND. This command will harmlessly fail for | ||
181 | * SD 1.0 cards. | ||
182 | */ | ||
183 | cmd.opcode = SD_SEND_IF_COND; | ||
184 | cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; | ||
185 | cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR; | ||
186 | |||
187 | err = mmc_wait_for_cmd(host, &cmd, 0); | ||
188 | if (err != MMC_ERR_NONE) | ||
189 | return err; | ||
190 | |||
191 | if ((cmd.resp[0] & 0xFF) != test_pattern) | ||
192 | return MMC_ERR_FAILED; | ||
193 | |||
194 | return MMC_ERR_NONE; | ||
195 | } | ||
196 | |||
197 | int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) | ||
198 | { | ||
199 | int err; | ||
200 | struct mmc_command cmd; | ||
201 | |||
202 | BUG_ON(!host); | ||
203 | BUG_ON(!rca); | ||
204 | |||
205 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
206 | |||
207 | cmd.opcode = SD_SEND_RELATIVE_ADDR; | ||
208 | cmd.arg = 0; | ||
209 | cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; | ||
210 | |||
211 | err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); | ||
212 | if (err != MMC_ERR_NONE) | ||
213 | return err; | ||
214 | |||
215 | *rca = cmd.resp[0] >> 16; | ||
216 | |||
217 | return MMC_ERR_NONE; | ||
218 | } | ||
219 | |||
220 | int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | ||
221 | { | ||
222 | int err; | ||
223 | struct mmc_request mrq; | ||
224 | struct mmc_command cmd; | ||
225 | struct mmc_data data; | ||
226 | struct scatterlist sg; | ||
227 | |||
228 | BUG_ON(!card); | ||
229 | BUG_ON(!card->host); | ||
230 | BUG_ON(!scr); | ||
231 | |||
232 | err = mmc_app_cmd(card->host, card); | ||
233 | if (err != MMC_ERR_NONE) | ||
234 | return err; | ||
235 | |||
236 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
237 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
238 | memset(&data, 0, sizeof(struct mmc_data)); | ||
239 | |||
240 | mrq.cmd = &cmd; | ||
241 | mrq.data = &data; | ||
242 | |||
243 | cmd.opcode = SD_APP_SEND_SCR; | ||
244 | cmd.arg = 0; | ||
245 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
246 | |||
247 | data.blksz = 8; | ||
248 | data.blocks = 1; | ||
249 | data.flags = MMC_DATA_READ; | ||
250 | data.sg = &sg; | ||
251 | data.sg_len = 1; | ||
252 | |||
253 | sg_init_one(&sg, scr, 8); | ||
254 | |||
255 | mmc_set_data_timeout(&data, card, 0); | ||
256 | |||
257 | mmc_wait_for_req(card->host, &mrq); | ||
258 | |||
259 | if (cmd.error != MMC_ERR_NONE) | ||
260 | return cmd.error; | ||
261 | if (data.error != MMC_ERR_NONE) | ||
262 | return data.error; | ||
263 | |||
264 | scr[0] = ntohl(scr[0]); | ||
265 | scr[1] = ntohl(scr[1]); | ||
266 | |||
267 | return MMC_ERR_NONE; | ||
268 | } | ||
269 | |||
270 | int mmc_sd_switch(struct mmc_card *card, int mode, int group, | ||
271 | u8 value, u8 *resp) | ||
272 | { | ||
273 | struct mmc_request mrq; | ||
274 | struct mmc_command cmd; | ||
275 | struct mmc_data data; | ||
276 | struct scatterlist sg; | ||
277 | |||
278 | BUG_ON(!card); | ||
279 | BUG_ON(!card->host); | ||
280 | |||
281 | mode = !!mode; | ||
282 | value &= 0xF; | ||
283 | |||
284 | memset(&mrq, 0, sizeof(struct mmc_request)); | ||
285 | memset(&cmd, 0, sizeof(struct mmc_command)); | ||
286 | memset(&data, 0, sizeof(struct mmc_data)); | ||
287 | |||
288 | mrq.cmd = &cmd; | ||
289 | mrq.data = &data; | ||
290 | |||
291 | cmd.opcode = SD_SWITCH; | ||
292 | cmd.arg = mode << 31 | 0x00FFFFFF; | ||
293 | cmd.arg &= ~(0xF << (group * 4)); | ||
294 | cmd.arg |= value << (group * 4); | ||
295 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
296 | |||
297 | data.blksz = 64; | ||
298 | data.blocks = 1; | ||
299 | data.flags = MMC_DATA_READ; | ||
300 | data.sg = &sg; | ||
301 | data.sg_len = 1; | ||
302 | |||
303 | sg_init_one(&sg, resp, 64); | ||
304 | |||
305 | mmc_set_data_timeout(&data, card, 0); | ||
306 | |||
307 | mmc_wait_for_req(card->host, &mrq); | ||
308 | |||
309 | if (cmd.error != MMC_ERR_NONE) | ||
310 | return cmd.error; | ||
311 | if (data.error != MMC_ERR_NONE) | ||
312 | return data.error; | ||
313 | |||
314 | return MMC_ERR_NONE; | ||
315 | } | ||
316 | |||
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h new file mode 100644 index 000000000000..1240fddba5e3 --- /dev/null +++ b/drivers/mmc/core/sd_ops.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/sd_ops.h | ||
3 | * | ||
4 | * Copyright 2006-2007 Pierre Ossman | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
9 | * your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _MMC_SD_OPS_H | ||
13 | #define _MMC_SD_OPS_H | ||
14 | |||
15 | int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card); | ||
16 | int mmc_app_set_bus_width(struct mmc_card *card, int width); | ||
17 | int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr); | ||
18 | int mmc_send_if_cond(struct mmc_host *host, u32 ocr); | ||
19 | int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca); | ||
20 | int mmc_app_send_scr(struct mmc_card *card, u32 *scr); | ||
21 | int mmc_sd_switch(struct mmc_card *card, int mode, int group, | ||
22 | u8 value, u8 *resp); | ||
23 | |||
24 | #endif | ||
25 | |||
diff --git a/drivers/mmc/core/sysfs.c b/drivers/mmc/core/sysfs.c index bf9a5f8beb86..5c9ce02e7e55 100644 --- a/drivers/mmc/core/sysfs.c +++ b/drivers/mmc/core/sysfs.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/mmc/card.h> | 18 | #include <linux/mmc/card.h> |
19 | #include <linux/mmc/host.h> | 19 | #include <linux/mmc/host.h> |
20 | 20 | ||
21 | #include "core.h" | 21 | #include "sysfs.h" |
22 | 22 | ||
23 | #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) | 23 | #define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) |
24 | #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) | 24 | #define to_mmc_driver(d) container_of(d, struct mmc_driver, drv) |
diff --git a/drivers/mmc/core/sysfs.h b/drivers/mmc/core/sysfs.h new file mode 100644 index 000000000000..80e29b358282 --- /dev/null +++ b/drivers/mmc/core/sysfs.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * linux/drivers/mmc/core/sysfs.h | ||
3 | * | ||
4 | * Copyright (C) 2003 Russell King, All Rights Reserved. | ||
5 | * Copyright 2007 Pierre Ossman | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #ifndef _MMC_CORE_SYSFS_H | ||
12 | #define _MMC_CORE_SYSFS_H | ||
13 | |||
14 | void mmc_init_card(struct mmc_card *card, struct mmc_host *host); | ||
15 | int mmc_register_card(struct mmc_card *card); | ||
16 | void mmc_remove_card(struct mmc_card *card); | ||
17 | |||
18 | struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev); | ||
19 | int mmc_add_host_sysfs(struct mmc_host *host); | ||
20 | void mmc_remove_host_sysfs(struct mmc_host *host); | ||
21 | void mmc_free_host_sysfs(struct mmc_host *host); | ||
22 | |||
23 | int mmc_schedule_work(struct work_struct *work); | ||
24 | int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay); | ||
25 | void mmc_flush_scheduled_work(void); | ||
26 | |||
27 | #endif | ||