From befe4048d8d20483a62636e20f3dbffebf85a1c1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 1 May 2012 16:27:25 +0200 Subject: [PATCH] mmc: add CD GPIO polling support to slot functions A simple extension of mmc slot functions add support for CD GPIO polling for cases where the GPIO cannot produce interrupts, or where this is not desired for some reason. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/core/slot-gpio.c | 56 +++++++++++++++++++++++++++-------- include/linux/mmc/slot-gpio.h | 2 ++ 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 468e5a0e512..92cba02c04b 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -18,7 +18,7 @@ #include struct mmc_gpio { - unsigned int cd_gpio; + int cd_gpio; char cd_label[0]; }; @@ -29,6 +29,18 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) return IRQ_HANDLED; } +int mmc_gpio_get_cd(struct mmc_host *host) +{ + struct mmc_gpio *ctx = host->slot.handler_priv; + + if (!ctx || !gpio_is_valid(ctx->cd_gpio)) + return -ENOSYS; + + return !gpio_get_value_cansleep(ctx->cd_gpio) ^ + !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); +} +EXPORT_SYMBOL(mmc_gpio_get_cd); + int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) { size_t len = strlen(dev_name(host->parent)) + 4; @@ -36,9 +48,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) int irq = gpio_to_irq(gpio); int ret; - if (irq < 0) - return irq; - ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL); if (!ctx) return -ENOMEM; @@ -49,20 +58,32 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) if (ret < 0) goto egpioreq; - ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, + /* + * Even if gpio_to_irq() returns a valid IRQ number, the platform might + * still prefer to poll, e.g., because that IRQ number is already used + * by another unit and cannot be shared. + */ + if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) + irq = -EINVAL; + + if (irq >= 0) { + ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ctx->cd_label, host); - if (ret < 0) - goto eirqreq; + if (ret < 0) + irq = ret; + } - ctx->cd_gpio = gpio; host->slot.cd_irq = irq; + + if (irq < 0) + host->caps |= MMC_CAP_NEEDS_POLL; + + ctx->cd_gpio = gpio; host->slot.handler_priv = ctx; return 0; -eirqreq: - gpio_free(gpio); egpioreq: kfree(ctx); return ret; @@ -72,12 +93,21 @@ EXPORT_SYMBOL(mmc_gpio_request_cd); void mmc_gpio_free_cd(struct mmc_host *host) { struct mmc_gpio *ctx = host->slot.handler_priv; + int gpio; - if (!ctx) + if (!ctx || !gpio_is_valid(ctx->cd_gpio)) return; - free_irq(host->slot.cd_irq, host); - gpio_free(ctx->cd_gpio); + if (host->slot.cd_irq >= 0) { + free_irq(host->slot.cd_irq, host); + host->slot.cd_irq = -EINVAL; + } + + gpio = ctx->cd_gpio; + ctx->cd_gpio = -EINVAL; + + gpio_free(gpio); + host->slot.handler_priv = NULL; kfree(ctx); } EXPORT_SYMBOL(mmc_gpio_free_cd); diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index edfaa325437..1a977d7ba3b 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -12,6 +12,8 @@ #define MMC_SLOT_GPIO_H struct mmc_host; + +int mmc_gpio_get_cd(struct mmc_host *host); int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio); void mmc_gpio_free_cd(struct mmc_host *host); -- 2.34.1