aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/bus.c41
-rw-r--r--drivers/mmc/core/core.c15
-rw-r--r--drivers/mmc/core/mmc.c14
-rw-r--r--drivers/mmc/core/pwrseq.c16
-rw-r--r--drivers/mmc/core/pwrseq.h6
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c11
-rw-r--r--drivers/mmc/core/pwrseq_simple.c11
-rw-r--r--drivers/mmc/core/sd.c4
-rw-r--r--drivers/mmc/core/sdio.c32
9 files changed, 93 insertions, 57 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index c5ef10065a4a..972ff844cf5a 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -26,6 +26,8 @@
#include "sdio_cis.h"
#include "bus.h"
+#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
+
static ssize_t type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -105,14 +107,33 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
+static int mmc_bus_probe(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ return drv->probe(card);
+}
+
+static int mmc_bus_remove(struct device *dev)
+{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ drv->remove(card);
+
+ return 0;
+}
+
static void mmc_bus_shutdown(struct device *dev)
{
+ struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret;
- if (dev->driver && dev->driver->shutdown)
- dev->driver->shutdown(dev);
+ if (dev->driver && drv->shutdown)
+ drv->shutdown(card);
if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host);
@@ -181,6 +202,8 @@ static struct bus_type mmc_bus_type = {
.dev_groups = mmc_dev_groups,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
+ .probe = mmc_bus_probe,
+ .remove = mmc_bus_remove,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
@@ -199,22 +222,24 @@ void mmc_unregister_bus(void)
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
-int mmc_register_driver(struct device_driver *drv)
+int mmc_register_driver(struct mmc_driver *drv)
{
- drv->bus = &mmc_bus_type;
- return driver_register(drv);
+ drv->drv.bus = &mmc_bus_type;
+ return driver_register(&drv->drv);
}
+
EXPORT_SYMBOL(mmc_register_driver);
/**
* mmc_unregister_driver - unregister a media driver
* @drv: MMC media driver
*/
-void mmc_unregister_driver(struct device_driver *drv)
+void mmc_unregister_driver(struct mmc_driver *drv)
{
- drv->bus = &mmc_bus_type;
- driver_unregister(drv);
+ drv->drv.bus = &mmc_bus_type;
+ driver_unregister(&drv->drv);
}
+
EXPORT_SYMBOL(mmc_unregister_driver);
static void mmc_release_card(struct device *dev)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 23f10f72e5f3..c296bc098fe2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -897,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
int stop;
+ bool pm = false;
might_sleep();
@@ -916,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
host->claimed = 1;
host->claimer = current;
host->claim_cnt += 1;
+ if (host->claim_cnt == 1)
+ pm = true;
} else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
- if (host->ops->enable && !stop && host->claim_cnt == 1)
- host->ops->enable(host);
+
+ if (pm)
+ pm_runtime_get_sync(mmc_dev(host));
+
return stop;
}
-
EXPORT_SYMBOL(__mmc_claim_host);
/**
@@ -940,9 +944,6 @@ void mmc_release_host(struct mmc_host *host)
WARN_ON(!host->claimed);
- if (host->ops->disable && host->claim_cnt == 1)
- host->ops->disable(host);
-
spin_lock_irqsave(&host->lock, flags);
if (--host->claim_cnt) {
/* Release for nested claim */
@@ -952,6 +953,8 @@ void mmc_release_host(struct mmc_host *host)
host->claimer = NULL;
spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq);
+ pm_runtime_mark_last_busy(mmc_dev(host));
+ pm_runtime_put_autosuspend(mmc_dev(host));
}
}
EXPORT_SYMBOL(mmc_release_host);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 1d41e8541f38..f36c76f8b232 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -11,6 +11,7 @@
*/
#include <linux/err.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/pm_runtime.h>
@@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, idx;
unsigned int part_size;
+ struct device_node *np;
+ bool broken_hpi = false;
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
@@ -349,6 +352,11 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
}
+ np = mmc_of_find_child_device(card->host, 0);
+ if (np && of_device_is_compatible(np, "mmc-card"))
+ broken_hpi = of_property_read_bool(np, "broken-hpi");
+ of_node_put(np);
+
/*
* The EXT_CSD format is meant to be forward compatible. As long
* as CSD_STRUCTURE does not change, all values for EXT_CSD_REV
@@ -494,7 +502,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
/* check whether the eMMC card supports HPI */
- if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+ if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
@@ -1750,7 +1758,7 @@ static int mmc_runtime_suspend(struct mmc_host *host)
err = _mmc_suspend(host, true);
if (err)
- pr_err("%s: error %d doing aggessive suspend\n",
+ pr_err("%s: error %d doing aggressive suspend\n",
mmc_hostname(host), err);
return err;
@@ -1768,7 +1776,7 @@ static int mmc_runtime_resume(struct mmc_host *host)
err = _mmc_resume(host);
if (err)
- pr_err("%s: error %d doing aggessive resume\n",
+ pr_err("%s: error %d doing aggressive resume\n",
mmc_hostname(host), err);
return 0;
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c
index 862356123d78..4c1d1757dbf9 100644
--- a/drivers/mmc/core/pwrseq.c
+++ b/drivers/mmc/core/pwrseq.c
@@ -19,7 +19,7 @@
struct mmc_pwrseq_match {
const char *compatible;
- int (*alloc)(struct mmc_host *host, struct device *dev);
+ struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);
};
static struct mmc_pwrseq_match pwrseq_match[] = {
@@ -52,6 +52,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
struct platform_device *pdev;
struct device_node *np;
struct mmc_pwrseq_match *match;
+ struct mmc_pwrseq *pwrseq;
int ret = 0;
np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
@@ -70,9 +71,14 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
goto err;
}
- ret = match->alloc(host, &pdev->dev);
- if (!ret)
- dev_info(host->parent, "allocated mmc-pwrseq\n");
+ pwrseq = match->alloc(host, &pdev->dev);
+ if (IS_ERR(pwrseq)) {
+ ret = PTR_ERR(pwrseq);
+ goto err;
+ }
+
+ host->pwrseq = pwrseq;
+ dev_info(host->parent, "allocated mmc-pwrseq\n");
err:
of_node_put(np);
@@ -109,4 +115,6 @@ void mmc_pwrseq_free(struct mmc_host *host)
if (pwrseq && pwrseq->ops && pwrseq->ops->free)
pwrseq->ops->free(host);
+
+ host->pwrseq = NULL;
}
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
index aba3409e8d6e..096da48c6a7e 100644
--- a/drivers/mmc/core/pwrseq.h
+++ b/drivers/mmc/core/pwrseq.h
@@ -27,8 +27,10 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host);
void mmc_pwrseq_power_off(struct mmc_host *host);
void mmc_pwrseq_free(struct mmc_host *host);
-int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev);
-int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev);
+struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
+ struct device *dev);
+struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
+ struct device *dev);
#else
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
index a2d545904fbf..9d6d2fb21796 100644
--- a/drivers/mmc/core/pwrseq_emmc.c
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -49,7 +49,6 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
unregister_restart_handler(&pwrseq->reset_nb);
gpiod_put(pwrseq->reset_gpio);
kfree(pwrseq);
- host->pwrseq = NULL;
}
static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
@@ -67,14 +66,15 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
return NOTIFY_DONE;
}
-int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
+struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
+ struct device *dev)
{
struct mmc_pwrseq_emmc *pwrseq;
int ret = 0;
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
if (!pwrseq)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW);
if (IS_ERR(pwrseq->reset_gpio)) {
@@ -92,10 +92,9 @@ int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
register_restart_handler(&pwrseq->reset_nb);
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
- host->pwrseq = &pwrseq->pwrseq;
- return 0;
+ return &pwrseq->pwrseq;
free:
kfree(pwrseq);
- return ret;
+ return ERR_PTR(ret);
}
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index c53f14a7ce54..0b14b83a53d6 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -85,7 +85,6 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
clk_put(pwrseq->ext_clk);
kfree(pwrseq);
- host->pwrseq = NULL;
}
static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
@@ -95,7 +94,8 @@ static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
.free = mmc_pwrseq_simple_free,
};
-int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
+struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
+ struct device *dev)
{
struct mmc_pwrseq_simple *pwrseq;
int i, nr_gpios, ret = 0;
@@ -107,7 +107,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *
sizeof(struct gpio_desc *), GFP_KERNEL);
if (!pwrseq)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
pwrseq->ext_clk = clk_get(dev, "ext_clock");
if (IS_ERR(pwrseq->ext_clk) &&
@@ -133,13 +133,12 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
pwrseq->nr_gpios = nr_gpios;
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
- host->pwrseq = &pwrseq->pwrseq;
- return 0;
+ return &pwrseq->pwrseq;
clk_put:
if (!IS_ERR(pwrseq->ext_clk))
clk_put(pwrseq->ext_clk);
free:
kfree(pwrseq);
- return ret;
+ return ERR_PTR(ret);
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index ad4d43eae99d..31a9ef256d06 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1157,7 +1157,7 @@ static int mmc_sd_runtime_suspend(struct mmc_host *host)
err = _mmc_sd_suspend(host);
if (err)
- pr_err("%s: error %d doing aggessive suspend\n",
+ pr_err("%s: error %d doing aggressive suspend\n",
mmc_hostname(host), err);
return err;
@@ -1175,7 +1175,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
err = _mmc_sd_resume(host);
if (err)
- pr_err("%s: error %d doing aggessive resume\n",
+ pr_err("%s: error %d doing aggressive resume\n",
mmc_hostname(host), err);
return 0;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index ce6cc47206b0..5bc6c7dbbd60 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
int err;
if (card->type == MMC_TYPE_SDIO)
- return sdio_enable_wide(card);
-
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = sdio_enable_wide(card);
+ else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
if (err)
return err;
+ err = sdio_enable_wide(card);
+ if (err <= 0)
+ mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
} else
return 0;
- err = sdio_enable_wide(card);
- if (err <= 0)
- mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
+ if (err > 0) {
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ err = 0;
+ }
return err;
}
@@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
/*
* Switch to wider bus (if supported).
*/
- if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+ if (card->host->caps & MMC_CAP_4_BIT_DATA)
err = sdio_enable_4bit_bus(card);
- if (err > 0) {
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- err = 0;
- }
- }
/* Set the driver strength for the card */
sdio_select_driver_type(card);
@@ -803,9 +801,7 @@ try_again:
* Switch to wider bus (if supported).
*/
err = sdio_enable_4bit_bus(card);
- if (err > 0)
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- else if (err)
+ if (err)
goto remove;
}
finish:
@@ -983,10 +979,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
- if (err > 0) {
- mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
- err = 0;
- }
}
if (!err && host->sdio_irqs) {