#include "slot-gpio.h"
#include "pwrseq.h"
-#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
-
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
int ret;
bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false;
+ enum of_gpio_flags pwrseq_flags;
+ int pwrseq_gpio;
if (!host->parent || !host->parent->of_node)
return 0;
np = host->parent->of_node;
+ pwrseq_gpio = of_get_named_gpio_flags(np, "pwrseq-gpio", 0, &pwrseq_flags);
+ if ( gpio_is_valid(pwrseq_gpio) ) {
+ ret = devm_gpio_request_one(&host->class_dev, pwrseq_gpio, (pwrseq_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, "sdpwr-gpio");
+ if (ret != 0) {
+ dev_err(&host->class_dev, "request sdcard pwrseq gpio error\n");
+ return -EIO;
+ }
+ };
+
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
dev_dbg(host->parent,
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
if (of_property_read_bool(np, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+ if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+ host->caps2 |= MMC_CAP2_HS400_ES;
+
+ if (of_property_read_bool(np, "supports-sd"))
+ host->restrict_caps |= RESTRICT_CARD_TYPE_SD;
+ if (of_property_read_bool(np, "supports-sdio"))
+ host->restrict_caps |= RESTRICT_CARD_TYPE_SDIO;
+ if (of_property_read_bool(np, "supports-emmc"))
+ host->restrict_caps |= RESTRICT_CARD_TYPE_EMMC;
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
if (host->dsr_req && (host->dsr & ~0xffff)) {
* prepared to start servicing requests before this function
* completes.
*/
+struct mmc_host *primary_sdio_host;
int mmc_add_host(struct mmc_host *host)
{
int err;
mmc_add_host_debugfs(host);
#endif
+#ifdef CONFIG_BLOCK
+ mmc_latency_hist_sysfs_init(host);
+#endif
+
mmc_start_host(host);
if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
register_pm_notifier(&host->pm_notify);
+ if (host->restrict_caps & RESTRICT_CARD_TYPE_SDIO)
+ primary_sdio_host = host;
+
return 0;
}
mmc_remove_host_debugfs(host);
#endif
+#ifdef CONFIG_BLOCK
+ mmc_latency_hist_sysfs_exit(host);
+#endif
+
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
}
EXPORT_SYMBOL(mmc_free_host);
+
+/**
+ * mmc_host_rescan - triger software rescan flow
+ * @host: mmc host
+ *
+ * rescan slot attach in the assigned host.
+ * If @host is NULL, default rescan primary_sdio_host
+ * saved by mmc_add_host().
+ * OR, rescan host from argument.
+ *
+ */
+int mmc_host_rescan(struct mmc_host *host, int val, int is_cap_sdio_irq)
+{
+ if (NULL != primary_sdio_host) {
+ if (!host)
+ host = primary_sdio_host;
+ else
+ pr_info("%s: mmc_host_rescan pass in host from argument!\n",
+ mmc_hostname(host));
+ } else {
+ pr_err("sdio: host isn't initialization successfully.\n");
+ return -ENOMEDIUM;
+ }
+
+ pr_info("%s:mmc host rescan start!\n", mmc_hostname(host));
+
+ /* 0: oob 1:cap-sdio-irq */
+ if (is_cap_sdio_irq == 1) {
+ host->caps |= MMC_CAP_SDIO_IRQ;
+ } else if (is_cap_sdio_irq == 0) {
+ host->caps &= ~MMC_CAP_SDIO_IRQ;
+ } else {
+ dev_err(&host->class_dev, "sdio: host doesn't identify oob or sdio_irq mode!\n");
+ return -ENOMEDIUM;
+ }
+
+ if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->set_sdio_status)
+ host->ops->set_sdio_status(host, val);
+
+ return 0;
+}
+EXPORT_SYMBOL(mmc_host_rescan);