@@ -322,7 +322,11 @@ int mmc_of_parse(struct mmc_host *host)
host->dsr_req = 0;
}
- return mmc_pwrseq_alloc(host);
+ host->pwrseq = pwrseq_alloc(host->parent->of_node, "mmc-pwrseq");
+ if (IS_ERR(host->pwrseq))
+ return PTR_ERR(host->pwrseq);
+ else
+ return 0;
}
EXPORT_SYMBOL(mmc_of_parse);
@@ -462,7 +466,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
- mmc_pwrseq_free(host);
+ pwrseq_free(host->pwrseq);
put_device(&host->class_dev);
}
@@ -5,37 +5,38 @@
*
* License terms: GNU General Public License (GPL) version 2
*
- * MMC power sequence management
+ * Power sequence management helpers
*/
+
+#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pwrseq.h>
-#include <linux/mmc/host.h>
static DEFINE_MUTEX(pwrseq_list_mutex);
static LIST_HEAD(pwrseq_list);
-int mmc_pwrseq_alloc(struct mmc_host *host)
+struct pwrseq *pwrseq_alloc(const struct device_node *node,
+ const char *phandle_name)
{
struct device_node *np;
- struct pwrseq *p;
+ struct pwrseq *p, *pwrseq = NULL;
- np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
+ np = of_parse_phandle(node, phandle_name, 0);
if (!np)
- return 0;
+ return NULL;
mutex_lock(&pwrseq_list_mutex);
list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
if (p->dev->of_node == np) {
if (!try_module_get(p->owner))
- dev_err(host->parent,
+ dev_err(p->dev,
"increasing module refcount failed\n");
else
- host->pwrseq = p;
-
+ pwrseq = p;
break;
}
}
@@ -43,19 +44,21 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
of_node_put(np);
mutex_unlock(&pwrseq_list_mutex);
- if (!host->pwrseq)
- return -EPROBE_DEFER;
+ if (!pwrseq)
+ return ERR_PTR(-EPROBE_DEFER);
- dev_info(host->parent, "allocated mmc-pwrseq\n");
+ dev_info(p->dev, "pwrseq is allocated\n");
- return 0;
+ return pwrseq;
}
-EXPORT_SYMBOL_GPL(mmc_pwrseq_alloc);
+EXPORT_SYMBOL_GPL(pwrseq_alloc);
-void pwrseq_pre_power_on(struct pwrseq *pwrseq)
+int pwrseq_pre_power_on(struct pwrseq *pwrseq)
{
if (pwrseq && pwrseq->ops->pre_power_on)
- pwrseq->ops->pre_power_on(pwrseq);
+ return pwrseq->ops->pre_power_on(pwrseq);
+ else
+ return 0;
}
EXPORT_SYMBOL_GPL(pwrseq_pre_power_on);
@@ -73,16 +76,12 @@ void pwrseq_power_off(struct pwrseq *pwrseq)
}
EXPORT_SYMBOL_GPL(pwrseq_power_off);
-void mmc_pwrseq_free(struct mmc_host *host)
+void pwrseq_free(struct pwrseq *pwrseq)
{
- struct pwrseq *pwrseq = host->pwrseq;
-
- if (pwrseq) {
+ if (pwrseq)
module_put(pwrseq->owner);
- host->pwrseq = NULL;
- }
}
-EXPORT_SYMBOL_GPL(mmc_pwrseq_free);
+EXPORT_SYMBOL_GPL(pwrseq_free);
int pwrseq_register(struct pwrseq *pwrseq)
{
@@ -44,16 +44,20 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
}
}
-static void mmc_pwrseq_simple_pre_power_on(struct pwrseq *_pwrseq)
+static int mmc_pwrseq_simple_pre_power_on(struct pwrseq *_pwrseq)
{
struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(_pwrseq);
+ int ret = 0;
if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
- clk_prepare_enable(pwrseq->ext_clk);
- pwrseq->clk_enabled = true;
+ ret = clk_prepare_enable(pwrseq->ext_clk);
+ if (!ret)
+ pwrseq->clk_enabled = true;
}
mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+
+ return 0;
}
static void mmc_pwrseq_simple_post_power_on(struct pwrseq *_pwrseq)
@@ -8,14 +8,6 @@
#ifndef _LINUX_PWRSEQ_H
#define _LINUX_PWRSEQ_H
-#include <linux/mmc/host.h>
-
-struct pwrseq_ops {
- void (*pre_power_on)(struct pwrseq *pwrseq);
- void (*post_power_on)(struct pwrseq *pwrseq);
- void (*power_off)(struct pwrseq *pwrseq);
-};
-
struct pwrseq {
const struct pwrseq_ops *ops;
struct device *dev;
@@ -23,16 +15,23 @@ struct pwrseq {
struct module *owner;
};
+struct pwrseq_ops {
+ int (*pre_power_on)(struct pwrseq *pwrseq);
+ void (*post_power_on)(struct pwrseq *pwrseq);
+ void (*power_off)(struct pwrseq *pwrseq);
+};
+
#ifdef CONFIG_POWER_SEQ
int pwrseq_register(struct pwrseq *pwrseq);
void pwrseq_unregister(struct pwrseq *pwrseq);
-void pwrseq_pre_power_on(struct pwrseq *pwrseq);
+int pwrseq_pre_power_on(struct pwrseq *pwrseq);
void pwrseq_post_power_on(struct pwrseq *pwrseq);
void pwrseq_power_off(struct pwrseq *pwrseq);
-int mmc_pwrseq_alloc(struct mmc_host *host);
-void mmc_pwrseq_free(struct mmc_host *host);
+struct pwrseq *pwrseq_alloc(const struct device_node *node,
+ const char *phandle_name);
+void pwrseq_free(struct pwrseq *pwrseq);
#else /* CONFIG_POWER_SEQ */
@@ -41,11 +40,15 @@ static inline int pwrseq_register(struct pwrseq *pwrseq)
return -ENOSYS;
}
static inline void pwrseq_unregister(struct pwrseq *pwrseq) {}
-static inline void pwrseq_pre_power_on(struct pwrseq *pwrseq) {}
+static inline int pwrseq_pre_power_on(struct pwrseq *pwrseq) {}
static inline void pwrseq_post_power_on(struct pwrseq *pwrseq) {}
static inline void pwrseq_power_off(struct pwrseq *pwrseq) {}
-static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
-static inline void mmc_pwrseq_free(struct mmc_host *host) {}
+static inline struct pwrseq *pwrseq_alloc(const struct device_node *node,
+ const char *phandle_name)
+{
+ return NULL;
+}
+static inline void pwrseq_free(struct mmc_host *host) {}
#endif /* CONFIG_POWER_SEQ */
These helpers are only used by mmc now, change them as generic and do corresponding changes at mmc code. Meanwhile, change return value of helper pwrseq_pre_power_on since it may occur error during enable clock/regulator, etc. Signed-off-by: Peter Chen <peter.chen@nxp.com> --- drivers/mmc/core/host.c | 8 +++++-- drivers/power/pwrseq/pwrseq.c | 45 ++++++++++++++++++------------------ drivers/power/pwrseq/pwrseq_simple.c | 10 +++++--- include/linux/pwrseq.h | 31 ++++++++++++++----------- 4 files changed, 52 insertions(+), 42 deletions(-)