Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci-spear: use generic card detection gpio support

sdhci has support for using GPIOs for card detection. If we have a
GPIO specified, we can use that directly, without needing our own
interrupt handler.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Chris Ball <chris@printf.net>

authored by

Russell King and committed by
Chris Ball
b42b9b12 42c1add9

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