Commit | Line | Data |
---|---|---|
3aa8793f UH |
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 | */ | |
8c96f89c | 10 | #include <linux/kernel.h> |
8c96f89c | 11 | #include <linux/err.h> |
d97a1e5d | 12 | #include <linux/module.h> |
8c96f89c | 13 | #include <linux/of.h> |
8c96f89c | 14 | |
3aa8793f UH |
15 | #include <linux/mmc/host.h> |
16 | ||
17 | #include "pwrseq.h" | |
18 | ||
d97a1e5d SK |
19 | static DEFINE_MUTEX(pwrseq_list_mutex); |
20 | static LIST_HEAD(pwrseq_list); | |
3aa8793f UH |
21 | |
22 | int mmc_pwrseq_alloc(struct mmc_host *host) | |
23 | { | |
8c96f89c | 24 | struct device_node *np; |
d97a1e5d | 25 | struct mmc_pwrseq *p; |
8c96f89c UH |
26 | |
27 | np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); | |
28 | if (!np) | |
29 | return 0; | |
30 | ||
d97a1e5d SK |
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; | |
8c96f89c | 39 | |
d97a1e5d SK |
40 | break; |
41 | } | |
8c96f89c UH |
42 | } |
43 | ||
d97a1e5d SK |
44 | of_node_put(np); |
45 | mutex_unlock(&pwrseq_list_mutex); | |
46 | ||
47 | if (!host->pwrseq) | |
48 | return -EPROBE_DEFER; | |
0f12a0ce | 49 | |
0f12a0ce | 50 | dev_info(host->parent, "allocated mmc-pwrseq\n"); |
8c96f89c | 51 | |
d97a1e5d | 52 | return 0; |
3aa8793f UH |
53 | } |
54 | ||
55 | void mmc_pwrseq_pre_power_on(struct mmc_host *host) | |
56 | { | |
57 | struct mmc_pwrseq *pwrseq = host->pwrseq; | |
58 | ||
d97a1e5d | 59 | if (pwrseq && pwrseq->ops->pre_power_on) |
3aa8793f UH |
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 | ||
d97a1e5d | 67 | if (pwrseq && pwrseq->ops->post_power_on) |
3aa8793f UH |
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 | ||
d97a1e5d | 75 | if (pwrseq && pwrseq->ops->power_off) |
3aa8793f UH |
76 | pwrseq->ops->power_off(host); |
77 | } | |
78 | ||
79 | void mmc_pwrseq_free(struct mmc_host *host) | |
80 | { | |
81 | struct mmc_pwrseq *pwrseq = host->pwrseq; | |
82 | ||
d97a1e5d SK |
83 | if (pwrseq) { |
84 | module_put(pwrseq->owner); | |
85 | host->pwrseq = NULL; | |
86 | } | |
87 | } | |
88 | ||
89 | int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) | |
90 | { | |
91 | if (!pwrseq || !pwrseq->ops || !pwrseq->dev) | |
92 | return -EINVAL; | |
0f12a0ce | 93 | |
d97a1e5d SK |
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 | ||
102 | void 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 | } | |
3aa8793f | 109 | } |
d97a1e5d | 110 | EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister); |