summaryrefslogtreecommitdiff
path: root/drivers/mmc/core/host.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/core/host.c')
-rw-r--r--drivers/mmc/core/host.c53
1 files changed, 40 insertions, 13 deletions
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index d17eda753b7e..88c95dbfd9cf 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -13,9 +13,7 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/pagemap.h>
-#include <linux/pm_wakeup.h>
#include <linux/export.h>
#include <linux/leds.h>
#include <linux/slab.h>
@@ -76,7 +74,7 @@ static void mmc_host_classdev_release(struct device *dev)
struct mmc_host *host = cls_dev_to_mmc_host(dev);
wakeup_source_unregister(host->ws);
if (of_alias_get_id(host->parent->of_node, "mmc") < 0)
- ida_simple_remove(&mmc_host_ida, host->index);
+ ida_free(&mmc_host_ida, host->index);
kfree(host);
}
@@ -88,7 +86,7 @@ static int mmc_host_classdev_shutdown(struct device *dev)
return 0;
}
-static struct class mmc_host_class = {
+static const struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
.shutdown_pre = mmc_host_classdev_shutdown,
@@ -119,13 +117,12 @@ void mmc_retune_enable(struct mmc_host *host)
/*
* Pause re-tuning for a small set of operations. The pause begins after the
- * next command and after first doing re-tuning.
+ * next command.
*/
void mmc_retune_pause(struct mmc_host *host)
{
if (!host->retune_paused) {
host->retune_paused = 1;
- mmc_retune_needed(host);
mmc_retune_hold(host);
}
}
@@ -150,13 +147,13 @@ void mmc_retune_disable(struct mmc_host *host)
{
mmc_retune_unpause(host);
host->can_retune = 0;
- del_timer_sync(&host->retune_timer);
+ timer_delete_sync(&host->retune_timer);
mmc_retune_clear(host);
}
void mmc_retune_timer_stop(struct mmc_host *host)
{
- del_timer_sync(&host->retune_timer);
+ timer_delete_sync(&host->retune_timer);
}
EXPORT_SYMBOL(mmc_retune_timer_stop);
@@ -215,7 +212,7 @@ out:
static void mmc_retune_timer(struct timer_list *t)
{
- struct mmc_host *host = from_timer(host, t, retune_timer);
+ struct mmc_host *host = timer_container_of(host, t, retune_timer);
mmc_retune_needed(host);
}
@@ -235,10 +232,8 @@ static void mmc_of_parse_timing_phase(struct device *dev, const char *prop,
}
void
-mmc_of_parse_clk_phase(struct mmc_host *host, struct mmc_clk_phase_map *map)
+mmc_of_parse_clk_phase(struct device *dev, struct mmc_clk_phase_map *map)
{
- struct device *dev = host->parent;
-
mmc_of_parse_timing_phase(dev, "clk-phase-legacy",
&map->phase[MMC_TIMING_LEGACY]);
mmc_of_parse_timing_phase(dev, "clk-phase-mmc-hs",
@@ -307,6 +302,8 @@ int mmc_of_parse(struct mmc_host *host)
/* f_max is obtained from the optional "max-frequency" property */
device_property_read_u32(dev, "max-frequency", &host->f_max);
+ device_property_read_u32(dev, "max-sd-hs-hz", &host->max_sd_hs_hz);
+
/*
* Configure CD and WP pins. They are both by default active low to
* match the SDHCI spec. If GPIOs are provided for CD and / or WP, the
@@ -539,7 +536,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
min_idx = mmc_first_nonreserved_index();
max_idx = 0;
- index = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
+ index = ida_alloc_range(&mmc_host_ida, min_idx, max_idx - 1,
+ GFP_KERNEL);
if (index < 0) {
kfree(host);
return NULL;
@@ -568,6 +566,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
INIT_WORK(&host->sdio_irq_work, sdio_irq_work);
timer_setup(&host->retune_timer, mmc_retune_timer, 0);
+ INIT_WORK(&host->supply.uv_work, mmc_undervoltage_workfn);
+
/*
* By default, hosts do not support SGIO or large requests.
* They have to set these according to their abilities.
@@ -588,6 +588,32 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
EXPORT_SYMBOL(mmc_alloc_host);
+static void devm_mmc_host_release(struct device *dev, void *res)
+{
+ mmc_free_host(*(struct mmc_host **)res);
+}
+
+struct mmc_host *devm_mmc_alloc_host(struct device *dev, int extra)
+{
+ struct mmc_host **dr, *host;
+
+ dr = devres_alloc(devm_mmc_host_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return NULL;
+
+ host = mmc_alloc_host(extra, dev);
+ if (!host) {
+ devres_free(dr);
+ return NULL;
+ }
+
+ *dr = host;
+ devres_add(dev, dr);
+
+ return host;
+}
+EXPORT_SYMBOL(devm_mmc_alloc_host);
+
static int mmc_validate_host_caps(struct mmc_host *host)
{
struct device *dev = host->parent;
@@ -666,6 +692,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
+ cancel_delayed_work_sync(&host->detect);
mmc_pwrseq_free(host);
put_device(&host->class_dev);
}