xref: /openbmc/linux/drivers/mmc/core/pwrseq.c (revision c997aabb)
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