diff options
author | Javier Martinez Canillas <javier.martinez@collabora.co.uk> | 2015-01-29 10:00:06 -0500 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2015-01-30 06:10:23 -0500 |
commit | c13045b1e939a9ecffab4a8f8d514e8a2a0bd2c9 (patch) | |
tree | 8485f823dafec20c596457251ad36826d30cc293 /drivers/mmc/core | |
parent | 3f656a168c70a583a5d87614eb4a707abd7f80b9 (diff) |
mmc: pwrseq_simple: Add optional reference clock support
Some WLAN chips attached to a SDIO interface, need a reference clock.
Since this is very common, extend the prseq_simple driver to support
an optional clock that is enabled prior the card power up procedure.
Note: the external clock is optional. Thus an error is not returned
if the clock is not found.
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r-- | drivers/mmc/core/pwrseq_simple.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index e53d3c7e059c..e9f1d8d84613 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * | 7 | * |
8 | * Simple MMC power sequence management | 8 | * Simple MMC power sequence management |
9 | */ | 9 | */ |
10 | #include <linux/clk.h> | ||
10 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
11 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
12 | #include <linux/device.h> | 13 | #include <linux/device.h> |
@@ -20,6 +21,8 @@ | |||
20 | 21 | ||
21 | struct mmc_pwrseq_simple { | 22 | struct mmc_pwrseq_simple { |
22 | struct mmc_pwrseq pwrseq; | 23 | struct mmc_pwrseq pwrseq; |
24 | bool clk_enabled; | ||
25 | struct clk *ext_clk; | ||
23 | int nr_gpios; | 26 | int nr_gpios; |
24 | struct gpio_desc *reset_gpios[0]; | 27 | struct gpio_desc *reset_gpios[0]; |
25 | }; | 28 | }; |
@@ -39,6 +42,11 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) | |||
39 | struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, | 42 | struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, |
40 | struct mmc_pwrseq_simple, pwrseq); | 43 | struct mmc_pwrseq_simple, pwrseq); |
41 | 44 | ||
45 | if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) { | ||
46 | clk_prepare_enable(pwrseq->ext_clk); | ||
47 | pwrseq->clk_enabled = true; | ||
48 | } | ||
49 | |||
42 | mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); | 50 | mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); |
43 | } | 51 | } |
44 | 52 | ||
@@ -50,6 +58,19 @@ static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) | |||
50 | mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); | 58 | mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); |
51 | } | 59 | } |
52 | 60 | ||
61 | static void mmc_pwrseq_simple_power_off(struct mmc_host *host) | ||
62 | { | ||
63 | struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, | ||
64 | struct mmc_pwrseq_simple, pwrseq); | ||
65 | |||
66 | mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); | ||
67 | |||
68 | if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) { | ||
69 | clk_disable_unprepare(pwrseq->ext_clk); | ||
70 | pwrseq->clk_enabled = false; | ||
71 | } | ||
72 | } | ||
73 | |||
53 | static void mmc_pwrseq_simple_free(struct mmc_host *host) | 74 | static void mmc_pwrseq_simple_free(struct mmc_host *host) |
54 | { | 75 | { |
55 | struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, | 76 | struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, |
@@ -60,6 +81,9 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) | |||
60 | if (!IS_ERR(pwrseq->reset_gpios[i])) | 81 | if (!IS_ERR(pwrseq->reset_gpios[i])) |
61 | gpiod_put(pwrseq->reset_gpios[i]); | 82 | gpiod_put(pwrseq->reset_gpios[i]); |
62 | 83 | ||
84 | if (!IS_ERR(pwrseq->ext_clk)) | ||
85 | clk_put(pwrseq->ext_clk); | ||
86 | |||
63 | kfree(pwrseq); | 87 | kfree(pwrseq); |
64 | host->pwrseq = NULL; | 88 | host->pwrseq = NULL; |
65 | } | 89 | } |
@@ -67,7 +91,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) | |||
67 | static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { | 91 | static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { |
68 | .pre_power_on = mmc_pwrseq_simple_pre_power_on, | 92 | .pre_power_on = mmc_pwrseq_simple_pre_power_on, |
69 | .post_power_on = mmc_pwrseq_simple_post_power_on, | 93 | .post_power_on = mmc_pwrseq_simple_post_power_on, |
70 | .power_off = mmc_pwrseq_simple_pre_power_on, | 94 | .power_off = mmc_pwrseq_simple_power_off, |
71 | .free = mmc_pwrseq_simple_free, | 95 | .free = mmc_pwrseq_simple_free, |
72 | }; | 96 | }; |
73 | 97 | ||
@@ -85,6 +109,13 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) | |||
85 | if (!pwrseq) | 109 | if (!pwrseq) |
86 | return -ENOMEM; | 110 | return -ENOMEM; |
87 | 111 | ||
112 | pwrseq->ext_clk = clk_get(dev, "ext_clock"); | ||
113 | if (IS_ERR(pwrseq->ext_clk) && | ||
114 | PTR_ERR(pwrseq->ext_clk) != -ENOENT) { | ||
115 | ret = PTR_ERR(pwrseq->ext_clk); | ||
116 | goto free; | ||
117 | } | ||
118 | |||
88 | for (i = 0; i < nr_gpios; i++) { | 119 | for (i = 0; i < nr_gpios; i++) { |
89 | pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, | 120 | pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i, |
90 | GPIOD_OUT_HIGH); | 121 | GPIOD_OUT_HIGH); |
@@ -96,7 +127,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) | |||
96 | while (--i) | 127 | while (--i) |
97 | gpiod_put(pwrseq->reset_gpios[i]); | 128 | gpiod_put(pwrseq->reset_gpios[i]); |
98 | 129 | ||
99 | goto free; | 130 | goto clk_put; |
100 | } | 131 | } |
101 | } | 132 | } |
102 | 133 | ||
@@ -105,6 +136,9 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) | |||
105 | host->pwrseq = &pwrseq->pwrseq; | 136 | host->pwrseq = &pwrseq->pwrseq; |
106 | 137 | ||
107 | return 0; | 138 | return 0; |
139 | clk_put: | ||
140 | if (!IS_ERR(pwrseq->ext_clk)) | ||
141 | clk_put(pwrseq->ext_clk); | ||
108 | free: | 142 | free: |
109 | kfree(pwrseq); | 143 | kfree(pwrseq); |
110 | return ret; | 144 | return ret; |