diff options
-rw-r--r-- | drivers/mmc/core/slot-gpio.c | 56 | ||||
-rw-r--r-- | 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 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); |
diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index edfaa3254373..1a977d7ba3ba 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h | |||
@@ -12,6 +12,8 @@ | |||
12 | #define MMC_SLOT_GPIO_H | 12 | #define MMC_SLOT_GPIO_H |
13 | 13 | ||
14 | struct mmc_host; | 14 | struct mmc_host; |
15 | |||
16 | int mmc_gpio_get_cd(struct mmc_host *host); | ||
15 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio); | 17 | int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio); |
16 | void mmc_gpio_free_cd(struct mmc_host *host); | 18 | void mmc_gpio_free_cd(struct mmc_host *host); |
17 | 19 | ||