summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/core/core.c20
-rw-r--r--drivers/mmc/core/sd_ops.c26
-rw-r--r--drivers/mmc/core/sd_ops.h3
-rw-r--r--include/linux/mmc/host.h3
-rw-r--r--include/linux/mmc/sd.h13
5 files changed, 64 insertions, 1 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 35f3df8810e0..3fe73a7c1e99 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2109,6 +2109,26 @@ void mmc_stop_host(struct mmc_host *host)
mmc_power_off(host);
}
+int mmc_speed_class_control(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = -ENOSYS;
+ u32 status;
+
+ err = mmc_send_speed_class_ctrl(host, speed_class_ctrl_arg);
+ if (err)
+ return err;
+
+ /* Issue CMD13 to check for any errors during the busy period of CMD20 */
+ err = mmc_send_status(host->card, &status);
+ if (!err) {
+ if (status & R1_ERROR)
+ err = -EINVAL;
+ }
+ return err;
+}
+EXPORT_SYMBOL(mmc_speed_class_control);
+
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 021fed153804..b06781e69ce3 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -389,3 +389,29 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
return 0;
}
+
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg)
+{
+ int err = 0;
+ struct mmc_command cmd = {
+ .opcode = SD_SPEED_CLASS_CONTROL,
+ .arg = (speed_class_ctrl_arg << 28),
+ .flags = MMC_RSP_R1B | MMC_CMD_AC | MMC_RSP_BUSY,
+ };
+
+ BUG_ON(!host);
+ BUG_ON(speed_class_ctrl_arg > 3);
+ err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+ if (err)
+ return err;
+
+ /*
+ * If the host does not wait while the card signals busy, then we will
+ * will have to wait the max busy indication timeout.
+ */
+ if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+ mmc_delay(1000);
+ return err;
+}
+
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index ffc2305d905f..a77b8facceb4 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -20,6 +20,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp);
int mmc_app_sd_status(struct mmc_card *card, void *ssr);
-
+int mmc_send_speed_class_ctrl(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg);
#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 8c0bf3f2a36f..0e56f1ae7602 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -401,6 +401,9 @@ int mmc_host_enable(struct mmc_host *host);
int mmc_host_disable(struct mmc_host *host);
int mmc_host_lazy_disable(struct mmc_host *host);
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
+int mmc_speed_class_control(struct mmc_host *host,
+ unsigned int speed_class_ctrl_arg);
+
static inline void mmc_set_disable_delay(struct mmc_host *host,
unsigned int disable_delay)
diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
index 1ebcf9ba1256..e65bf7c9dab0 100644
--- a/include/linux/mmc/sd.h
+++ b/include/linux/mmc/sd.h
@@ -19,6 +19,10 @@
#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
#define SD_SWITCH_VOLTAGE 11 /* ac R1 */
+ /* class 2 */
+#define SD_SEND_TUNING_PATTERN 19 /* adtc R1 */
+#define SD_SPEED_CLASS_CONTROL 20 /* ac R1b */
+
/* class 10 */
#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
@@ -91,4 +95,13 @@
#define SD_SWITCH_ACCESS_DEF 0
#define SD_SWITCH_ACCESS_HS 1
+/*
+ * SD_SPEED_CLASS_CONTROL definitions
+ */
+#define SD_SPEED_CLASS_CONTROL_START_REC 0x0
+#define SD_SPEED_CLASS_CONTROL_CREATE_DIR 0x1
+#define SD_SPEED_CLASS_CONTROL_UPDATE_CI 0x4
+
+
#endif /* LINUX_MMC_SD_H */
+