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 Hanssonint 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 Hanssonvoid 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 Hanssonvoid 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 Hanssonvoid 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 Hanssonvoid 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 Hanssonvoid 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 Kandagatlaint 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 Kandagatlavoid 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