blob: 468e5a0e5126d9108d294a2c669c07eddde672e0 [file] [log] [blame]
Guennadi Liakhovetskifd0ea652012-04-30 23:31:57 +02001/*
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/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
20struct mmc_gpio {
21 unsigned int cd_gpio;
22 char cd_label[0];
23};
24
25static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
26{
27 /* Schedule a card detection after a debounce timeout */
28 mmc_detect_change(dev_id, msecs_to_jiffies(100));
29 return IRQ_HANDLED;
30}
31
32int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
33{
34 size_t len = strlen(dev_name(host->parent)) + 4;
35 struct mmc_gpio *ctx;
36 int irq = gpio_to_irq(gpio);
37 int ret;
38
39 if (irq < 0)
40 return irq;
41
42 ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL);
43 if (!ctx)
44 return -ENOMEM;
45
46 snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
47
48 ret = gpio_request_one(gpio, GPIOF_DIR_IN, ctx->cd_label);
49 if (ret < 0)
50 goto egpioreq;
51
52 ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt,
53 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
54 ctx->cd_label, host);
55 if (ret < 0)
56 goto eirqreq;
57
58 ctx->cd_gpio = gpio;
Guennadi Liakhovetski27410ee2012-05-01 15:40:15 +020059 host->slot.cd_irq = irq;
60 host->slot.handler_priv = ctx;
Guennadi Liakhovetskifd0ea652012-04-30 23:31:57 +020061
62 return 0;
63
64eirqreq:
65 gpio_free(gpio);
66egpioreq:
67 kfree(ctx);
68 return ret;
69}
70EXPORT_SYMBOL(mmc_gpio_request_cd);
71
72void mmc_gpio_free_cd(struct mmc_host *host)
73{
Guennadi Liakhovetski27410ee2012-05-01 15:40:15 +020074 struct mmc_gpio *ctx = host->slot.handler_priv;
Guennadi Liakhovetskifd0ea652012-04-30 23:31:57 +020075
76 if (!ctx)
77 return;
78
Guennadi Liakhovetski27410ee2012-05-01 15:40:15 +020079 free_irq(host->slot.cd_irq, host);
Guennadi Liakhovetskifd0ea652012-04-30 23:31:57 +020080 gpio_free(ctx->cd_gpio);
81 kfree(ctx);
82}
83EXPORT_SYMBOL(mmc_gpio_free_cd);