Commit | Line | Data |
---|---|---|
349ab524 GL |
1 | /* |
2 | * Generic GPIO card-detect helper | |
3 | * | |
4 | * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/err.h> | |
12 | #include <linux/gpio.h> | |
13 | #include <linux/interrupt.h> | |
14 | #include <linux/jiffies.h> | |
15 | #include <linux/mmc/host.h> | |
fd0ea65d | 16 | #include <linux/mmc/slot-gpio.h> |
349ab524 GL |
17 | #include <linux/module.h> |
18 | #include <linux/slab.h> | |
19 | ||
fd0ea65d | 20 | struct mmc_gpio { |
5aa7dad3 | 21 | int ro_gpio; |
befe4048 | 22 | int cd_gpio; |
5aa7dad3 | 23 | char *ro_label; |
fd0ea65d | 24 | char cd_label[0]; |
349ab524 GL |
25 | }; |
26 | ||
fd0ea65d | 27 | static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) |
349ab524 GL |
28 | { |
29 | /* Schedule a card detection after a debounce timeout */ | |
451c8957 GL |
30 | struct mmc_host *host = dev_id; |
31 | ||
32 | if (host->ops->card_event) | |
33 | host->ops->card_event(host); | |
34 | ||
35 | mmc_detect_change(host, msecs_to_jiffies(200)); | |
36 | ||
349ab524 GL |
37 | return IRQ_HANDLED; |
38 | } | |
39 | ||
a7d1a1eb GL |
40 | static int mmc_gpio_alloc(struct mmc_host *host) |
41 | { | |
42 | size_t len = strlen(dev_name(host->parent)) + 4; | |
43 | struct mmc_gpio *ctx; | |
44 | ||
45 | mutex_lock(&host->slot.lock); | |
46 | ||
47 | ctx = host->slot.handler_priv; | |
48 | if (!ctx) { | |
49 | /* | |
50 | * devm_kzalloc() can be called after device_initialize(), even | |
51 | * before device_add(), i.e., between mmc_alloc_host() and | |
52 | * mmc_add_host() | |
53 | */ | |
5aa7dad3 | 54 | ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len, |
a7d1a1eb GL |
55 | GFP_KERNEL); |
56 | if (ctx) { | |
5aa7dad3 | 57 | ctx->ro_label = ctx->cd_label + len; |
a7d1a1eb | 58 | snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); |
5aa7dad3 | 59 | snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); |
a7d1a1eb | 60 | ctx->cd_gpio = -EINVAL; |
5aa7dad3 | 61 | ctx->ro_gpio = -EINVAL; |
a7d1a1eb GL |
62 | host->slot.handler_priv = ctx; |
63 | } | |
64 | } | |
65 | ||
66 | mutex_unlock(&host->slot.lock); | |
67 | ||
68 | return ctx ? 0 : -ENOMEM; | |
69 | } | |
70 | ||
5aa7dad3 GL |
71 | int mmc_gpio_get_ro(struct mmc_host *host) |
72 | { | |
73 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
74 | ||
75 | if (!ctx || !gpio_is_valid(ctx->ro_gpio)) | |
76 | return -ENOSYS; | |
77 | ||
78 | return !gpio_get_value_cansleep(ctx->ro_gpio) ^ | |
79 | !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); | |
80 | } | |
81 | EXPORT_SYMBOL(mmc_gpio_get_ro); | |
82 | ||
befe4048 GL |
83 | int mmc_gpio_get_cd(struct mmc_host *host) |
84 | { | |
85 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
86 | ||
87 | if (!ctx || !gpio_is_valid(ctx->cd_gpio)) | |
88 | return -ENOSYS; | |
89 | ||
90 | return !gpio_get_value_cansleep(ctx->cd_gpio) ^ | |
91 | !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); | |
92 | } | |
93 | EXPORT_SYMBOL(mmc_gpio_get_cd); | |
94 | ||
c8bdfea7 SG |
95 | /** |
96 | * mmc_gpio_request_ro - request a gpio for write-protection | |
97 | * @host: mmc host | |
98 | * @gpio: gpio number requested | |
99 | * | |
100 | * As devm_* managed functions are used in mmc_gpio_request_ro(), client | |
101 | * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up, | |
102 | * if the requesting and freeing are only needed at probing and unbinding time | |
103 | * for once. However, if client drivers do something special like runtime | |
104 | * switching for write-protection, they are responsible for calling | |
105 | * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own. | |
106 | * | |
107 | * Returns zero on success, else an error. | |
108 | */ | |
5aa7dad3 GL |
109 | int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) |
110 | { | |
111 | struct mmc_gpio *ctx; | |
112 | int ret; | |
113 | ||
114 | if (!gpio_is_valid(gpio)) | |
115 | return -EINVAL; | |
116 | ||
117 | ret = mmc_gpio_alloc(host); | |
118 | if (ret < 0) | |
119 | return ret; | |
120 | ||
121 | ctx = host->slot.handler_priv; | |
122 | ||
c8bdfea7 SG |
123 | ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, |
124 | ctx->ro_label); | |
15e8a8e4 CB |
125 | if (ret < 0) |
126 | return ret; | |
127 | ||
128 | ctx->ro_gpio = gpio; | |
129 | ||
130 | return 0; | |
5aa7dad3 GL |
131 | } |
132 | EXPORT_SYMBOL(mmc_gpio_request_ro); | |
133 | ||
c8bdfea7 SG |
134 | /** |
135 | * mmc_gpio_request_cd - request a gpio for card-detection | |
136 | * @host: mmc host | |
137 | * @gpio: gpio number requested | |
138 | * | |
139 | * As devm_* managed functions are used in mmc_gpio_request_cd(), client | |
140 | * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up, | |
141 | * if the requesting and freeing are only needed at probing and unbinding time | |
142 | * for once. However, if client drivers do something special like runtime | |
143 | * switching for card-detection, they are responsible for calling | |
144 | * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own. | |
145 | * | |
146 | * Returns zero on success, else an error. | |
147 | */ | |
fd0ea65d | 148 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) |
349ab524 | 149 | { |
fd0ea65d | 150 | struct mmc_gpio *ctx; |
c9b0546a | 151 | int irq = gpio_to_irq(gpio); |
349ab524 GL |
152 | int ret; |
153 | ||
a7d1a1eb GL |
154 | ret = mmc_gpio_alloc(host); |
155 | if (ret < 0) | |
156 | return ret; | |
349ab524 | 157 | |
a7d1a1eb | 158 | ctx = host->slot.handler_priv; |
349ab524 | 159 | |
c8bdfea7 SG |
160 | ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, |
161 | ctx->cd_label); | |
349ab524 | 162 | if (ret < 0) |
a7d1a1eb GL |
163 | /* |
164 | * don't bother freeing memory. It might still get used by other | |
165 | * slot functions, in any case it will be freed, when the device | |
166 | * is destroyed. | |
167 | */ | |
168 | return ret; | |
349ab524 | 169 | |
befe4048 GL |
170 | /* |
171 | * Even if gpio_to_irq() returns a valid IRQ number, the platform might | |
172 | * still prefer to poll, e.g., because that IRQ number is already used | |
173 | * by another unit and cannot be shared. | |
174 | */ | |
175 | if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) | |
176 | irq = -EINVAL; | |
177 | ||
178 | if (irq >= 0) { | |
c8bdfea7 SG |
179 | ret = devm_request_threaded_irq(&host->class_dev, irq, |
180 | NULL, mmc_gpio_cd_irqt, | |
fd0ea65d GL |
181 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
182 | ctx->cd_label, host); | |
befe4048 GL |
183 | if (ret < 0) |
184 | irq = ret; | |
185 | } | |
349ab524 | 186 | |
27410ee7 | 187 | host->slot.cd_irq = irq; |
befe4048 GL |
188 | |
189 | if (irq < 0) | |
190 | host->caps |= MMC_CAP_NEEDS_POLL; | |
191 | ||
192 | ctx->cd_gpio = gpio; | |
349ab524 GL |
193 | |
194 | return 0; | |
349ab524 | 195 | } |
fd0ea65d | 196 | EXPORT_SYMBOL(mmc_gpio_request_cd); |
349ab524 | 197 | |
c8bdfea7 SG |
198 | /** |
199 | * mmc_gpio_free_ro - free the write-protection gpio | |
200 | * @host: mmc host | |
201 | * | |
202 | * It's provided only for cases that client drivers need to manually free | |
203 | * up the write-protection gpio requested by mmc_gpio_request_ro(). | |
204 | */ | |
5aa7dad3 GL |
205 | void mmc_gpio_free_ro(struct mmc_host *host) |
206 | { | |
207 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
208 | int gpio; | |
209 | ||
210 | if (!ctx || !gpio_is_valid(ctx->ro_gpio)) | |
211 | return; | |
212 | ||
213 | gpio = ctx->ro_gpio; | |
214 | ctx->ro_gpio = -EINVAL; | |
215 | ||
c8bdfea7 | 216 | devm_gpio_free(&host->class_dev, gpio); |
5aa7dad3 GL |
217 | } |
218 | EXPORT_SYMBOL(mmc_gpio_free_ro); | |
219 | ||
c8bdfea7 SG |
220 | /** |
221 | * mmc_gpio_free_cd - free the card-detection gpio | |
222 | * @host: mmc host | |
223 | * | |
224 | * It's provided only for cases that client drivers need to manually free | |
225 | * up the card-detection gpio requested by mmc_gpio_request_cd(). | |
226 | */ | |
fd0ea65d | 227 | void mmc_gpio_free_cd(struct mmc_host *host) |
349ab524 | 228 | { |
27410ee7 | 229 | struct mmc_gpio *ctx = host->slot.handler_priv; |
befe4048 | 230 | int gpio; |
349ab524 | 231 | |
befe4048 | 232 | if (!ctx || !gpio_is_valid(ctx->cd_gpio)) |
0e9f480b GL |
233 | return; |
234 | ||
befe4048 | 235 | if (host->slot.cd_irq >= 0) { |
c8bdfea7 | 236 | devm_free_irq(&host->class_dev, host->slot.cd_irq, host); |
befe4048 GL |
237 | host->slot.cd_irq = -EINVAL; |
238 | } | |
239 | ||
240 | gpio = ctx->cd_gpio; | |
241 | ctx->cd_gpio = -EINVAL; | |
242 | ||
c8bdfea7 | 243 | devm_gpio_free(&host->class_dev, gpio); |
349ab524 | 244 | } |
fd0ea65d | 245 | EXPORT_SYMBOL(mmc_gpio_free_cd); |