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> | |
842f4bdd | 13 | #include <linux/gpio/consumer.h> |
349ab524 GL |
14 | #include <linux/interrupt.h> |
15 | #include <linux/jiffies.h> | |
16 | #include <linux/mmc/host.h> | |
fd0ea65d | 17 | #include <linux/mmc/slot-gpio.h> |
349ab524 GL |
18 | #include <linux/module.h> |
19 | #include <linux/slab.h> | |
20 | ||
fd0ea65d | 21 | struct mmc_gpio { |
842f4bdd AH |
22 | struct gpio_desc *ro_gpio; |
23 | struct gpio_desc *cd_gpio; | |
24 | bool override_ro_active_level; | |
25 | bool override_cd_active_level; | |
5aa7dad3 | 26 | char *ro_label; |
fd0ea65d | 27 | char cd_label[0]; |
349ab524 GL |
28 | }; |
29 | ||
fd0ea65d | 30 | static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) |
349ab524 GL |
31 | { |
32 | /* Schedule a card detection after a debounce timeout */ | |
451c8957 GL |
33 | struct mmc_host *host = dev_id; |
34 | ||
fa372a51 | 35 | host->trigger_card_event = true; |
451c8957 GL |
36 | mmc_detect_change(host, msecs_to_jiffies(200)); |
37 | ||
349ab524 GL |
38 | return IRQ_HANDLED; |
39 | } | |
40 | ||
a7d1a1eb GL |
41 | static int mmc_gpio_alloc(struct mmc_host *host) |
42 | { | |
43 | size_t len = strlen(dev_name(host->parent)) + 4; | |
44 | struct mmc_gpio *ctx; | |
45 | ||
46 | mutex_lock(&host->slot.lock); | |
47 | ||
48 | ctx = host->slot.handler_priv; | |
49 | if (!ctx) { | |
50 | /* | |
51 | * devm_kzalloc() can be called after device_initialize(), even | |
52 | * before device_add(), i.e., between mmc_alloc_host() and | |
53 | * mmc_add_host() | |
54 | */ | |
5aa7dad3 | 55 | ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len, |
a7d1a1eb GL |
56 | GFP_KERNEL); |
57 | if (ctx) { | |
5aa7dad3 | 58 | ctx->ro_label = ctx->cd_label + len; |
a7d1a1eb | 59 | snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent)); |
5aa7dad3 | 60 | snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent)); |
a7d1a1eb GL |
61 | host->slot.handler_priv = ctx; |
62 | } | |
63 | } | |
64 | ||
65 | mutex_unlock(&host->slot.lock); | |
66 | ||
67 | return ctx ? 0 : -ENOMEM; | |
68 | } | |
69 | ||
5aa7dad3 GL |
70 | int mmc_gpio_get_ro(struct mmc_host *host) |
71 | { | |
72 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
73 | ||
842f4bdd | 74 | if (!ctx || !ctx->ro_gpio) |
5aa7dad3 GL |
75 | return -ENOSYS; |
76 | ||
842f4bdd AH |
77 | if (ctx->override_ro_active_level) |
78 | return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^ | |
79 | !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); | |
80 | ||
81 | return gpiod_get_value_cansleep(ctx->ro_gpio); | |
5aa7dad3 GL |
82 | } |
83 | EXPORT_SYMBOL(mmc_gpio_get_ro); | |
84 | ||
befe4048 GL |
85 | int mmc_gpio_get_cd(struct mmc_host *host) |
86 | { | |
87 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
88 | ||
842f4bdd | 89 | if (!ctx || !ctx->cd_gpio) |
befe4048 GL |
90 | return -ENOSYS; |
91 | ||
842f4bdd AH |
92 | if (ctx->override_cd_active_level) |
93 | return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^ | |
94 | !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); | |
95 | ||
96 | return gpiod_get_value_cansleep(ctx->cd_gpio); | |
befe4048 GL |
97 | } |
98 | EXPORT_SYMBOL(mmc_gpio_get_cd); | |
99 | ||
d65b5ae8 SG |
100 | /** |
101 | * mmc_gpio_request_ro - request a gpio for write-protection | |
102 | * @host: mmc host | |
103 | * @gpio: gpio number requested | |
104 | * | |
105 | * As devm_* managed functions are used in mmc_gpio_request_ro(), client | |
106 | * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up, | |
107 | * if the requesting and freeing are only needed at probing and unbinding time | |
108 | * for once. However, if client drivers do something special like runtime | |
109 | * switching for write-protection, they are responsible for calling | |
110 | * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own. | |
111 | * | |
112 | * Returns zero on success, else an error. | |
113 | */ | |
5aa7dad3 GL |
114 | int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio) |
115 | { | |
116 | struct mmc_gpio *ctx; | |
117 | int ret; | |
118 | ||
119 | if (!gpio_is_valid(gpio)) | |
120 | return -EINVAL; | |
121 | ||
122 | ret = mmc_gpio_alloc(host); | |
123 | if (ret < 0) | |
124 | return ret; | |
125 | ||
126 | ctx = host->slot.handler_priv; | |
127 | ||
d65b5ae8 SG |
128 | ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, |
129 | ctx->ro_label); | |
15e8a8e4 CB |
130 | if (ret < 0) |
131 | return ret; | |
132 | ||
842f4bdd AH |
133 | ctx->override_ro_active_level = true; |
134 | ctx->ro_gpio = gpio_to_desc(gpio); | |
15e8a8e4 CB |
135 | |
136 | return 0; | |
5aa7dad3 GL |
137 | } |
138 | EXPORT_SYMBOL(mmc_gpio_request_ro); | |
139 | ||
740a221e | 140 | void mmc_gpiod_request_cd_irq(struct mmc_host *host) |
26652671 AH |
141 | { |
142 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
143 | int ret, irq; | |
144 | ||
145 | if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio) | |
146 | return; | |
147 | ||
148 | irq = gpiod_to_irq(ctx->cd_gpio); | |
149 | ||
150 | /* | |
151 | * Even if gpiod_to_irq() returns a valid IRQ number, the platform might | |
152 | * still prefer to poll, e.g., because that IRQ number is already used | |
153 | * by another unit and cannot be shared. | |
154 | */ | |
155 | if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) | |
156 | irq = -EINVAL; | |
157 | ||
158 | if (irq >= 0) { | |
159 | ret = devm_request_threaded_irq(&host->class_dev, irq, | |
160 | NULL, mmc_gpio_cd_irqt, | |
161 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | |
162 | ctx->cd_label, host); | |
163 | if (ret < 0) | |
164 | irq = ret; | |
165 | } | |
166 | ||
167 | host->slot.cd_irq = irq; | |
168 | ||
169 | if (irq < 0) | |
170 | host->caps |= MMC_CAP_NEEDS_POLL; | |
171 | } | |
740a221e | 172 | EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); |
26652671 | 173 | |
d65b5ae8 SG |
174 | /** |
175 | * mmc_gpio_request_cd - request a gpio for card-detection | |
176 | * @host: mmc host | |
177 | * @gpio: gpio number requested | |
214fc309 | 178 | * @debounce: debounce time in microseconds |
d65b5ae8 SG |
179 | * |
180 | * As devm_* managed functions are used in mmc_gpio_request_cd(), client | |
181 | * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up, | |
182 | * if the requesting and freeing are only needed at probing and unbinding time | |
183 | * for once. However, if client drivers do something special like runtime | |
184 | * switching for card-detection, they are responsible for calling | |
185 | * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own. | |
186 | * | |
214fc309 LP |
187 | * If GPIO debouncing is desired, set the debounce parameter to a non-zero |
188 | * value. The caller is responsible for ensuring that the GPIO driver associated | |
189 | * with the GPIO supports debouncing, otherwise an error will be returned. | |
190 | * | |
d65b5ae8 SG |
191 | * Returns zero on success, else an error. |
192 | */ | |
214fc309 LP |
193 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, |
194 | unsigned int debounce) | |
349ab524 | 195 | { |
fd0ea65d | 196 | struct mmc_gpio *ctx; |
349ab524 GL |
197 | int ret; |
198 | ||
a7d1a1eb GL |
199 | ret = mmc_gpio_alloc(host); |
200 | if (ret < 0) | |
201 | return ret; | |
349ab524 | 202 | |
a7d1a1eb | 203 | ctx = host->slot.handler_priv; |
349ab524 | 204 | |
d65b5ae8 SG |
205 | ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, |
206 | ctx->cd_label); | |
349ab524 | 207 | if (ret < 0) |
a7d1a1eb GL |
208 | /* |
209 | * don't bother freeing memory. It might still get used by other | |
210 | * slot functions, in any case it will be freed, when the device | |
211 | * is destroyed. | |
212 | */ | |
213 | return ret; | |
349ab524 | 214 | |
214fc309 LP |
215 | if (debounce) { |
216 | ret = gpio_set_debounce(gpio, debounce); | |
217 | if (ret < 0) | |
218 | return ret; | |
219 | } | |
220 | ||
842f4bdd AH |
221 | ctx->override_cd_active_level = true; |
222 | ctx->cd_gpio = gpio_to_desc(gpio); | |
349ab524 | 223 | |
26652671 AH |
224 | mmc_gpiod_request_cd_irq(host); |
225 | ||
349ab524 | 226 | return 0; |
349ab524 | 227 | } |
fd0ea65d | 228 | EXPORT_SYMBOL(mmc_gpio_request_cd); |
349ab524 | 229 | |
d65b5ae8 SG |
230 | /** |
231 | * mmc_gpio_free_ro - free the write-protection gpio | |
232 | * @host: mmc host | |
233 | * | |
234 | * It's provided only for cases that client drivers need to manually free | |
235 | * up the write-protection gpio requested by mmc_gpio_request_ro(). | |
236 | */ | |
5aa7dad3 GL |
237 | void mmc_gpio_free_ro(struct mmc_host *host) |
238 | { | |
239 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
240 | int gpio; | |
241 | ||
842f4bdd | 242 | if (!ctx || !ctx->ro_gpio) |
5aa7dad3 GL |
243 | return; |
244 | ||
842f4bdd AH |
245 | gpio = desc_to_gpio(ctx->ro_gpio); |
246 | ctx->ro_gpio = NULL; | |
5aa7dad3 | 247 | |
d65b5ae8 | 248 | devm_gpio_free(&host->class_dev, gpio); |
5aa7dad3 GL |
249 | } |
250 | EXPORT_SYMBOL(mmc_gpio_free_ro); | |
251 | ||
d65b5ae8 SG |
252 | /** |
253 | * mmc_gpio_free_cd - free the card-detection gpio | |
254 | * @host: mmc host | |
255 | * | |
256 | * It's provided only for cases that client drivers need to manually free | |
257 | * up the card-detection gpio requested by mmc_gpio_request_cd(). | |
258 | */ | |
fd0ea65d | 259 | void mmc_gpio_free_cd(struct mmc_host *host) |
349ab524 | 260 | { |
27410ee7 | 261 | struct mmc_gpio *ctx = host->slot.handler_priv; |
befe4048 | 262 | int gpio; |
349ab524 | 263 | |
842f4bdd | 264 | if (!ctx || !ctx->cd_gpio) |
0e9f480b GL |
265 | return; |
266 | ||
befe4048 | 267 | if (host->slot.cd_irq >= 0) { |
d65b5ae8 | 268 | devm_free_irq(&host->class_dev, host->slot.cd_irq, host); |
befe4048 GL |
269 | host->slot.cd_irq = -EINVAL; |
270 | } | |
271 | ||
842f4bdd AH |
272 | gpio = desc_to_gpio(ctx->cd_gpio); |
273 | ctx->cd_gpio = NULL; | |
befe4048 | 274 | |
d65b5ae8 | 275 | devm_gpio_free(&host->class_dev, gpio); |
349ab524 | 276 | } |
fd0ea65d | 277 | EXPORT_SYMBOL(mmc_gpio_free_cd); |
740a221e AH |
278 | |
279 | /** | |
280 | * mmc_gpiod_request_cd - request a gpio descriptor for card-detection | |
281 | * @host: mmc host | |
282 | * @con_id: function within the GPIO consumer | |
283 | * @idx: index of the GPIO to obtain in the consumer | |
284 | * @override_active_level: ignore %GPIO_ACTIVE_LOW flag | |
285 | * @debounce: debounce time in microseconds | |
286 | * | |
287 | * Use this function in place of mmc_gpio_request_cd() to use the GPIO | |
288 | * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not | |
289 | * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host() | |
290 | * otherwise the caller must also call mmc_gpiod_request_cd_irq(). | |
291 | * | |
292 | * Returns zero on success, else an error. | |
293 | */ | |
294 | int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id, | |
295 | unsigned int idx, bool override_active_level, | |
296 | unsigned int debounce) | |
297 | { | |
298 | struct mmc_gpio *ctx; | |
299 | struct gpio_desc *desc; | |
300 | int ret; | |
301 | ||
302 | ret = mmc_gpio_alloc(host); | |
303 | if (ret < 0) | |
304 | return ret; | |
305 | ||
306 | ctx = host->slot.handler_priv; | |
307 | ||
308 | if (!con_id) | |
309 | con_id = ctx->cd_label; | |
310 | ||
9fbc6950 | 311 | desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); |
740a221e AH |
312 | if (IS_ERR(desc)) |
313 | return PTR_ERR(desc); | |
314 | ||
740a221e AH |
315 | if (debounce) { |
316 | ret = gpiod_set_debounce(desc, debounce); | |
317 | if (ret < 0) | |
318 | return ret; | |
319 | } | |
320 | ||
321 | ctx->override_cd_active_level = override_active_level; | |
322 | ctx->cd_gpio = desc; | |
323 | ||
324 | return 0; | |
325 | } | |
326 | EXPORT_SYMBOL(mmc_gpiod_request_cd); | |
327 | ||
9d2fa242 LW |
328 | /** |
329 | * mmc_gpiod_request_ro - request a gpio descriptor for write protection | |
330 | * @host: mmc host | |
331 | * @con_id: function within the GPIO consumer | |
332 | * @idx: index of the GPIO to obtain in the consumer | |
333 | * @override_active_level: ignore %GPIO_ACTIVE_LOW flag | |
334 | * @debounce: debounce time in microseconds | |
335 | * | |
336 | * Use this function in place of mmc_gpio_request_ro() to use the GPIO | |
337 | * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not | |
338 | * mmc_gpio_free_ro(). | |
339 | * | |
340 | * Returns zero on success, else an error. | |
341 | */ | |
342 | int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id, | |
343 | unsigned int idx, bool override_active_level, | |
344 | unsigned int debounce) | |
345 | { | |
346 | struct mmc_gpio *ctx; | |
347 | struct gpio_desc *desc; | |
348 | int ret; | |
349 | ||
350 | ret = mmc_gpio_alloc(host); | |
351 | if (ret < 0) | |
352 | return ret; | |
353 | ||
354 | ctx = host->slot.handler_priv; | |
355 | ||
356 | if (!con_id) | |
357 | con_id = ctx->ro_label; | |
358 | ||
359 | desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN); | |
360 | if (IS_ERR(desc)) | |
361 | return PTR_ERR(desc); | |
362 | ||
363 | if (debounce) { | |
364 | ret = gpiod_set_debounce(desc, debounce); | |
365 | if (ret < 0) | |
366 | return ret; | |
367 | } | |
368 | ||
369 | ctx->override_ro_active_level = override_active_level; | |
370 | ctx->ro_gpio = desc; | |
371 | ||
372 | return 0; | |
373 | } | |
374 | EXPORT_SYMBOL(mmc_gpiod_request_ro); | |
375 | ||
740a221e AH |
376 | /** |
377 | * mmc_gpiod_free_cd - free the card-detection gpio descriptor | |
378 | * @host: mmc host | |
379 | * | |
380 | * It's provided only for cases that client drivers need to manually free | |
381 | * up the card-detection gpio requested by mmc_gpiod_request_cd(). | |
382 | */ | |
383 | void mmc_gpiod_free_cd(struct mmc_host *host) | |
384 | { | |
385 | struct mmc_gpio *ctx = host->slot.handler_priv; | |
386 | ||
387 | if (!ctx || !ctx->cd_gpio) | |
388 | return; | |
389 | ||
390 | if (host->slot.cd_irq >= 0) { | |
391 | devm_free_irq(&host->class_dev, host->slot.cd_irq, host); | |
392 | host->slot.cd_irq = -EINVAL; | |
393 | } | |
394 | ||
395 | devm_gpiod_put(&host->class_dev, ctx->cd_gpio); | |
396 | ||
397 | ctx->cd_gpio = NULL; | |
398 | } | |
399 | EXPORT_SYMBOL(mmc_gpiod_free_cd); |