diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2013-05-06 05:17:33 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-05-26 14:23:24 -0400 |
commit | a61abe6eebfda1add8cb54e6e10384ea747d68a5 (patch) | |
tree | c90f64916791cfcee3e8af856775a6491294b200 | |
parent | f0710a557cb17746b09234f01073a2cdafe4f4a5 (diff) |
mmc: sdhci-acpi: support runtime PM for ACPI HID 80860F14 SD cards
Enable runtime PM for ACPI HID 80860F14 SD cards, adding support for
card detect GPIO.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/sdhci-acpi.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index b1a6588b50fa..a51e603acbc5 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c | |||
@@ -31,8 +31,10 @@ | |||
31 | #include <linux/bitops.h> | 31 | #include <linux/bitops.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/err.h> | 33 | #include <linux/err.h> |
34 | #include <linux/gpio.h> | ||
34 | #include <linux/interrupt.h> | 35 | #include <linux/interrupt.h> |
35 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
37 | #include <linux/acpi_gpio.h> | ||
36 | #include <linux/pm.h> | 38 | #include <linux/pm.h> |
37 | #include <linux/pm_runtime.h> | 39 | #include <linux/pm_runtime.h> |
38 | 40 | ||
@@ -101,6 +103,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { | |||
101 | }; | 103 | }; |
102 | 104 | ||
103 | static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { | 105 | static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = { |
106 | .flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM, | ||
107 | .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON, | ||
104 | }; | 108 | }; |
105 | 109 | ||
106 | struct sdhci_acpi_uid_slot { | 110 | struct sdhci_acpi_uid_slot { |
@@ -161,6 +165,57 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle, | |||
161 | return slot; | 165 | return slot; |
162 | } | 166 | } |
163 | 167 | ||
168 | #ifdef CONFIG_PM_RUNTIME | ||
169 | |||
170 | static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id) | ||
171 | { | ||
172 | mmc_detect_change(dev_id, msecs_to_jiffies(200)); | ||
173 | return IRQ_HANDLED; | ||
174 | } | ||
175 | |||
176 | static int sdhci_acpi_add_own_cd(struct device *dev, int gpio, | ||
177 | struct mmc_host *mmc) | ||
178 | { | ||
179 | unsigned long flags; | ||
180 | int err, irq; | ||
181 | |||
182 | if (gpio < 0) { | ||
183 | err = gpio; | ||
184 | goto out; | ||
185 | } | ||
186 | |||
187 | err = devm_gpio_request_one(dev, gpio, GPIOF_DIR_IN, "sd_cd"); | ||
188 | if (err) | ||
189 | goto out; | ||
190 | |||
191 | irq = gpio_to_irq(gpio); | ||
192 | if (irq < 0) | ||
193 | goto out_free; | ||
194 | |||
195 | flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; | ||
196 | err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc); | ||
197 | if (err) | ||
198 | goto out_free; | ||
199 | |||
200 | return 0; | ||
201 | |||
202 | out_free: | ||
203 | devm_gpio_free(dev, gpio); | ||
204 | out: | ||
205 | dev_warn(dev, "failed to setup card detect wake up\n"); | ||
206 | return err; | ||
207 | } | ||
208 | |||
209 | #else | ||
210 | |||
211 | static int sdhci_acpi_add_own_cd(struct device *dev, int gpio, | ||
212 | struct mmc_host *mmc) | ||
213 | { | ||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | #endif | ||
218 | |||
164 | static int sdhci_acpi_probe(struct platform_device *pdev) | 219 | static int sdhci_acpi_probe(struct platform_device *pdev) |
165 | { | 220 | { |
166 | struct device *dev = &pdev->dev; | 221 | struct device *dev = &pdev->dev; |
@@ -171,7 +226,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev) | |||
171 | struct resource *iomem; | 226 | struct resource *iomem; |
172 | resource_size_t len; | 227 | resource_size_t len; |
173 | const char *hid; | 228 | const char *hid; |
174 | int err; | 229 | int err, gpio; |
175 | 230 | ||
176 | if (acpi_bus_get_device(handle, &device)) | 231 | if (acpi_bus_get_device(handle, &device)) |
177 | return -ENODEV; | 232 | return -ENODEV; |
@@ -196,6 +251,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) | |||
196 | if (IS_ERR(host)) | 251 | if (IS_ERR(host)) |
197 | return PTR_ERR(host); | 252 | return PTR_ERR(host); |
198 | 253 | ||
254 | gpio = acpi_get_gpio_by_index(dev, 0, NULL); | ||
255 | |||
199 | c = sdhci_priv(host); | 256 | c = sdhci_priv(host); |
200 | c->host = host; | 257 | c->host = host; |
201 | c->slot = sdhci_acpi_get_slot(handle, hid); | 258 | c->slot = sdhci_acpi_get_slot(handle, hid); |
@@ -251,6 +308,11 @@ static int sdhci_acpi_probe(struct platform_device *pdev) | |||
251 | if (err) | 308 | if (err) |
252 | goto err_free; | 309 | goto err_free; |
253 | 310 | ||
311 | if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) { | ||
312 | if (sdhci_acpi_add_own_cd(dev, gpio, host->mmc)) | ||
313 | c->use_runtime_pm = false; | ||
314 | } | ||
315 | |||
254 | if (c->use_runtime_pm) { | 316 | if (c->use_runtime_pm) { |
255 | pm_runtime_set_active(dev); | 317 | pm_runtime_set_active(dev); |
256 | pm_suspend_ignore_children(dev, 1); | 318 | pm_suspend_ignore_children(dev, 1); |