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 22 int 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 55 void 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 63 void 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 71 void 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 79 void mmc_pwrseq_reset(struct mmc_host *host) 80 { 81 struct mmc_pwrseq *pwrseq = host->pwrseq; 82 83 if (pwrseq && pwrseq->ops->reset) 84 pwrseq->ops->reset(host); 85 } 86 87 void mmc_pwrseq_free(struct mmc_host *host) 88 { 89 struct mmc_pwrseq *pwrseq = host->pwrseq; 90 91 if (pwrseq) { 92 module_put(pwrseq->owner); 93 host->pwrseq = NULL; 94 } 95 } 96 97 int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) 98 { 99 if (!pwrseq || !pwrseq->ops || !pwrseq->dev) 100 return -EINVAL; 101 102 mutex_lock(&pwrseq_list_mutex); 103 list_add(&pwrseq->pwrseq_node, &pwrseq_list); 104 mutex_unlock(&pwrseq_list_mutex); 105 106 return 0; 107 } 108 EXPORT_SYMBOL_GPL(mmc_pwrseq_register); 109 110 void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) 111 { 112 if (pwrseq) { 113 mutex_lock(&pwrseq_list_mutex); 114 list_del(&pwrseq->pwrseq_node); 115 mutex_unlock(&pwrseq_list_mutex); 116 } 117 } 118 EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister); 119