diff options
| -rw-r--r-- | drivers/mmc/host/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/mmc/host/Makefile | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/ricoh_mmc.c | 262 | ||||
| -rw-r--r-- | drivers/pci/quirks.c | 85 |
4 files changed, 88 insertions, 270 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index ce1d28884e29..6bc3ecb1f247 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
| @@ -69,20 +69,16 @@ config MMC_SDHCI_PCI | |||
| 69 | If unsure, say N. | 69 | If unsure, say N. |
| 70 | 70 | ||
| 71 | config MMC_RICOH_MMC | 71 | config MMC_RICOH_MMC |
| 72 | tristate "Ricoh MMC Controller Disabler (EXPERIMENTAL)" | 72 | bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)" |
| 73 | depends on MMC_SDHCI_PCI | 73 | depends on MMC_SDHCI_PCI |
| 74 | help | 74 | help |
| 75 | This selects the disabler for the Ricoh MMC Controller. This | 75 | This adds a pci quirk to disable Ricoh MMC Controller. This |
| 76 | proprietary controller is unnecessary because the SDHCI driver | 76 | proprietary controller is unnecessary because the SDHCI driver |
| 77 | supports MMC cards on the SD controller, but if it is not | 77 | supports MMC cards on the SD controller, but if it is not |
| 78 | disabled, it will steal the MMC cards away - rendering them | 78 | disabled, it will steal the MMC cards away - rendering them |
| 79 | useless. It is safe to select this driver even if you don't | 79 | useless. It is safe to select this even if you don't |
| 80 | have a Ricoh based card reader. | 80 | have a Ricoh based card reader. |
| 81 | 81 | ||
| 82 | |||
| 83 | To compile this driver as a module, choose M here: | ||
| 84 | the module will be called ricoh_mmc. | ||
| 85 | |||
| 86 | If unsure, say Y. | 82 | If unsure, say Y. |
| 87 | 83 | ||
| 88 | config MMC_SDHCI_OF | 84 | config MMC_SDHCI_OF |
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 3d253dd4240f..f4803977dfce 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile | |||
| @@ -12,7 +12,6 @@ obj-$(CONFIG_MMC_IMX) += imxmmc.o | |||
| 12 | obj-$(CONFIG_MMC_MXC) += mxcmmc.o | 12 | obj-$(CONFIG_MMC_MXC) += mxcmmc.o |
| 13 | obj-$(CONFIG_MMC_SDHCI) += sdhci.o | 13 | obj-$(CONFIG_MMC_SDHCI) += sdhci.o |
| 14 | obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o | 14 | obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o |
| 15 | obj-$(CONFIG_MMC_RICOH_MMC) += ricoh_mmc.o | ||
| 16 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o | 15 | obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o |
| 17 | obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o | 16 | obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o |
| 18 | obj-$(CONFIG_MMC_WBSD) += wbsd.o | 17 | obj-$(CONFIG_MMC_WBSD) += wbsd.o |
diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c deleted file mode 100644 index f62790513322..000000000000 --- a/drivers/mmc/host/ricoh_mmc.c +++ /dev/null | |||
| @@ -1,262 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007 Philip Langdale, All Rights Reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
| 9 | * your option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | /* | ||
| 13 | * This is a conceptually ridiculous driver, but it is required by the way | ||
| 14 | * the Ricoh multi-function chips (R5CXXX) work. These chips implement | ||
| 15 | * the four main memory card controllers (SD, MMC, MS, xD) and one or both | ||
| 16 | * of cardbus or firewire. It happens that they implement SD and MMC | ||
| 17 | * support as separate controllers (and PCI functions). The linux SDHCI | ||
| 18 | * driver supports MMC cards but the chip detects MMC cards in hardware | ||
| 19 | * and directs them to the MMC controller - so the SDHCI driver never sees | ||
| 20 | * them. To get around this, we must disable the useless MMC controller. | ||
| 21 | * At that point, the SDHCI controller will start seeing them. As a bonus, | ||
| 22 | * a detection event occurs immediately, even if the MMC card is already | ||
| 23 | * in the reader. | ||
| 24 | * | ||
| 25 | * It seems to be the case that the relevant PCI registers to deactivate the | ||
| 26 | * MMC controller live on PCI function 0, which might be the cardbus controller | ||
| 27 | * or the firewire controller, depending on the particular chip in question. As | ||
| 28 | * such, it makes what this driver has to do unavoidably ugly. Such is life. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/pci.h> | ||
| 32 | |||
| 33 | #define DRIVER_NAME "ricoh-mmc" | ||
| 34 | |||
| 35 | static const struct pci_device_id pci_ids[] __devinitdata = { | ||
| 36 | { | ||
| 37 | .vendor = PCI_VENDOR_ID_RICOH, | ||
| 38 | .device = PCI_DEVICE_ID_RICOH_R5C843, | ||
| 39 | .subvendor = PCI_ANY_ID, | ||
| 40 | .subdevice = PCI_ANY_ID, | ||
| 41 | }, | ||
| 42 | { /* end: all zeroes */ }, | ||
| 43 | }; | ||
| 44 | |||
| 45 | MODULE_DEVICE_TABLE(pci, pci_ids); | ||
| 46 | |||
| 47 | static int ricoh_mmc_disable(struct pci_dev *fw_dev) | ||
| 48 | { | ||
| 49 | u8 write_enable; | ||
| 50 | u8 write_target; | ||
| 51 | u8 disable; | ||
| 52 | |||
| 53 | if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { | ||
| 54 | /* via RL5C476 */ | ||
| 55 | |||
| 56 | pci_read_config_byte(fw_dev, 0xB7, &disable); | ||
| 57 | if (disable & 0x02) { | ||
| 58 | printk(KERN_INFO DRIVER_NAME | ||
| 59 | ": Controller already disabled. " \ | ||
| 60 | "Nothing to do.\n"); | ||
| 61 | return -ENODEV; | ||
| 62 | } | ||
| 63 | |||
| 64 | pci_read_config_byte(fw_dev, 0x8E, &write_enable); | ||
| 65 | pci_write_config_byte(fw_dev, 0x8E, 0xAA); | ||
| 66 | pci_read_config_byte(fw_dev, 0x8D, &write_target); | ||
| 67 | pci_write_config_byte(fw_dev, 0x8D, 0xB7); | ||
| 68 | pci_write_config_byte(fw_dev, 0xB7, disable | 0x02); | ||
| 69 | pci_write_config_byte(fw_dev, 0x8E, write_enable); | ||
| 70 | pci_write_config_byte(fw_dev, 0x8D, write_target); | ||
| 71 | } else { | ||
| 72 | /* via R5C832 */ | ||
| 73 | |||
| 74 | pci_read_config_byte(fw_dev, 0xCB, &disable); | ||
| 75 | if (disable & 0x02) { | ||
| 76 | printk(KERN_INFO DRIVER_NAME | ||
| 77 | ": Controller already disabled. " \ | ||
| 78 | "Nothing to do.\n"); | ||
| 79 | return -ENODEV; | ||
| 80 | } | ||
| 81 | |||
| 82 | pci_read_config_byte(fw_dev, 0xCA, &write_enable); | ||
| 83 | pci_write_config_byte(fw_dev, 0xCA, 0x57); | ||
| 84 | pci_write_config_byte(fw_dev, 0xCB, disable | 0x02); | ||
| 85 | pci_write_config_byte(fw_dev, 0xCA, write_enable); | ||
| 86 | } | ||
| 87 | |||
| 88 | printk(KERN_INFO DRIVER_NAME | ||
| 89 | ": Controller is now disabled.\n"); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int ricoh_mmc_enable(struct pci_dev *fw_dev) | ||
| 95 | { | ||
| 96 | u8 write_enable; | ||
| 97 | u8 write_target; | ||
| 98 | u8 disable; | ||
| 99 | |||
| 100 | if (fw_dev->device == PCI_DEVICE_ID_RICOH_RL5C476) { | ||
| 101 | /* via RL5C476 */ | ||
| 102 | |||
| 103 | pci_read_config_byte(fw_dev, 0x8E, &write_enable); | ||
| 104 | pci_write_config_byte(fw_dev, 0x8E, 0xAA); | ||
| 105 | pci_read_config_byte(fw_dev, 0x8D, &write_target); | ||
| 106 | pci_write_config_byte(fw_dev, 0x8D, 0xB7); | ||
| 107 | pci_read_config_byte(fw_dev, 0xB7, &disable); | ||
| 108 | pci_write_config_byte(fw_dev, 0xB7, disable & ~0x02); | ||
| 109 | pci_write_config_byte(fw_dev, 0x8E, write_enable); | ||
| 110 | pci_write_config_byte(fw_dev, 0x8D, write_target); | ||
| 111 | } else { | ||
| 112 | /* via R5C832 */ | ||
| 113 | |||
| 114 | pci_read_config_byte(fw_dev, 0xCA, &write_enable); | ||
| 115 | pci_read_config_byte(fw_dev, 0xCB, &disable); | ||
| 116 | pci_write_config_byte(fw_dev, 0xCA, 0x57); | ||
| 117 | pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02); | ||
| 118 | pci_write_config_byte(fw_dev, 0xCA, write_enable); | ||
| 119 | } | ||
| 120 | |||
| 121 | printk(KERN_INFO DRIVER_NAME | ||
| 122 | ": Controller is now re-enabled.\n"); | ||
| 123 | |||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int __devinit ricoh_mmc_probe(struct pci_dev *pdev, | ||
| 128 | const struct pci_device_id *ent) | ||
| 129 | { | ||
| 130 | u8 rev; | ||
| 131 | u8 ctrlfound = 0; | ||
| 132 | |||
| 133 | struct pci_dev *fw_dev = NULL; | ||
| 134 | |||
| 135 | BUG_ON(pdev == NULL); | ||
| 136 | BUG_ON(ent == NULL); | ||
| 137 | |||
| 138 | pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev); | ||
| 139 | |||
| 140 | printk(KERN_INFO DRIVER_NAME | ||
| 141 | ": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n", | ||
| 142 | pci_name(pdev), (int)pdev->vendor, (int)pdev->device, | ||
| 143 | (int)rev); | ||
| 144 | |||
| 145 | while ((fw_dev = | ||
| 146 | pci_get_device(PCI_VENDOR_ID_RICOH, | ||
| 147 | PCI_DEVICE_ID_RICOH_RL5C476, fw_dev))) { | ||
| 148 | if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && | ||
| 149 | PCI_FUNC(fw_dev->devfn) == 0 && | ||
| 150 | pdev->bus == fw_dev->bus) { | ||
| 151 | if (ricoh_mmc_disable(fw_dev) != 0) | ||
| 152 | return -ENODEV; | ||
| 153 | |||
| 154 | pci_set_drvdata(pdev, fw_dev); | ||
| 155 | |||
| 156 | ++ctrlfound; | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | fw_dev = NULL; | ||
| 162 | |||
| 163 | while (!ctrlfound && | ||
| 164 | (fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, | ||
| 165 | PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) { | ||
| 166 | if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) && | ||
| 167 | PCI_FUNC(fw_dev->devfn) == 0 && | ||
| 168 | pdev->bus == fw_dev->bus) { | ||
| 169 | if (ricoh_mmc_disable(fw_dev) != 0) | ||
| 170 | return -ENODEV; | ||
| 171 | |||
| 172 | pci_set_drvdata(pdev, fw_dev); | ||
| 173 | |||
| 174 | ++ctrlfound; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | if (!ctrlfound) { | ||
| 179 | printk(KERN_WARNING DRIVER_NAME | ||
| 180 | ": Main Ricoh function not found. Cannot disable controller.\n"); | ||
| 181 | return -ENODEV; | ||
| 182 | } | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static void __devexit ricoh_mmc_remove(struct pci_dev *pdev) | ||
| 188 | { | ||
| 189 | struct pci_dev *fw_dev = NULL; | ||
| 190 | |||
| 191 | fw_dev = pci_get_drvdata(pdev); | ||
| 192 | BUG_ON(fw_dev == NULL); | ||
| 193 | |||
| 194 | ricoh_mmc_enable(fw_dev); | ||
| 195 | |||
| 196 | pci_set_drvdata(pdev, NULL); | ||
| 197 | } | ||
| 198 | |||
| 199 | static int ricoh_mmc_suspend_late(struct pci_dev *pdev, pm_message_t state) | ||
| 200 | { | ||
| 201 | struct pci_dev *fw_dev = NULL; | ||
| 202 | |||
| 203 | fw_dev = pci_get_drvdata(pdev); | ||
| 204 | BUG_ON(fw_dev == NULL); | ||
| 205 | |||
| 206 | printk(KERN_INFO DRIVER_NAME ": Suspending.\n"); | ||
| 207 | |||
| 208 | ricoh_mmc_enable(fw_dev); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int ricoh_mmc_resume_early(struct pci_dev *pdev) | ||
| 214 | { | ||
| 215 | struct pci_dev *fw_dev = NULL; | ||
| 216 | |||
| 217 | fw_dev = pci_get_drvdata(pdev); | ||
| 218 | BUG_ON(fw_dev == NULL); | ||
| 219 | |||
| 220 | printk(KERN_INFO DRIVER_NAME ": Resuming.\n"); | ||
| 221 | |||
| 222 | ricoh_mmc_disable(fw_dev); | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
| 226 | |||
| 227 | static struct pci_driver ricoh_mmc_driver = { | ||
| 228 | .name = DRIVER_NAME, | ||
| 229 | .id_table = pci_ids, | ||
| 230 | .probe = ricoh_mmc_probe, | ||
| 231 | .remove = __devexit_p(ricoh_mmc_remove), | ||
| 232 | .suspend_late = ricoh_mmc_suspend_late, | ||
| 233 | .resume_early = ricoh_mmc_resume_early, | ||
| 234 | }; | ||
| 235 | |||
| 236 | /*****************************************************************************\ | ||
| 237 | * * | ||
| 238 | * Driver init/exit * | ||
| 239 | * * | ||
| 240 | \*****************************************************************************/ | ||
| 241 | |||
| 242 | static int __init ricoh_mmc_drv_init(void) | ||
| 243 | { | ||
| 244 | printk(KERN_INFO DRIVER_NAME | ||
| 245 | ": Ricoh MMC Controller disabling driver\n"); | ||
| 246 | printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n"); | ||
| 247 | |||
| 248 | return pci_register_driver(&ricoh_mmc_driver); | ||
| 249 | } | ||
| 250 | |||
| 251 | static void __exit ricoh_mmc_drv_exit(void) | ||
| 252 | { | ||
| 253 | pci_unregister_driver(&ricoh_mmc_driver); | ||
| 254 | } | ||
| 255 | |||
| 256 | module_init(ricoh_mmc_drv_init); | ||
| 257 | module_exit(ricoh_mmc_drv_exit); | ||
| 258 | |||
| 259 | MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>"); | ||
| 260 | MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver"); | ||
| 261 | MODULE_LICENSE("GPL"); | ||
| 262 | |||
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 039e87b71442..81d19d5683ac 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
| @@ -2533,6 +2533,91 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov); | |||
| 2533 | 2533 | ||
| 2534 | #endif /* CONFIG_PCI_IOV */ | 2534 | #endif /* CONFIG_PCI_IOV */ |
| 2535 | 2535 | ||
| 2536 | /* | ||
| 2537 | * This is a quirk for the Ricoh MMC controller found as a part of | ||
| 2538 | * some mulifunction chips. | ||
| 2539 | |||
| 2540 | * This is very similiar and based on the ricoh_mmc driver written by | ||
| 2541 | * Philip Langdale. Thank you for these magic sequences. | ||
| 2542 | * | ||
| 2543 | * These chips implement the four main memory card controllers (SD, MMC, MS, xD) | ||
| 2544 | * and one or both of cardbus or firewire. | ||
| 2545 | * | ||
| 2546 | * It happens that they implement SD and MMC | ||
| 2547 | * support as separate controllers (and PCI functions). The linux SDHCI | ||
| 2548 | * driver supports MMC cards but the chip detects MMC cards in hardware | ||
| 2549 | * and directs them to the MMC controller - so the SDHCI driver never sees | ||
| 2550 | * them. | ||
| 2551 | * | ||
| 2552 | * To get around this, we must disable the useless MMC controller. | ||
| 2553 | * At that point, the SDHCI controller will start seeing them | ||
| 2554 | * It seems to be the case that the relevant PCI registers to deactivate the | ||
| 2555 | * MMC controller live on PCI function 0, which might be the cardbus controller | ||
| 2556 | * or the firewire controller, depending on the particular chip in question | ||
| 2557 | * | ||
| 2558 | * This has to be done early, because as soon as we disable the MMC controller | ||
| 2559 | * other pci functions shift up one level, e.g. function #2 becomes function | ||
| 2560 | * #1, and this will confuse the pci core. | ||
| 2561 | */ | ||
| 2562 | |||
| 2563 | #ifdef CONFIG_MMC_RICOH_MMC | ||
| 2564 | static void ricoh_mmc_fixup_rl5c476(struct pci_dev *dev) | ||
| 2565 | { | ||
| 2566 | /* disable via cardbus interface */ | ||
| 2567 | u8 write_enable; | ||
| 2568 | u8 write_target; | ||
| 2569 | u8 disable; | ||
| 2570 | |||
| 2571 | /* disable must be done via function #0 */ | ||
| 2572 | if (PCI_FUNC(dev->devfn)) | ||
| 2573 | return; | ||
| 2574 | |||
| 2575 | pci_read_config_byte(dev, 0xB7, &disable); | ||
| 2576 | if (disable & 0x02) | ||
| 2577 | return; | ||
| 2578 | |||
| 2579 | pci_read_config_byte(dev, 0x8E, &write_enable); | ||
| 2580 | pci_write_config_byte(dev, 0x8E, 0xAA); | ||
| 2581 | pci_read_config_byte(dev, 0x8D, &write_target); | ||
| 2582 | pci_write_config_byte(dev, 0x8D, 0xB7); | ||
| 2583 | pci_write_config_byte(dev, 0xB7, disable | 0x02); | ||
| 2584 | pci_write_config_byte(dev, 0x8E, write_enable); | ||
| 2585 | pci_write_config_byte(dev, 0x8D, write_target); | ||
| 2586 | |||
| 2587 | dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via cardbus function)\n"); | ||
| 2588 | dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); | ||
| 2589 | } | ||
| 2590 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476); | ||
| 2591 | DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476); | ||
| 2592 | |||
| 2593 | static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) | ||
| 2594 | { | ||
| 2595 | /* disable via firewire interface */ | ||
| 2596 | u8 write_enable; | ||
| 2597 | u8 disable; | ||
| 2598 | |||
| 2599 | /* disable must be done via function #0 */ | ||
| 2600 | if (PCI_FUNC(dev->devfn)) | ||
| 2601 | return; | ||
| 2602 | |||
| 2603 | pci_read_config_byte(dev, 0xCB, &disable); | ||
| 2604 | |||
| 2605 | if (disable & 0x02) | ||
| 2606 | return; | ||
| 2607 | |||
| 2608 | pci_read_config_byte(dev, 0xCA, &write_enable); | ||
| 2609 | pci_write_config_byte(dev, 0xCA, 0x57); | ||
| 2610 | pci_write_config_byte(dev, 0xCB, disable | 0x02); | ||
| 2611 | pci_write_config_byte(dev, 0xCA, write_enable); | ||
| 2612 | |||
| 2613 | dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n"); | ||
| 2614 | dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); | ||
| 2615 | } | ||
| 2616 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); | ||
| 2617 | DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); | ||
| 2618 | #endif /*CONFIG_MMC_RICOH_MMC*/ | ||
| 2619 | |||
| 2620 | |||
| 2536 | static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, | 2621 | static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, |
| 2537 | struct pci_fixup *end) | 2622 | struct pci_fixup *end) |
| 2538 | { | 2623 | { |
