Merge branch 'core/speculation' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / mmc / core / slot-gpio.c
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/consumer.h>
13 #include <linux/interrupt.h>
14 #include <linux/jiffies.h>
15 #include <linux/mmc/host.h>
16 #include <linux/mmc/slot-gpio.h>
17 #include <linux/module.h>
18 #include <linux/slab.h>
19
20 #include "slot-gpio.h"
21
22 struct mmc_gpio {
23         struct gpio_desc *ro_gpio;
24         struct gpio_desc *cd_gpio;
25         bool override_cd_active_level;
26         irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
27         char *ro_label;
28         char *cd_label;
29         u32 cd_debounce_delay_ms;
30 };
31
32 static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
33 {
34         /* Schedule a card detection after a debounce timeout */
35         struct mmc_host *host = dev_id;
36         struct mmc_gpio *ctx = host->slot.handler_priv;
37
38         host->trigger_card_event = true;
39         mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
40
41         return IRQ_HANDLED;
42 }
43
44 int mmc_gpio_alloc(struct mmc_host *host)
45 {
46         struct mmc_gpio *ctx = devm_kzalloc(host->parent,
47                                             sizeof(*ctx), GFP_KERNEL);
48
49         if (ctx) {
50                 ctx->cd_debounce_delay_ms = 200;
51                 ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL,
52                                 "%s cd", dev_name(host->parent));
53                 if (!ctx->cd_label)
54                         return -ENOMEM;
55                 ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL,
56                                 "%s ro", dev_name(host->parent));
57                 if (!ctx->ro_label)
58                         return -ENOMEM;
59                 host->slot.handler_priv = ctx;
60                 host->slot.cd_irq = -EINVAL;
61         }
62
63         return ctx ? 0 : -ENOMEM;
64 }
65
66 int mmc_gpio_get_ro(struct mmc_host *host)
67 {
68         struct mmc_gpio *ctx = host->slot.handler_priv;
69
70         if (!ctx || !ctx->ro_gpio)
71                 return -ENOSYS;
72
73         return gpiod_get_value_cansleep(ctx->ro_gpio);
74 }
75 EXPORT_SYMBOL(mmc_gpio_get_ro);
76
77 int mmc_gpio_get_cd(struct mmc_host *host)
78 {
79         struct mmc_gpio *ctx = host->slot.handler_priv;
80         int cansleep;
81
82         if (!ctx || !ctx->cd_gpio)
83                 return -ENOSYS;
84
85         cansleep = gpiod_cansleep(ctx->cd_gpio);
86         if (ctx->override_cd_active_level) {
87                 int value = cansleep ?
88                                 gpiod_get_raw_value_cansleep(ctx->cd_gpio) :
89                                 gpiod_get_raw_value(ctx->cd_gpio);
90                 return !value ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
91         }
92
93         return cansleep ?
94                 gpiod_get_value_cansleep(ctx->cd_gpio) :
95                 gpiod_get_value(ctx->cd_gpio);
96 }
97 EXPORT_SYMBOL(mmc_gpio_get_cd);
98
99 void mmc_gpiod_request_cd_irq(struct mmc_host *host)
100 {
101         struct mmc_gpio *ctx = host->slot.handler_priv;
102         int irq = -EINVAL;
103         int ret;
104
105         if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
106                 return;
107
108         /*
109          * Do not use IRQ if the platform prefers to poll, e.g., because that
110          * IRQ number is already used by another unit and cannot be shared.
111          */
112         if (!(host->caps & MMC_CAP_NEEDS_POLL))
113                 irq = gpiod_to_irq(ctx->cd_gpio);
114
115         if (irq >= 0) {
116                 if (!ctx->cd_gpio_isr)
117                         ctx->cd_gpio_isr = mmc_gpio_cd_irqt;
118                 ret = devm_request_threaded_irq(host->parent, irq,
119                         NULL, ctx->cd_gpio_isr,
120                         IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
121                         ctx->cd_label, host);
122                 if (ret < 0)
123                         irq = ret;
124         }
125
126         host->slot.cd_irq = irq;
127
128         if (irq < 0)
129                 host->caps |= MMC_CAP_NEEDS_POLL;
130 }
131 EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
132
133 int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on)
134 {
135         int ret = 0;
136
137         if (!(host->caps & MMC_CAP_CD_WAKE) ||
138             host->slot.cd_irq < 0 ||
139             on == host->slot.cd_wake_enabled)
140                 return 0;
141
142         if (on) {
143                 ret = enable_irq_wake(host->slot.cd_irq);
144                 host->slot.cd_wake_enabled = !ret;
145         } else {
146                 disable_irq_wake(host->slot.cd_irq);
147                 host->slot.cd_wake_enabled = false;
148         }
149
150         return ret;
151 }
152 EXPORT_SYMBOL(mmc_gpio_set_cd_wake);
153
154 /* Register an alternate interrupt service routine for
155  * the card-detect GPIO.
156  */
157 void mmc_gpio_set_cd_isr(struct mmc_host *host,
158                          irqreturn_t (*isr)(int irq, void *dev_id))
159 {
160         struct mmc_gpio *ctx = host->slot.handler_priv;
161
162         WARN_ON(ctx->cd_gpio_isr);
163         ctx->cd_gpio_isr = isr;
164 }
165 EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
166
167 /**
168  * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
169  * @host: mmc host
170  * @con_id: function within the GPIO consumer
171  * @idx: index of the GPIO to obtain in the consumer
172  * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
173  * @debounce: debounce time in microseconds
174  * @gpio_invert: will return whether the GPIO line is inverted or not, set
175  * to NULL to ignore
176  *
177  * Note that this must be called prior to mmc_add_host()
178  * otherwise the caller must also call mmc_gpiod_request_cd_irq().
179  *
180  * Returns zero on success, else an error.
181  */
182 int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
183                          unsigned int idx, bool override_active_level,
184                          unsigned int debounce, bool *gpio_invert)
185 {
186         struct mmc_gpio *ctx = host->slot.handler_priv;
187         struct gpio_desc *desc;
188         int ret;
189
190         desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
191         if (IS_ERR(desc))
192                 return PTR_ERR(desc);
193
194         if (debounce) {
195                 ret = gpiod_set_debounce(desc, debounce);
196                 if (ret < 0)
197                         ctx->cd_debounce_delay_ms = debounce / 1000;
198         }
199
200         if (gpio_invert)
201                 *gpio_invert = !gpiod_is_active_low(desc);
202
203         ctx->override_cd_active_level = override_active_level;
204         ctx->cd_gpio = desc;
205
206         return 0;
207 }
208 EXPORT_SYMBOL(mmc_gpiod_request_cd);
209
210 bool mmc_can_gpio_cd(struct mmc_host *host)
211 {
212         struct mmc_gpio *ctx = host->slot.handler_priv;
213
214         return ctx->cd_gpio ? true : false;
215 }
216 EXPORT_SYMBOL(mmc_can_gpio_cd);
217
218 /**
219  * mmc_gpiod_request_ro - request a gpio descriptor for write protection
220  * @host: mmc host
221  * @con_id: function within the GPIO consumer
222  * @idx: index of the GPIO to obtain in the consumer
223  * @debounce: debounce time in microseconds
224  * @gpio_invert: will return whether the GPIO line is inverted or not,
225  * set to NULL to ignore
226  *
227  * Returns zero on success, else an error.
228  */
229 int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
230                          unsigned int idx,
231                          unsigned int debounce, bool *gpio_invert)
232 {
233         struct mmc_gpio *ctx = host->slot.handler_priv;
234         struct gpio_desc *desc;
235         int ret;
236
237         desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
238         if (IS_ERR(desc))
239                 return PTR_ERR(desc);
240
241         if (debounce) {
242                 ret = gpiod_set_debounce(desc, debounce);
243                 if (ret < 0)
244                         return ret;
245         }
246
247         if (gpio_invert)
248                 *gpio_invert = !gpiod_is_active_low(desc);
249
250         ctx->ro_gpio = desc;
251
252         return 0;
253 }
254 EXPORT_SYMBOL(mmc_gpiod_request_ro);
255
256 bool mmc_can_gpio_ro(struct mmc_host *host)
257 {
258         struct mmc_gpio *ctx = host->slot.handler_priv;
259
260         return ctx->ro_gpio ? true : false;
261 }
262 EXPORT_SYMBOL(mmc_can_gpio_ro);