diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2012-05-01 10:27:25 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-07-21 00:02:17 -0400 |
commit | befe4048d8d20483a62636e20f3dbffebf85a1c1 (patch) | |
tree | 31bec106a3a2f4956cc1fd4a1fa4b465d31bddb9 /drivers | |
parent | 5c08d7fae0815cd163a98e05c8d94fc0de77ff67 (diff) |
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 <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/core/slot-gpio.c | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 468e5a0e5126..92cba02c04be 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | 19 | ||
20 | struct mmc_gpio { | 20 | struct mmc_gpio { |
21 | unsigned int cd_gpio; | 21 | int cd_gpio; |
22 | char cd_label[0]; | 22 | char cd_label[0]; |
23 | }; | 23 | }; |
24 | 24 | ||
@@ -29,6 +29,18 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) | |||
29 | return IRQ_HANDLED; | 29 | return IRQ_HANDLED; |
30 | } | 30 | } |
31 | 31 | ||
32 | int mmc_gpio_get_cd(struct mmc_host *host) | ||
33 | { | ||
34 | struct mmc_gpio *ctx = host->slot.handler_priv; | ||
35 | |||
36 | if (!ctx || !gpio_is_valid(ctx->cd_gpio)) | ||
37 | return -ENOSYS; | ||
38 | |||
39 | return !gpio_get_value_cansleep(ctx->cd_gpio) ^ | ||
40 | !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH); | ||
41 | } | ||
42 | EXPORT_SYMBOL(mmc_gpio_get_cd); | ||
43 | |||
32 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) | 44 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) |
33 | { | 45 | { |
34 | size_t len = strlen(dev_name(host->parent)) + 4; | 46 | 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) | |||
36 | int irq = gpio_to_irq(gpio); | 48 | int irq = gpio_to_irq(gpio); |
37 | int ret; | 49 | int ret; |
38 | 50 | ||
39 | if (irq < 0) | ||
40 | return irq; | ||
41 | |||
42 | ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL); | 51 | ctx = kmalloc(sizeof(*ctx) + len, GFP_KERNEL); |
43 | if (!ctx) | 52 | if (!ctx) |
44 | return -ENOMEM; | 53 | return -ENOMEM; |
@@ -49,20 +58,32 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) | |||
49 | if (ret < 0) | 58 | if (ret < 0) |
50 | goto egpioreq; | 59 | goto egpioreq; |
51 | 60 | ||
52 | ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, | 61 | /* |
62 | * Even if gpio_to_irq() returns a valid IRQ number, the platform might | ||
63 | * still prefer to poll, e.g., because that IRQ number is already used | ||
64 | * by another unit and cannot be shared. | ||
65 | */ | ||
66 | if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL) | ||
67 | irq = -EINVAL; | ||
68 | |||
69 | if (irq >= 0) { | ||
70 | ret = request_threaded_irq(irq, NULL, mmc_gpio_cd_irqt, | ||
53 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | 71 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
54 | ctx->cd_label, host); | 72 | ctx->cd_label, host); |
55 | if (ret < 0) | 73 | if (ret < 0) |
56 | goto eirqreq; | 74 | irq = ret; |
75 | } | ||
57 | 76 | ||
58 | ctx->cd_gpio = gpio; | ||
59 | host->slot.cd_irq = irq; | 77 | host->slot.cd_irq = irq; |
78 | |||
79 | if (irq < 0) | ||
80 | host->caps |= MMC_CAP_NEEDS_POLL; | ||
81 | |||
82 | ctx->cd_gpio = gpio; | ||
60 | host->slot.handler_priv = ctx; | 83 | host->slot.handler_priv = ctx; |
61 | 84 | ||
62 | return 0; | 85 | return 0; |
63 | 86 | ||
64 | eirqreq: | ||
65 | gpio_free(gpio); | ||
66 | egpioreq: | 87 | egpioreq: |
67 | kfree(ctx); | 88 | kfree(ctx); |
68 | return ret; | 89 | return ret; |
@@ -72,12 +93,21 @@ EXPORT_SYMBOL(mmc_gpio_request_cd); | |||
72 | void mmc_gpio_free_cd(struct mmc_host *host) | 93 | void mmc_gpio_free_cd(struct mmc_host *host) |
73 | { | 94 | { |
74 | struct mmc_gpio *ctx = host->slot.handler_priv; | 95 | struct mmc_gpio *ctx = host->slot.handler_priv; |
96 | int gpio; | ||
75 | 97 | ||
76 | if (!ctx) | 98 | if (!ctx || !gpio_is_valid(ctx->cd_gpio)) |
77 | return; | 99 | return; |
78 | 100 | ||
79 | free_irq(host->slot.cd_irq, host); | 101 | if (host->slot.cd_irq >= 0) { |
80 | gpio_free(ctx->cd_gpio); | 102 | free_irq(host->slot.cd_irq, host); |
103 | host->slot.cd_irq = -EINVAL; | ||
104 | } | ||
105 | |||
106 | gpio = ctx->cd_gpio; | ||
107 | ctx->cd_gpio = -EINVAL; | ||
108 | |||
109 | gpio_free(gpio); | ||
110 | host->slot.handler_priv = NULL; | ||
81 | kfree(ctx); | 111 | kfree(ctx); |
82 | } | 112 | } |
83 | EXPORT_SYMBOL(mmc_gpio_free_cd); | 113 | EXPORT_SYMBOL(mmc_gpio_free_cd); |