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 19 static DEFINE_MUTEX(pwrseq_list_mutex); 20 static LIST_HEAD(pwrseq_list); 21 mmc_pwrseq_alloc(struct mmc_host * host)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 mmc_pwrseq_pre_power_on(struct mmc_host * host)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 mmc_pwrseq_post_power_on(struct mmc_host * host)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 mmc_pwrseq_power_off(struct mmc_host * host)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 mmc_pwrseq_free(struct mmc_host * host)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 mmc_pwrseq_register(struct mmc_pwrseq * pwrseq)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 } 100 EXPORT_SYMBOL_GPL(mmc_pwrseq_register); 101 mmc_pwrseq_unregister(struct mmc_pwrseq * pwrseq)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 } 110 EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister); 111