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