xref: /openbmc/linux/drivers/mmc/core/pwrseq.c (revision fa30becc)
1af873fceSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23aa8793fSUlf Hansson /*
33aa8793fSUlf Hansson  *  Copyright (C) 2014 Linaro Ltd
43aa8793fSUlf Hansson  *
53aa8793fSUlf Hansson  * Author: Ulf Hansson <ulf.hansson@linaro.org>
63aa8793fSUlf Hansson  *
73aa8793fSUlf Hansson  *  MMC power sequence management
83aa8793fSUlf Hansson  */
98c96f89cSUlf Hansson #include <linux/kernel.h>
108c96f89cSUlf Hansson #include <linux/err.h>
11d97a1e5dSSrinivas Kandagatla #include <linux/module.h>
128c96f89cSUlf Hansson #include <linux/of.h>
138c96f89cSUlf Hansson 
143aa8793fSUlf Hansson #include <linux/mmc/host.h>
153aa8793fSUlf Hansson 
163aa8793fSUlf Hansson #include "pwrseq.h"
173aa8793fSUlf Hansson 
18d97a1e5dSSrinivas Kandagatla static DEFINE_MUTEX(pwrseq_list_mutex);
19d97a1e5dSSrinivas Kandagatla static LIST_HEAD(pwrseq_list);
203aa8793fSUlf Hansson 
mmc_pwrseq_alloc(struct mmc_host * host)213aa8793fSUlf Hansson int mmc_pwrseq_alloc(struct mmc_host *host)
223aa8793fSUlf Hansson {
238c96f89cSUlf Hansson 	struct device_node *np;
24d97a1e5dSSrinivas Kandagatla 	struct mmc_pwrseq *p;
258c96f89cSUlf Hansson 
268c96f89cSUlf Hansson 	np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
278c96f89cSUlf Hansson 	if (!np)
283aa8793fSUlf Hansson 		return 0;
298c96f89cSUlf Hansson 
30d97a1e5dSSrinivas Kandagatla 	mutex_lock(&pwrseq_list_mutex);
31d97a1e5dSSrinivas Kandagatla 	list_for_each_entry(p, &pwrseq_list, pwrseq_node) {
32*fa30beccSye xingchen 		if (device_match_of_node(p->dev, np)) {
33d97a1e5dSSrinivas Kandagatla 			if (!try_module_get(p->owner))
34d97a1e5dSSrinivas Kandagatla 				dev_err(host->parent,
35d97a1e5dSSrinivas Kandagatla 					"increasing module refcount failed\n");
36d97a1e5dSSrinivas Kandagatla 			else
37d97a1e5dSSrinivas Kandagatla 				host->pwrseq = p;
38d97a1e5dSSrinivas Kandagatla 
39d97a1e5dSSrinivas Kandagatla 			break;
40d97a1e5dSSrinivas Kandagatla 		}
418c96f89cSUlf Hansson 	}
428c96f89cSUlf Hansson 
43d97a1e5dSSrinivas Kandagatla 	of_node_put(np);
44d97a1e5dSSrinivas Kandagatla 	mutex_unlock(&pwrseq_list_mutex);
458c96f89cSUlf Hansson 
46d97a1e5dSSrinivas Kandagatla 	if (!host->pwrseq)
47d97a1e5dSSrinivas Kandagatla 		return -EPROBE_DEFER;
480f12a0ceSAlexandre Courbot 
498c96f89cSUlf Hansson 	dev_info(host->parent, "allocated mmc-pwrseq\n");
508c96f89cSUlf Hansson 
51d97a1e5dSSrinivas Kandagatla 	return 0;
523aa8793fSUlf Hansson }
533aa8793fSUlf Hansson 
mmc_pwrseq_pre_power_on(struct mmc_host * host)543aa8793fSUlf Hansson void mmc_pwrseq_pre_power_on(struct mmc_host *host)
553aa8793fSUlf Hansson {
563aa8793fSUlf Hansson 	struct mmc_pwrseq *pwrseq = host->pwrseq;
573aa8793fSUlf Hansson 
58d97a1e5dSSrinivas Kandagatla 	if (pwrseq && pwrseq->ops->pre_power_on)
593aa8793fSUlf Hansson 		pwrseq->ops->pre_power_on(host);
603aa8793fSUlf Hansson }
613aa8793fSUlf Hansson 
mmc_pwrseq_post_power_on(struct mmc_host * host)623aa8793fSUlf Hansson void mmc_pwrseq_post_power_on(struct mmc_host *host)
633aa8793fSUlf Hansson {
643aa8793fSUlf Hansson 	struct mmc_pwrseq *pwrseq = host->pwrseq;
653aa8793fSUlf Hansson 
66d97a1e5dSSrinivas Kandagatla 	if (pwrseq && pwrseq->ops->post_power_on)
673aa8793fSUlf Hansson 		pwrseq->ops->post_power_on(host);
683aa8793fSUlf Hansson }
693aa8793fSUlf Hansson 
mmc_pwrseq_power_off(struct mmc_host * host)703aa8793fSUlf Hansson void mmc_pwrseq_power_off(struct mmc_host *host)
713aa8793fSUlf Hansson {
723aa8793fSUlf Hansson 	struct mmc_pwrseq *pwrseq = host->pwrseq;
733aa8793fSUlf Hansson 
74d97a1e5dSSrinivas Kandagatla 	if (pwrseq && pwrseq->ops->power_off)
753aa8793fSUlf Hansson 		pwrseq->ops->power_off(host);
763aa8793fSUlf Hansson }
773aa8793fSUlf Hansson 
mmc_pwrseq_reset(struct mmc_host * host)78773a9ef8SUlf Hansson void mmc_pwrseq_reset(struct mmc_host *host)
79773a9ef8SUlf Hansson {
80773a9ef8SUlf Hansson 	struct mmc_pwrseq *pwrseq = host->pwrseq;
81773a9ef8SUlf Hansson 
82773a9ef8SUlf Hansson 	if (pwrseq && pwrseq->ops->reset)
83773a9ef8SUlf Hansson 		pwrseq->ops->reset(host);
84773a9ef8SUlf Hansson }
85773a9ef8SUlf Hansson 
mmc_pwrseq_free(struct mmc_host * host)863aa8793fSUlf Hansson void mmc_pwrseq_free(struct mmc_host *host)
873aa8793fSUlf Hansson {
883aa8793fSUlf Hansson 	struct mmc_pwrseq *pwrseq = host->pwrseq;
893aa8793fSUlf Hansson 
90d97a1e5dSSrinivas Kandagatla 	if (pwrseq) {
91d97a1e5dSSrinivas Kandagatla 		module_put(pwrseq->owner);
920f12a0ceSAlexandre Courbot 		host->pwrseq = NULL;
933aa8793fSUlf Hansson 	}
94d97a1e5dSSrinivas Kandagatla }
95d97a1e5dSSrinivas Kandagatla 
mmc_pwrseq_register(struct mmc_pwrseq * pwrseq)96d97a1e5dSSrinivas Kandagatla int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq)
97d97a1e5dSSrinivas Kandagatla {
98d97a1e5dSSrinivas Kandagatla 	if (!pwrseq || !pwrseq->ops || !pwrseq->dev)
99d97a1e5dSSrinivas Kandagatla 		return -EINVAL;
100d97a1e5dSSrinivas Kandagatla 
101d97a1e5dSSrinivas Kandagatla 	mutex_lock(&pwrseq_list_mutex);
102d97a1e5dSSrinivas Kandagatla 	list_add(&pwrseq->pwrseq_node, &pwrseq_list);
103d97a1e5dSSrinivas Kandagatla 	mutex_unlock(&pwrseq_list_mutex);
104d97a1e5dSSrinivas Kandagatla 
105d97a1e5dSSrinivas Kandagatla 	return 0;
106d97a1e5dSSrinivas Kandagatla }
107d97a1e5dSSrinivas Kandagatla EXPORT_SYMBOL_GPL(mmc_pwrseq_register);
108d97a1e5dSSrinivas Kandagatla 
mmc_pwrseq_unregister(struct mmc_pwrseq * pwrseq)109d97a1e5dSSrinivas Kandagatla void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq)
110d97a1e5dSSrinivas Kandagatla {
111d97a1e5dSSrinivas Kandagatla 	if (pwrseq) {
112d97a1e5dSSrinivas Kandagatla 		mutex_lock(&pwrseq_list_mutex);
113d97a1e5dSSrinivas Kandagatla 		list_del(&pwrseq->pwrseq_node);
114d97a1e5dSSrinivas Kandagatla 		mutex_unlock(&pwrseq_list_mutex);
115d97a1e5dSSrinivas Kandagatla 	}
116d97a1e5dSSrinivas Kandagatla }
117d97a1e5dSSrinivas Kandagatla EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);
118