linux/drivers/mmc/core/slot-gpio.c
<<
>>
Prefs
   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/gpio/consumer.h>
  14#include <linux/interrupt.h>
  15#include <linux/jiffies.h>
  16#include <linux/mmc/host.h>
  17#include <linux/mmc/slot-gpio.h>
  18#include <linux/module.h>
  19#include <linux/slab.h>
  20
  21#include "slot-gpio.h"
  22
  23struct mmc_gpio {
  24        struct gpio_desc *ro_gpio;
  25        struct gpio_desc *cd_gpio;
  26        bool override_ro_active_level;
  27        bool override_cd_active_level;
  28        irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
  29        char *ro_label;
  30        char cd_label[0];
  31};
  32
  33static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
  34{
  35        /* Schedule a card detection after a debounce timeout */
  36        struct mmc_host *host = dev_id;
  37
  38        host->trigger_card_event = true;
  39        mmc_detect_change(host, msecs_to_jiffies(200));
  40
  41        return IRQ_HANDLED;
  42}
  43
  44int mmc_gpio_alloc(struct mmc_host *host)
  45{
  46        size_t len = strlen(dev_name(host->parent)) + 4;
  47        struct mmc_gpio *ctx = devm_kzalloc(host->parent,
  48                                sizeof(*ctx) + 2 * len, GFP_KERNEL);
  49
  50        if (ctx) {
  51                ctx->ro_label = ctx->cd_label + len;
  52                snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
  53                snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
  54                host->slot.handler_priv = ctx;
  55                host->slot.cd_irq = -EINVAL;
  56        }
  57
  58        return ctx ? 0 : -ENOMEM;
  59}
  60
  61int mmc_gpio_get_ro(struct mmc_host *host)
  62{
  63        struct mmc_gpio *ctx = host->slot.handler_priv;
  64
  65        if (!ctx || !ctx->ro_gpio)
  66                return -ENOSYS;
  67
  68        if (ctx->override_ro_active_level)
  69                return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^
  70                        !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
  71
  72        return gpiod_get_value_cansleep(ctx->ro_gpio);
  73}
  74EXPORT_SYMBOL(mmc_gpio_get_ro);
  75
  76int mmc_gpio_get_cd(struct mmc_host *host)
  77{
  78        struct mmc_gpio *ctx = host->slot.handler_priv;
  79
  80        if (!ctx || !ctx->cd_gpio)
  81                return -ENOSYS;
  82
  83        if (ctx->override_cd_active_level)
  84                return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
  85                        !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
  86
  87        return gpiod_get_value_cansleep(ctx->cd_gpio);
  88}
  89EXPORT_SYMBOL(mmc_gpio_get_cd);
  90
  91/**
  92 * mmc_gpio_request_ro - request a gpio for write-protection
  93 * @host: mmc host
  94 * @gpio: gpio number requested
  95 *
  96 * As devm_* managed functions are used in mmc_gpio_request_ro(), client
  97 * drivers do not need to worry about freeing up memory.
  98 *
  99 * Returns zero on success, else an error.
 100 */
 101int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
 102{
 103        struct mmc_gpio *ctx = host->slot.handler_priv;
 104        int ret;
 105
 106        if (!gpio_is_valid(gpio))
 107                return -EINVAL;
 108
 109        ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
 110                                    ctx->ro_label);
 111        if (ret < 0)
 112                return ret;
 113
 114        ctx->override_ro_active_level = true;
 115        ctx->ro_gpio = gpio_to_desc(gpio);
 116
 117        return 0;
 118}
 119EXPORT_SYMBOL(mmc_gpio_request_ro);
 120
 121void mmc_gpiod_request_cd_irq(struct mmc_host *host)
 122{
 123        struct mmc_gpio *ctx = host->slot.handler_priv;
 124        int ret, irq;
 125
 126        if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
 127                return;
 128
 129        irq = gpiod_to_irq(ctx->cd_gpio);
 130
 131        /*
 132         * Even if gpiod_to_irq() returns a valid IRQ number, the platform might
 133         * still prefer to poll, e.g., because that IRQ number is already used
 134         * by another unit and cannot be shared.
 135         */
 136        if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
 137                irq = -EINVAL;
 138
 139        if (irq >= 0) {
 140                if (!ctx->cd_gpio_isr)
 141                        ctx->cd_gpio_isr = mmc_gpio_cd_irqt;
 142                ret = devm_request_threaded_irq(host->parent, irq,
 143                        NULL, ctx->cd_gpio_isr,
 144                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 145                        ctx->cd_label, host);
 146                if (ret < 0)
 147                        irq = ret;
 148        }
 149
 150        host->slot.cd_irq = irq;
 151
 152        if (irq < 0)
 153                host->caps |= MMC_CAP_NEEDS_POLL;
 154}
 155EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
 156
 157/* Register an alternate interrupt service routine for
 158 * the card-detect GPIO.
 159 */
 160void mmc_gpio_set_cd_isr(struct mmc_host *host,
 161                         irqreturn_t (*isr)(int irq, void *dev_id))
 162{
 163        struct mmc_gpio *ctx = host->slot.handler_priv;
 164
 165        WARN_ON(ctx->cd_gpio_isr);
 166        ctx->cd_gpio_isr = isr;
 167}
 168EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
 169
 170/**
 171 * mmc_gpio_request_cd - request a gpio for card-detection
 172 * @host: mmc host
 173 * @gpio: gpio number requested
 174 * @debounce: debounce time in microseconds
 175 *
 176 * As devm_* managed functions are used in mmc_gpio_request_cd(), client
 177 * drivers do not need to worry about freeing up memory.
 178 *
 179 * If GPIO debouncing is desired, set the debounce parameter to a non-zero
 180 * value. The caller is responsible for ensuring that the GPIO driver associated
 181 * with the GPIO supports debouncing, otherwise an error will be returned.
 182 *
 183 * Returns zero on success, else an error.
 184 */
 185int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
 186                        unsigned int debounce)
 187{
 188        struct mmc_gpio *ctx = host->slot.handler_priv;
 189        int ret;
 190
 191        ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
 192                                    ctx->cd_label);
 193        if (ret < 0)
 194                /*
 195                 * don't bother freeing memory. It might still get used by other
 196                 * slot functions, in any case it will be freed, when the device
 197                 * is destroyed.
 198                 */
 199                return ret;
 200
 201        if (debounce) {
 202                ret = gpio_set_debounce(gpio, debounce);
 203                if (ret < 0)
 204                        return ret;
 205        }
 206
 207        ctx->override_cd_active_level = true;
 208        ctx->cd_gpio = gpio_to_desc(gpio);
 209
 210        return 0;
 211}
 212EXPORT_SYMBOL(mmc_gpio_request_cd);
 213
 214/**
 215 * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
 216 * @host: mmc host
 217 * @con_id: function within the GPIO consumer
 218 * @idx: index of the GPIO to obtain in the consumer
 219 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
 220 * @debounce: debounce time in microseconds
 221 * @gpio_invert: will return whether the GPIO line is inverted or not, set
 222 * to NULL to ignore
 223 *
 224 * Use this function in place of mmc_gpio_request_cd() to use the GPIO
 225 * descriptor API.  Note that it must be called prior to mmc_add_host()
 226 * otherwise the caller must also call mmc_gpiod_request_cd_irq().
 227 *
 228 * Returns zero on success, else an error.
 229 */
 230int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
 231                         unsigned int idx, bool override_active_level,
 232                         unsigned int debounce, bool *gpio_invert)
 233{
 234        struct mmc_gpio *ctx = host->slot.handler_priv;
 235        struct gpio_desc *desc;
 236        int ret;
 237
 238        if (!con_id)
 239                con_id = ctx->cd_label;
 240
 241        desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
 242        if (IS_ERR(desc))
 243                return PTR_ERR(desc);
 244
 245        if (debounce) {
 246                ret = gpiod_set_debounce(desc, debounce);
 247                if (ret < 0)
 248                        return ret;
 249        }
 250
 251        if (gpio_invert)
 252                *gpio_invert = !gpiod_is_active_low(desc);
 253
 254        ctx->override_cd_active_level = override_active_level;
 255        ctx->cd_gpio = desc;
 256
 257        return 0;
 258}
 259EXPORT_SYMBOL(mmc_gpiod_request_cd);
 260
 261/**
 262 * mmc_gpiod_request_ro - request a gpio descriptor for write protection
 263 * @host: mmc host
 264 * @con_id: function within the GPIO consumer
 265 * @idx: index of the GPIO to obtain in the consumer
 266 * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
 267 * @debounce: debounce time in microseconds
 268 * @gpio_invert: will return whether the GPIO line is inverted or not,
 269 * set to NULL to ignore
 270 *
 271 * Use this function in place of mmc_gpio_request_ro() to use the GPIO
 272 * descriptor API.
 273 *
 274 * Returns zero on success, else an error.
 275 */
 276int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
 277                         unsigned int idx, bool override_active_level,
 278                         unsigned int debounce, bool *gpio_invert)
 279{
 280        struct mmc_gpio *ctx = host->slot.handler_priv;
 281        struct gpio_desc *desc;
 282        int ret;
 283
 284        if (!con_id)
 285                con_id = ctx->ro_label;
 286
 287        desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
 288        if (IS_ERR(desc))
 289                return PTR_ERR(desc);
 290
 291        if (debounce) {
 292                ret = gpiod_set_debounce(desc, debounce);
 293                if (ret < 0)
 294                        return ret;
 295        }
 296
 297        if (gpio_invert)
 298                *gpio_invert = !gpiod_is_active_low(desc);
 299
 300        ctx->override_ro_active_level = override_active_level;
 301        ctx->ro_gpio = desc;
 302
 303        return 0;
 304}
 305EXPORT_SYMBOL(mmc_gpiod_request_ro);
 306