Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.10-rc5 110 lines 2.2 kB view raw
1/* 2 * Copyright (C) 2014 Linaro Ltd 3 * 4 * Author: Ulf Hansson <ulf.hansson@linaro.org> 5 * 6 * License terms: GNU General Public License (GPL) version 2 7 * 8 * MMC power sequence management 9 */ 10#include <linux/kernel.h> 11#include <linux/err.h> 12#include <linux/module.h> 13#include <linux/of.h> 14 15#include <linux/mmc/host.h> 16 17#include "pwrseq.h" 18 19static DEFINE_MUTEX(pwrseq_list_mutex); 20static LIST_HEAD(pwrseq_list); 21 22int mmc_pwrseq_alloc(struct mmc_host *host) 23{ 24 struct device_node *np; 25 struct mmc_pwrseq *p; 26 27 np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); 28 if (!np) 29 return 0; 30 31 mutex_lock(&pwrseq_list_mutex); 32 list_for_each_entry(p, &pwrseq_list, pwrseq_node) { 33 if (p->dev->of_node == np) { 34 if (!try_module_get(p->owner)) 35 dev_err(host->parent, 36 "increasing module refcount failed\n"); 37 else 38 host->pwrseq = p; 39 40 break; 41 } 42 } 43 44 of_node_put(np); 45 mutex_unlock(&pwrseq_list_mutex); 46 47 if (!host->pwrseq) 48 return -EPROBE_DEFER; 49 50 dev_info(host->parent, "allocated mmc-pwrseq\n"); 51 52 return 0; 53} 54 55void mmc_pwrseq_pre_power_on(struct mmc_host *host) 56{ 57 struct mmc_pwrseq *pwrseq = host->pwrseq; 58 59 if (pwrseq && pwrseq->ops->pre_power_on) 60 pwrseq->ops->pre_power_on(host); 61} 62 63void mmc_pwrseq_post_power_on(struct mmc_host *host) 64{ 65 struct mmc_pwrseq *pwrseq = host->pwrseq; 66 67 if (pwrseq && pwrseq->ops->post_power_on) 68 pwrseq->ops->post_power_on(host); 69} 70 71void mmc_pwrseq_power_off(struct mmc_host *host) 72{ 73 struct mmc_pwrseq *pwrseq = host->pwrseq; 74 75 if (pwrseq && pwrseq->ops->power_off) 76 pwrseq->ops->power_off(host); 77} 78 79void mmc_pwrseq_free(struct mmc_host *host) 80{ 81 struct mmc_pwrseq *pwrseq = host->pwrseq; 82 83 if (pwrseq) { 84 module_put(pwrseq->owner); 85 host->pwrseq = NULL; 86 } 87} 88 89int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) 90{ 91 if (!pwrseq || !pwrseq->ops || !pwrseq->dev) 92 return -EINVAL; 93 94 mutex_lock(&pwrseq_list_mutex); 95 list_add(&pwrseq->pwrseq_node, &pwrseq_list); 96 mutex_unlock(&pwrseq_list_mutex); 97 98 return 0; 99} 100EXPORT_SYMBOL_GPL(mmc_pwrseq_register); 101 102void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) 103{ 104 if (pwrseq) { 105 mutex_lock(&pwrseq_list_mutex); 106 list_del(&pwrseq->pwrseq_node); 107 mutex_unlock(&pwrseq_list_mutex); 108 } 109} 110EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister);