aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMaxim Levitsky <maximlevitsky@gmail.com>2010-08-10 21:01:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:03 -0400
commitccc92c23240cdf952ef7cc39ba563910dcbc9cbe (patch)
treed656aad9e86fff59c1a5cbece4a5ccb019c35011 /drivers/mmc
parent4c2ef25fe0b847d2ae818f74758ddb0be1c27d8e (diff)
mmc: make sdhci work with ricoh mmc controller
The current way of disabling it is not well tested by vendor and has all kinds of bugs that show up on resume from ram/disk. A very good example is a dead SDHCI controller. Old way of disabling is still supported by continuing to use CONFIG_MMC_RICOH_MMC. Based on 'http://list.drzeus.cx/pipermail/sdhci-devel/2007-December/002085.html' Therefore most of the credit for this goes to Andrew de Quincey Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Cc: Andrew de Quincey <adq_dvb@lidskialf.net> Acked-by: Philip Langdale <philipl@overt.org> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-pci.c41
-rw-r--r--drivers/mmc/host/sdhci.c3
-rw-r--r--drivers/mmc/host/sdhci.h4
3 files changed, 47 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 65483fdea45b..e0214316aedb 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -17,6 +17,7 @@
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#include <linux/slab.h>
20#include <linux/device.h>
20 21
21#include <linux/mmc/host.h> 22#include <linux/mmc/host.h>
22 23
@@ -84,7 +85,30 @@ static int ricoh_probe(struct sdhci_pci_chip *chip)
84 if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG || 85 if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
85 chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) 86 chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
86 chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; 87 chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
88 return 0;
89}
90
91static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
92{
93 slot->host->caps =
94 ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT)
95 & SDHCI_TIMEOUT_CLK_MASK) |
96
97 ((0x21 << SDHCI_CLOCK_BASE_SHIFT)
98 & SDHCI_CLOCK_BASE_MASK) |
87 99
100 SDHCI_TIMEOUT_CLK_UNIT |
101 SDHCI_CAN_VDD_330 |
102 SDHCI_CAN_DO_SDMA;
103 return 0;
104}
105
106static int ricoh_mmc_resume(struct sdhci_pci_chip *chip)
107{
108 /* Apply a delay to allow controller to settle */
109 /* Otherwise it becomes confused if card state changed
110 during suspend */
111 msleep(500);
88 return 0; 112 return 0;
89} 113}
90 114
@@ -95,6 +119,15 @@ static const struct sdhci_pci_fixes sdhci_ricoh = {
95 SDHCI_QUIRK_CLOCK_BEFORE_RESET, 119 SDHCI_QUIRK_CLOCK_BEFORE_RESET,
96}; 120};
97 121
122static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
123 .probe_slot = ricoh_mmc_probe_slot,
124 .resume = ricoh_mmc_resume,
125 .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
126 SDHCI_QUIRK_CLOCK_BEFORE_RESET |
127 SDHCI_QUIRK_NO_CARD_NO_RESET |
128 SDHCI_QUIRK_MISSING_CAPS
129};
130
98static const struct sdhci_pci_fixes sdhci_ene_712 = { 131static const struct sdhci_pci_fixes sdhci_ene_712 = {
99 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE | 132 .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
100 SDHCI_QUIRK_BROKEN_DMA, 133 SDHCI_QUIRK_BROKEN_DMA,
@@ -374,6 +407,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
374 }, 407 },
375 408
376 { 409 {
410 .vendor = PCI_VENDOR_ID_RICOH,
411 .device = 0x843,
412 .subvendor = PCI_ANY_ID,
413 .subdevice = PCI_ANY_ID,
414 .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
415 },
416
417 {
377 .vendor = PCI_VENDOR_ID_ENE, 418 .vendor = PCI_VENDOR_ID_ENE,
378 .device = PCI_DEVICE_ID_ENE_CB712_SD, 419 .device = PCI_DEVICE_ID_ENE_CB712_SD,
379 .subvendor = PCI_ANY_ID, 420 .subvendor = PCI_ANY_ID,
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c6d1bd8d4ac4..483b78eee3ac 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1687,7 +1687,8 @@ int sdhci_add_host(struct sdhci_host *host)
1687 host->version); 1687 host->version);
1688 } 1688 }
1689 1689
1690 caps = sdhci_readl(host, SDHCI_CAPABILITIES); 1690 caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
1691 sdhci_readl(host, SDHCI_CAPABILITIES);
1691 1692
1692 if (host->quirks & SDHCI_QUIRK_FORCE_DMA) 1693 if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
1693 host->flags |= SDHCI_USE_SDMA; 1694 host->flags |= SDHCI_USE_SDMA;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index c8468134adc9..b1839a315b86 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -240,6 +240,8 @@ struct sdhci_host {
240#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25) 240#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN (1<<25)
241/* Controller cannot support End Attribute in NOP ADMA descriptor */ 241/* Controller cannot support End Attribute in NOP ADMA descriptor */
242#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26) 242#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC (1<<26)
243/* Controller is missing device caps. Use caps provided by host */
244#define SDHCI_QUIRK_MISSING_CAPS (1<<27)
243 245
244 int irq; /* Device IRQ */ 246 int irq; /* Device IRQ */
245 void __iomem * ioaddr; /* Mapped address */ 247 void __iomem * ioaddr; /* Mapped address */
@@ -292,6 +294,8 @@ struct sdhci_host {
292 294
293 struct timer_list timer; /* Timer for timeouts */ 295 struct timer_list timer; /* Timer for timeouts */
294 296
297 unsigned int caps; /* Alternative capabilities */
298
295 unsigned long private[0] ____cacheline_aligned; 299 unsigned long private[0] ____cacheline_aligned;
296}; 300};
297 301