diff options
author | Minda Chen <Minda.Chen@csr.com> | 2014-11-26 00:05:33 -0500 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2014-11-26 08:36:51 -0500 |
commit | 996903de92f0c7a32d8c83f37d7ebcea0def8660 (patch) | |
tree | e4a4d16b0f9a088c1be9cf57583d676348d1ff50 /drivers/mmc/core/mmc_ops.c | |
parent | c6eb588028f8f23dae8e26312cf192f365c85b95 (diff) |
mmc: core: add core-level function for sending tuning commands
According to the SD card spec, Add a manual tuning command function
for SDR104/HS200.
Sending command 19 or command 21 to read data and compare with the
tunning block pattern.
This patch will help to decrease some platform private codes in SDHCI
platform_execute_tuning() callbacks.
Signed-off-by: Minda Chen <Minda.Chen@csr.com>
Signed-off-by: Barry Song <Baohua.Song@csr.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/core/mmc_ops.c')
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 23aa3a380f27..12b2a32df346 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c | |||
@@ -547,6 +547,76 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, | |||
547 | } | 547 | } |
548 | EXPORT_SYMBOL_GPL(mmc_switch); | 548 | EXPORT_SYMBOL_GPL(mmc_switch); |
549 | 549 | ||
550 | int mmc_send_tuning(struct mmc_card *card) | ||
551 | { | ||
552 | struct mmc_request mrq = {NULL}; | ||
553 | struct mmc_command cmd = {0}; | ||
554 | struct mmc_data data = {0}; | ||
555 | struct scatterlist sg; | ||
556 | struct mmc_host *mmc = card->host; | ||
557 | struct mmc_ios *ios = &mmc->ios; | ||
558 | const u8 *tuning_block_pattern; | ||
559 | int size, err = 0; | ||
560 | u8 *data_buf; | ||
561 | u32 opcode; | ||
562 | |||
563 | if (ios->bus_width == MMC_BUS_WIDTH_8) { | ||
564 | tuning_block_pattern = tuning_blk_pattern_8bit; | ||
565 | size = sizeof(tuning_blk_pattern_8bit); | ||
566 | opcode = MMC_SEND_TUNING_BLOCK_HS200; | ||
567 | } else if (ios->bus_width == MMC_BUS_WIDTH_4) { | ||
568 | tuning_block_pattern = tuning_blk_pattern_4bit; | ||
569 | size = sizeof(tuning_blk_pattern_4bit); | ||
570 | opcode = MMC_SEND_TUNING_BLOCK; | ||
571 | } else | ||
572 | return -EINVAL; | ||
573 | |||
574 | data_buf = kzalloc(size, GFP_KERNEL); | ||
575 | if (!data_buf) | ||
576 | return -ENOMEM; | ||
577 | |||
578 | mrq.cmd = &cmd; | ||
579 | mrq.data = &data; | ||
580 | |||
581 | cmd.opcode = opcode; | ||
582 | cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; | ||
583 | |||
584 | data.blksz = size; | ||
585 | data.blocks = 1; | ||
586 | data.flags = MMC_DATA_READ; | ||
587 | |||
588 | /* | ||
589 | * According to the tuning specs, Tuning process | ||
590 | * is normally shorter 40 executions of CMD19, | ||
591 | * and timeout value should be shorter than 150 ms | ||
592 | */ | ||
593 | data.timeout_ns = 150 * NSEC_PER_MSEC; | ||
594 | |||
595 | data.sg = &sg; | ||
596 | data.sg_len = 1; | ||
597 | sg_init_one(&sg, data_buf, size); | ||
598 | |||
599 | mmc_wait_for_req(mmc, &mrq); | ||
600 | |||
601 | if (cmd.error) { | ||
602 | err = cmd.error; | ||
603 | goto out; | ||
604 | } | ||
605 | |||
606 | if (data.error) { | ||
607 | err = data.error; | ||
608 | goto out; | ||
609 | } | ||
610 | |||
611 | if (memcmp(data_buf, tuning_block_pattern, size)) | ||
612 | err = -EIO; | ||
613 | |||
614 | out: | ||
615 | kfree(data_buf); | ||
616 | return err; | ||
617 | } | ||
618 | EXPORT_SYMBOL_GPL(mmc_send_tuning); | ||
619 | |||
550 | static int | 620 | static int |
551 | mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, | 621 | mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, |
552 | u8 len) | 622 | u8 len) |