diff options
author | Shridhar Rasal <srasal@nvidia.com> | 2012-01-25 17:54:30 +0530 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-02-10 13:12:17 -0800 |
commit | 506e63fcfb563581c4a0417d424e36a75cf51acf (patch) | |
tree | e9bf67c45323f25b73c60418c8a2b68b7355182d /drivers/mmc/core/mmc_ops.c | |
parent | 9c5ce68dd28bb7d750c47181ebcca6ac6c071eab (diff) |
mmc: core: Add support for BKOPS and HPI interrupt
Added support for starting BKOPS and issuing HPI
commands which are supported by eMMC v4.41 and eMMC
v4.5 cards.
Enable BKOPS and HPI interrupt if the host and card
support it.
Originally reviewed on: http://git-master/r/69778
Bug 919232
Change-Id: I09b33ddc18013e2eeb505fdb28dd8357fa75b569
Signed-off-by: Pavan Kunapuli <pkunapuli@nvidia.com>
Signed-off-by: Shridhar Rasal <srasal@nvidia.com>
Reviewed-on: http://git-master/r/77319
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: Varun Wadekar <vwadekar@nvidia.com>
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 770c3d06f5dc..330b968393d6 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -547,3 +547,73 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); return err; } + +int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) +{ + struct mmc_command cmd = {0}; + unsigned int opcode; + unsigned int flags; + int err; + + opcode = card->ext_csd.hpi_cmd; + flags = MMC_RSP_R1 | MMC_CMD_AC; + + cmd.opcode = opcode; + cmd.arg = card->rca << 16 | 1; + cmd.flags = flags; + + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err) { + pr_warn("%s: error %d interrupting operation. " + "HPI command response %#x\n", mmc_hostname(card->host), + err, cmd.resp[0]); + return err; + } + if (status) + *status = cmd.resp[0]; + + return 0; +} + +int mmc_send_bk_ops_cmd(struct mmc_card *card, bool is_synchronous) +{ + int err; + struct mmc_command cmd; + u32 status; + + BUG_ON(!card); + BUG_ON(!card->host); + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SWITCH; + cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (EXT_CSD_BKOPS_EN << 16) | + (1 << 8) | + EXT_CSD_CMD_SET_NORMAL; + if (is_synchronous) + cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + else + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + if (err) + return err; + + /* Must check status to be sure of no errors */ + do { + err = mmc_send_status(card, &status); + if (err) + return err; + if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) + break; + } while (R1_CURRENT_STATE(status) == 7); + + if (status & 0xFDFFA000) + printk(KERN_ERR "%s: unexpected status %#x after " + "switch", mmc_hostname(card->host), status); + if (status & R1_SWITCH_ERROR) + return -EBADMSG; + + return 0; +} |