aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/sdhci-spear.c79
1 files changed, 17 insertions, 62 deletions
diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c
index 676df4623057..0316dec3f006 100644
--- a/drivers/mmc/host/sdhci-spear.c
+++ b/drivers/mmc/host/sdhci-spear.c
@@ -27,6 +27,7 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/mmc/host.h> 28#include <linux/mmc/host.h>
29#include <linux/mmc/sdhci-spear.h> 29#include <linux/mmc/sdhci-spear.h>
30#include <linux/mmc/slot-gpio.h>
30#include <linux/io.h> 31#include <linux/io.h>
31#include "sdhci.h" 32#include "sdhci.h"
32 33
@@ -40,28 +41,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
40 /* Nothing to do for now. */ 41 /* Nothing to do for now. */
41}; 42};
42 43
43/* gpio card detection interrupt handler */
44static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
45{
46 struct platform_device *pdev = dev_id;
47 struct sdhci_host *host = platform_get_drvdata(pdev);
48 struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
49 unsigned long gpio_irq_type;
50 int val;
51
52 val = gpio_get_value(sdhci->data->card_int_gpio);
53
54 /* val == 1 -> card removed, val == 0 -> card inserted */
55 /* if card removed - set irq for low level, else vice versa */
56 gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
57 irq_set_irq_type(irq, gpio_irq_type);
58
59 /* inform sdhci driver about card insertion/removal */
60 tasklet_schedule(&host->card_tasklet);
61
62 return IRQ_HANDLED;
63}
64
65#ifdef CONFIG_OF 44#ifdef CONFIG_OF
66static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) 45static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
67{ 46{
@@ -152,6 +131,22 @@ static int sdhci_probe(struct platform_device *pdev)
152 sdhci->data = dev_get_platdata(&pdev->dev); 131 sdhci->data = dev_get_platdata(&pdev->dev);
153 } 132 }
154 133
134 /*
135 * It is optional to use GPIOs for sdhci card detection. If
136 * sdhci->data is NULL, then use original sdhci lines otherwise
137 * GPIO lines. We use the built-in GPIO support for this.
138 */
139 if (sdhci->data && sdhci->data->card_int_gpio >= 0) {
140 ret = mmc_gpio_request_cd(host->mmc,
141 sdhci->data->card_int_gpio, 0);
142 if (ret < 0) {
143 dev_dbg(&pdev->dev,
144 "failed to request card-detect gpio%d\n",
145 sdhci->data->card_int_gpio);
146 goto disable_clk;
147 }
148 }
149
155 ret = sdhci_add_host(host); 150 ret = sdhci_add_host(host);
156 if (ret) { 151 if (ret) {
157 dev_dbg(&pdev->dev, "error adding host\n"); 152 dev_dbg(&pdev->dev, "error adding host\n");
@@ -160,48 +155,8 @@ static int sdhci_probe(struct platform_device *pdev)
160 155
161 platform_set_drvdata(pdev, host); 156 platform_set_drvdata(pdev, host);
162 157
163 /*
164 * It is optional to use GPIOs for sdhci Power control & sdhci card
165 * interrupt detection. If sdhci->data is NULL, then use original sdhci
166 * lines otherwise GPIO lines.
167 * If GPIO is selected for power control, then power should be disabled
168 * after card removal and should be enabled when card insertion
169 * interrupt occurs
170 */
171 if (!sdhci->data)
172 return 0;
173
174 if (sdhci->data->card_int_gpio >= 0) {
175 ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio,
176 "sdhci");
177 if (ret < 0) {
178 dev_dbg(&pdev->dev, "gpio request fail: %d\n",
179 sdhci->data->card_int_gpio);
180 goto set_drvdata;
181 }
182
183 ret = gpio_direction_input(sdhci->data->card_int_gpio);
184 if (ret) {
185 dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
186 sdhci->data->card_int_gpio);
187 goto set_drvdata;
188 }
189 ret = devm_request_irq(&pdev->dev,
190 gpio_to_irq(sdhci->data->card_int_gpio),
191 sdhci_gpio_irq, IRQF_TRIGGER_LOW,
192 mmc_hostname(host->mmc), pdev);
193 if (ret) {
194 dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
195 sdhci->data->card_int_gpio);
196 goto set_drvdata;
197 }
198
199 }
200
201 return 0; 158 return 0;
202 159
203set_drvdata:
204 sdhci_remove_host(host, 1);
205disable_clk: 160disable_clk:
206 clk_disable_unprepare(sdhci->clk); 161 clk_disable_unprepare(sdhci->clk);
207err_host: 162err_host: