mmc: core: Add deferred bus resume policy.
A card driver can now specify that the underlying bus should *not* auto-resume with the rest of the system. This is useful for reducing resume latency as well as saving power when the card driver is not using the bus. In the future, we'll add support for manual suspend Change-Id: I077d7dc9311ff12e6e16de631abeac965c8facd9 Signed-off-by: San Mehat <san@google.com> Git-commit: b44e6c88fc57e08562ff6b4fd68ba89cc2aa21bc Git-repo: git://git-android.quicinc.com/kernel/msm-3.10 [asutoshd@codeaurora.org: merge conflicts resolved and similar changes were updated in a different file; due to changes in kernel version] Signed-off-by: Asutosh Das <asutoshd@codeaurora.org> [subhashj@codeaurora.org: fixed trivial merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
99f872cfe2
commit
7eac9a6d85
3 changed files with 53 additions and 0 deletions
|
@ -164,6 +164,8 @@ static int mmc_bus_suspend(struct device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (mmc_bus_needs_resume(host))
|
||||||
|
return 0;
|
||||||
ret = host->bus_ops->suspend(host);
|
ret = host->bus_ops->suspend(host);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -174,11 +176,17 @@ static int mmc_bus_resume(struct device *dev)
|
||||||
struct mmc_host *host = card->host;
|
struct mmc_host *host = card->host;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (host->bus_resume_flags & MMC_BUSRESUME_MANUAL_RESUME) {
|
||||||
|
host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
|
||||||
|
goto skip_full_resume;
|
||||||
|
}
|
||||||
|
|
||||||
ret = host->bus_ops->resume(host);
|
ret = host->bus_ops->resume(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
pr_warn("%s: error %d during resume (card was removed?)\n",
|
pr_warn("%s: error %d during resume (card was removed?)\n",
|
||||||
mmc_hostname(host), ret);
|
mmc_hostname(host), ret);
|
||||||
|
|
||||||
|
skip_full_resume:
|
||||||
ret = pm_generic_resume(dev);
|
ret = pm_generic_resume(dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -190,6 +198,9 @@ static int mmc_runtime_suspend(struct device *dev)
|
||||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||||
struct mmc_host *host = card->host;
|
struct mmc_host *host = card->host;
|
||||||
|
|
||||||
|
if (mmc_bus_needs_resume(host))
|
||||||
|
return 0;
|
||||||
|
|
||||||
return host->bus_ops->runtime_suspend(host);
|
return host->bus_ops->runtime_suspend(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +209,9 @@ static int mmc_runtime_resume(struct device *dev)
|
||||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||||
struct mmc_host *host = card->host;
|
struct mmc_host *host = card->host;
|
||||||
|
|
||||||
|
if (mmc_bus_needs_resume(host))
|
||||||
|
host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;
|
||||||
|
|
||||||
return host->bus_ops->runtime_resume(host);
|
return host->bus_ops->runtime_resume(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3048,6 +3048,29 @@ static inline void mmc_bus_put(struct mmc_host *host)
|
||||||
spin_unlock_irqrestore(&host->lock, flags);
|
spin_unlock_irqrestore(&host->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mmc_resume_bus(struct mmc_host *host)
|
||||||
|
{
|
||||||
|
if (!mmc_bus_needs_resume(host))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pr_debug("%s: Starting deferred resume\n", mmc_hostname(host));
|
||||||
|
host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;
|
||||||
|
mmc_bus_get(host);
|
||||||
|
if (host->bus_ops && !host->bus_dead && host->card) {
|
||||||
|
mmc_power_up(host, host->card->ocr);
|
||||||
|
BUG_ON(!host->bus_ops->resume);
|
||||||
|
host->bus_ops->resume(host);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host->bus_ops->detect && !host->bus_dead)
|
||||||
|
host->bus_ops->detect(host);
|
||||||
|
|
||||||
|
mmc_bus_put(host);
|
||||||
|
pr_debug("%s: Deferred resume completed\n", mmc_hostname(host));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(mmc_resume_bus);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign a mmc bus handler to a host. Only one bus handler may control a
|
* Assign a mmc bus handler to a host. Only one bus handler may control a
|
||||||
* host at any given time.
|
* host at any given time.
|
||||||
|
|
|
@ -511,6 +511,10 @@ struct mmc_host {
|
||||||
const struct mmc_bus_ops *bus_ops; /* current bus driver */
|
const struct mmc_bus_ops *bus_ops; /* current bus driver */
|
||||||
unsigned int bus_refs; /* reference counter */
|
unsigned int bus_refs; /* reference counter */
|
||||||
|
|
||||||
|
unsigned int bus_resume_flags;
|
||||||
|
#define MMC_BUSRESUME_MANUAL_RESUME (1 << 0)
|
||||||
|
#define MMC_BUSRESUME_NEEDS_RESUME (1 << 1)
|
||||||
|
|
||||||
unsigned int sdio_irqs;
|
unsigned int sdio_irqs;
|
||||||
struct task_struct *sdio_irq_thread;
|
struct task_struct *sdio_irq_thread;
|
||||||
bool sdio_irq_pending;
|
bool sdio_irq_pending;
|
||||||
|
@ -614,6 +618,18 @@ static inline void *mmc_cmdq_private(struct mmc_host *host)
|
||||||
#define mmc_dev(x) ((x)->parent)
|
#define mmc_dev(x) ((x)->parent)
|
||||||
#define mmc_classdev(x) (&(x)->class_dev)
|
#define mmc_classdev(x) (&(x)->class_dev)
|
||||||
#define mmc_hostname(x) (dev_name(&(x)->class_dev))
|
#define mmc_hostname(x) (dev_name(&(x)->class_dev))
|
||||||
|
#define mmc_bus_needs_resume(host) ((host)->bus_resume_flags & \
|
||||||
|
MMC_BUSRESUME_NEEDS_RESUME)
|
||||||
|
|
||||||
|
static inline void mmc_set_bus_resume_policy(struct mmc_host *host, int manual)
|
||||||
|
{
|
||||||
|
if (manual)
|
||||||
|
host->bus_resume_flags |= MMC_BUSRESUME_MANUAL_RESUME;
|
||||||
|
else
|
||||||
|
host->bus_resume_flags &= ~MMC_BUSRESUME_MANUAL_RESUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int mmc_resume_bus(struct mmc_host *host);
|
||||||
|
|
||||||
int mmc_power_save_host(struct mmc_host *host);
|
int mmc_power_save_host(struct mmc_host *host);
|
||||||
int mmc_power_restore_host(struct mmc_host *host);
|
int mmc_power_restore_host(struct mmc_host *host);
|
||||||
|
|
Loading…
Add table
Reference in a new issue