This patch is support the sysfs for operation mode. There are two operation modes(open-ended/pre-defined). Now, operation mode is selected only one at the compile time. But using this patch, we can change the operation mode with node at runtime. * pre-defined mode echo 1 > /sys/class/mmc_host/mmc0/pre_defined_op * open-ended mode echo 0 > /sys/class/mmc_host/mmc0/pre_defined_op Signed-off-by: Jaehoon Chung <jh80.chung@xxxxxxxxxxx> Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx> --- Changelog V3: - Add the mmc_change_operation_mode() Changelog v2: - Add the check point in mmc_cmd23_store() (If host controller didn't support CMD23, need not to change the ops-mode.) drivers/mmc/card/block.c | 19 +++++++++++++++++++ drivers/mmc/core/host.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/mmc/card.h | 1 + include/linux/mmc/host.h | 3 +++ 4 files changed, 62 insertions(+), 0 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 176b78e..2ca72d2 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1765,6 +1765,25 @@ static const struct mmc_fixup blk_fixups[] = END_FIXUP }; +void mmc_change_operation_mode(struct mmc_card *card, int val) +{ + struct mmc_blk_data *md = mmc_get_drvdata(card); + + if (mmc_host_cmd23(card->host)) { + if (mmc_card_mmc(card) || + (mmc_card_sd(card) && + card->scr.cmds & SD_SCR_CMD23_SUPPORT)) { + if (val) { + md->flags |= MMC_BLK_CMD23; + card->host->pre_defined_op = val; + } else { + md->flags &= ~MMC_BLK_CMD23; + card->host->pre_defined_op = val; + } + } + } +} + static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 30055f2..7dab0dc 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -293,6 +293,41 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host) #endif +static ssize_t mmc_cmd23_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + return snprintf(buf, PAGE_SIZE, "%d\n", host->pre_defined_op); +} + +static ssize_t mmc_cmd23_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct mmc_host *host = cls_dev_to_mmc_host(dev); + int value; + unsigned long flags; + + if (kstrtoint(buf, 0, &value)) + return -EINVAL; + + spin_lock_irqsave(&host->lock, flags); + mmc_change_operation_mode(host->card, value); + spin_unlock_irqrestore(&host->lock, flags); + return count; +} + +static inline void mmc_host_cmd23_sysfs_init(struct mmc_host *host) +{ + host->pre_defined_attr.show = mmc_cmd23_show; + host->pre_defined_attr.store = mmc_cmd23_store; + sysfs_attr_init(&host->pre_defined_attr.attr); + host->pre_defined_attr.attr.name = "pre_defined_op"; + host->pre_defined_attr.attr.mode = S_IRUGO | S_IWUSR; + if (device_create_file(&host->class_dev, &host->pre_defined_attr)) + pr_err("%s: Failed to create pre_defined_op sysfs entry\n", + mmc_hostname(host)); +} + /** * mmc_alloc_host - initialise the per-host structure. * @extra: sizeof private data structure @@ -381,6 +416,10 @@ int mmc_add_host(struct mmc_host *host) #endif mmc_host_clk_sysfs_init(host); + if (host->caps & MMC_CAP_CMD23) + host->pre_defined_op = 1; + mmc_host_cmd23_sysfs_init(host); + mmc_start_host(host); register_pm_notifier(&host->pm_notify); diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index f9a0663..6c530f9 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -485,5 +485,6 @@ extern void mmc_unregister_driver(struct mmc_driver *); extern void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table); +extern void mmc_change_operation_mode(struct mmc_card *card, int val); #endif /* LINUX_MMC_CARD_H */ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index dd13e05..16604a2 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -258,6 +258,9 @@ struct mmc_host { #define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \ MMC_CAP2_HS200_1_2V_SDR) + struct device_attribute pre_defined_attr; + int pre_defined_op; /* CMD23 should be use or not */ + mmc_pm_flag_t pm_caps; /* supported pm features */ unsigned int power_notify_type; #define MMC_HOST_PW_NOTIFY_NONE 0 -- To unsubscribe from this list: send the line "unsubscribe linux-mmc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html