diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index e0356644d1aa..6701af629c30 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/highmem.h> | 16 | #include <linux/highmem.h> |
17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/slab.h> | ||
19 | 20 | ||
20 | #include <linux/mmc/host.h> | 21 | #include <linux/mmc/host.h> |
21 | 22 | ||
@@ -80,9 +81,6 @@ struct sdhci_pci_chip { | |||
80 | 81 | ||
81 | static int ricoh_probe(struct sdhci_pci_chip *chip) | 82 | static int ricoh_probe(struct sdhci_pci_chip *chip) |
82 | { | 83 | { |
83 | if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) | ||
84 | chip->quirks |= SDHCI_QUIRK_CLOCK_BEFORE_RESET; | ||
85 | |||
86 | if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || | 84 | if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || |
87 | chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) | 85 | chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) |
88 | chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; | 86 | chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; |
@@ -92,7 +90,9 @@ static int ricoh_probe(struct sdhci_pci_chip *chip) | |||
92 | 90 | ||
93 | static const struct sdhci_pci_fixes sdhci_ricoh = { | 91 | static const struct sdhci_pci_fixes sdhci_ricoh = { |
94 | .probe = ricoh_probe, | 92 | .probe = ricoh_probe, |
95 | .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR, | 93 | .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | |
94 | SDHCI_QUIRK_FORCE_DMA | | ||
95 | SDHCI_QUIRK_CLOCK_BEFORE_RESET, | ||
96 | }; | 96 | }; |
97 | 97 | ||
98 | static const struct sdhci_pci_fixes sdhci_ene_712 = { | 98 | static const struct sdhci_pci_fixes sdhci_ene_712 = { |
@@ -285,6 +285,73 @@ static const struct sdhci_pci_fixes sdhci_jmicron = { | |||
285 | .resume = jmicron_resume, | 285 | .resume = jmicron_resume, |
286 | }; | 286 | }; |
287 | 287 | ||
288 | /* SysKonnect CardBus2SDIO extra registers */ | ||
289 | #define SYSKT_CTRL 0x200 | ||
290 | #define SYSKT_RDFIFO_STAT 0x204 | ||
291 | #define SYSKT_WRFIFO_STAT 0x208 | ||
292 | #define SYSKT_POWER_DATA 0x20c | ||
293 | #define SYSKT_POWER_330 0xef | ||
294 | #define SYSKT_POWER_300 0xf8 | ||
295 | #define SYSKT_POWER_184 0xcc | ||
296 | #define SYSKT_POWER_CMD 0x20d | ||
297 | #define SYSKT_POWER_START (1 << 7) | ||
298 | #define SYSKT_POWER_STATUS 0x20e | ||
299 | #define SYSKT_POWER_STATUS_OK (1 << 0) | ||
300 | #define SYSKT_BOARD_REV 0x210 | ||
301 | #define SYSKT_CHIP_REV 0x211 | ||
302 | #define SYSKT_CONF_DATA 0x212 | ||
303 | #define SYSKT_CONF_DATA_1V8 (1 << 2) | ||
304 | #define SYSKT_CONF_DATA_2V5 (1 << 1) | ||
305 | #define SYSKT_CONF_DATA_3V3 (1 << 0) | ||
306 | |||
307 | static int syskt_probe(struct sdhci_pci_chip *chip) | ||
308 | { | ||
309 | if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) { | ||
310 | chip->pdev->class &= ~0x0000FF; | ||
311 | chip->pdev->class |= PCI_SDHCI_IFDMA; | ||
312 | } | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int syskt_probe_slot(struct sdhci_pci_slot *slot) | ||
317 | { | ||
318 | int tm, ps; | ||
319 | |||
320 | u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV); | ||
321 | u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV); | ||
322 | dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, " | ||
323 | "board rev %d.%d, chip rev %d.%d\n", | ||
324 | board_rev >> 4, board_rev & 0xf, | ||
325 | chip_rev >> 4, chip_rev & 0xf); | ||
326 | if (chip_rev >= 0x20) | ||
327 | slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA; | ||
328 | |||
329 | writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA); | ||
330 | writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD); | ||
331 | udelay(50); | ||
332 | tm = 10; /* Wait max 1 ms */ | ||
333 | do { | ||
334 | ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS); | ||
335 | if (ps & SYSKT_POWER_STATUS_OK) | ||
336 | break; | ||
337 | udelay(100); | ||
338 | } while (--tm); | ||
339 | if (!tm) { | ||
340 | dev_err(&slot->chip->pdev->dev, | ||
341 | "power regulator never stabilized"); | ||
342 | writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD); | ||
343 | return -ENODEV; | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static const struct sdhci_pci_fixes sdhci_syskt = { | ||
350 | .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER, | ||
351 | .probe = syskt_probe, | ||
352 | .probe_slot = syskt_probe_slot, | ||
353 | }; | ||
354 | |||
288 | static int via_probe(struct sdhci_pci_chip *chip) | 355 | static int via_probe(struct sdhci_pci_chip *chip) |
289 | { | 356 | { |
290 | if (chip->pdev->revision == 0x10) | 357 | if (chip->pdev->revision == 0x10) |
@@ -363,6 +430,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { | |||
363 | }, | 430 | }, |
364 | 431 | ||
365 | { | 432 | { |
433 | .vendor = PCI_VENDOR_ID_SYSKONNECT, | ||
434 | .device = 0x8000, | ||
435 | .subvendor = PCI_ANY_ID, | ||
436 | .subdevice = PCI_ANY_ID, | ||
437 | .driver_data = (kernel_ulong_t)&sdhci_syskt, | ||
438 | }, | ||
439 | |||
440 | { | ||
366 | .vendor = PCI_VENDOR_ID_VIA, | 441 | .vendor = PCI_VENDOR_ID_VIA, |
367 | .device = 0x95d0, | 442 | .device = 0x95d0, |
368 | .subvendor = PCI_ANY_ID, | 443 | .subvendor = PCI_ANY_ID, |
@@ -426,6 +501,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
426 | { | 501 | { |
427 | struct sdhci_pci_chip *chip; | 502 | struct sdhci_pci_chip *chip; |
428 | struct sdhci_pci_slot *slot; | 503 | struct sdhci_pci_slot *slot; |
504 | mmc_pm_flag_t pm_flags = 0; | ||
429 | int i, ret; | 505 | int i, ret; |
430 | 506 | ||
431 | chip = pci_get_drvdata(pdev); | 507 | chip = pci_get_drvdata(pdev); |
@@ -444,6 +520,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
444 | sdhci_resume_host(chip->slots[i]->host); | 520 | sdhci_resume_host(chip->slots[i]->host); |
445 | return ret; | 521 | return ret; |
446 | } | 522 | } |
523 | |||
524 | pm_flags |= slot->host->mmc->pm_flags; | ||
447 | } | 525 | } |
448 | 526 | ||
449 | if (chip->fixes && chip->fixes->suspend) { | 527 | if (chip->fixes && chip->fixes->suspend) { |
@@ -456,9 +534,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
456 | } | 534 | } |
457 | 535 | ||
458 | pci_save_state(pdev); | 536 | pci_save_state(pdev); |
459 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | 537 | if (pm_flags & MMC_PM_KEEP_POWER) { |
460 | pci_disable_device(pdev); | 538 | if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) |
461 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 539 | pci_enable_wake(pdev, PCI_D3hot, 1); |
540 | pci_set_power_state(pdev, PCI_D3hot); | ||
541 | } else { | ||
542 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | ||
543 | pci_disable_device(pdev); | ||
544 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
545 | } | ||
462 | 546 | ||
463 | return 0; | 547 | return 0; |
464 | } | 548 | } |
@@ -578,6 +662,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( | |||
578 | goto unmap; | 662 | goto unmap; |
579 | } | 663 | } |
580 | 664 | ||
665 | host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; | ||
666 | |||
581 | ret = sdhci_add_host(host); | 667 | ret = sdhci_add_host(host); |
582 | if (ret) | 668 | if (ret) |
583 | goto remove; | 669 | goto remove; |