ricoh_mmc: port from driver to pci quirk
[linux-2.6-block.git] / drivers / pci / quirks.c
index 456c265b1fe9938eb744f19f1601203aa2a3be11..81d19d5683ace216b2edd8728c0bde78f3fccf31 100644 (file)
 #include <linux/dmi.h>
 #include <linux/pci-aspm.h>
 #include <linux/ioport.h>
+#include <asm/dma.h>   /* isa_dma_bridge_buggy */
 #include "pci.h"
 
-int isa_dma_bridge_buggy;
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-int pci_pci_problems;
-EXPORT_SYMBOL(pci_pci_problems);
-
-#ifdef CONFIG_PCI_QUIRKS
 /*
  * This quirk function disables memory decoding and releases memory resources
  * of the device specified by kernel's boot parameter 'pci=resource_alignment='.
@@ -2538,6 +2533,91 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov);
 
 #endif /* CONFIG_PCI_IOV */
 
+/*
+ * This is a quirk for the Ricoh MMC controller found as a part of
+ * some mulifunction chips.
+
+ * This is very similiar and based on the ricoh_mmc driver written by
+ * Philip Langdale. Thank you for these magic sequences.
+ *
+ * These chips implement the four main memory card controllers (SD, MMC, MS, xD)
+ * and one or both of cardbus or firewire.
+ *
+ * It happens that they implement SD and MMC
+ * support as separate controllers (and PCI functions). The linux SDHCI
+ * driver supports MMC cards but the chip detects MMC cards in hardware
+ * and directs them to the MMC controller - so the SDHCI driver never sees
+ * them.
+ *
+ * To get around this, we must disable the useless MMC controller.
+ * At that point, the SDHCI controller will start seeing them
+ * It seems to be the case that the relevant PCI registers to deactivate the
+ * MMC controller live on PCI function 0, which might be the cardbus controller
+ * or the firewire controller, depending on the particular chip in question
+ *
+ * This has to be done early, because as soon as we disable the MMC controller
+ * other pci functions shift up one level, e.g. function #2 becomes function
+ * #1, and this will confuse the pci core.
+ */
+
+#ifdef CONFIG_MMC_RICOH_MMC
+static void ricoh_mmc_fixup_rl5c476(struct pci_dev *dev)
+{
+       /* disable via cardbus interface */
+       u8 write_enable;
+       u8 write_target;
+       u8 disable;
+
+       /* disable must be done via function #0 */
+       if (PCI_FUNC(dev->devfn))
+               return;
+
+       pci_read_config_byte(dev, 0xB7, &disable);
+       if (disable & 0x02)
+               return;
+
+       pci_read_config_byte(dev, 0x8E, &write_enable);
+       pci_write_config_byte(dev, 0x8E, 0xAA);
+       pci_read_config_byte(dev, 0x8D, &write_target);
+       pci_write_config_byte(dev, 0x8D, 0xB7);
+       pci_write_config_byte(dev, 0xB7, disable | 0x02);
+       pci_write_config_byte(dev, 0x8E, write_enable);
+       pci_write_config_byte(dev, 0x8D, write_target);
+
+       dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via cardbus function)\n");
+       dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476);
+
+static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev)
+{
+       /* disable via firewire interface */
+       u8 write_enable;
+       u8 disable;
+
+       /* disable must be done via function #0 */
+       if (PCI_FUNC(dev->devfn))
+               return;
+
+       pci_read_config_byte(dev, 0xCB, &disable);
+
+       if (disable & 0x02)
+               return;
+
+       pci_read_config_byte(dev, 0xCA, &write_enable);
+       pci_write_config_byte(dev, 0xCA, 0x57);
+       pci_write_config_byte(dev, 0xCB, disable | 0x02);
+       pci_write_config_byte(dev, 0xCA, write_enable);
+
+       dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n");
+       dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n");
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832);
+#endif /*CONFIG_MMC_RICOH_MMC*/
+
+
 static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
                          struct pci_fixup *end)
 {
@@ -2613,6 +2693,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
        }
        pci_do_fixups(dev, start, end);
 }
+EXPORT_SYMBOL(pci_fixup_device);
 
 static int __init pci_apply_final_quirks(void)
 {
@@ -2724,9 +2805,3 @@ int pci_dev_specific_reset(struct pci_dev *dev, int probe)
 
        return -ENOTTY;
 }
-
-#else
-void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {}
-int pci_dev_specific_reset(struct pci_dev *dev, int probe) { return -ENOTTY; }
-#endif
-EXPORT_SYMBOL(pci_fixup_device);