summaryrefslogtreecommitdiff
path: root/drivers/mmc/core/mmc_ops.c
diff options
context:
space:
mode:
authorShridhar Rasal <srasal@nvidia.com>2012-01-25 17:54:30 +0530
committerSimone Willett <swillett@nvidia.com>2012-02-10 13:12:17 -0800
commit506e63fcfb563581c4a0417d424e36a75cf51acf (patch)
treee9bf67c45323f25b73c60418c8a2b68b7355182d /drivers/mmc/core/mmc_ops.c
parent9c5ce68dd28bb7d750c47181ebcca6ac6c071eab (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.c70
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;
+}