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