diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index dead61754ad76ef23ed532fbc503fe1d334491a9..f9cbcb891e992334c2837d75d8436ddf46857749 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -26,18 +26,31 @@ config MMC_PXA
 
 config MMC_SDHCI
 	tristate "Secure Digital Host Controller Interface support"
-	depends on PCI
+	depends on HAS_DMA
 	help
-	  This select the generic Secure Digital Host Controller Interface.
+	  This selects the generic Secure Digital Host Controller Interface.
 	  It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
 	  and Toshiba(R). Most controllers found in laptops are of this type.
+
+	  If you have a controller with this interface, say Y or M here. You
+	  also need to enable an appropriate bus interface.
+
+	  If unsure, say N.
+
+config MMC_SDHCI_PCI
+	tristate "SDHCI support on PCI bus"
+	depends on MMC_SDHCI && PCI
+	help
+	  This selects the PCI Secure Digital Host Controller Interface.
+	  Most controllers found today are PCI devices.
+
 	  If you have a controller with this interface, say Y or M here.
 
 	  If unsure, say N.
 
 config MMC_RICOH_MMC
 	tristate "Ricoh MMC Controller Disabler  (EXPERIMENTAL)"
-	depends on PCI && EXPERIMENTAL && MMC_SDHCI
+	depends on MMC_SDHCI_PCI
 	help
 	  This selects the disabler for the Ricoh MMC Controller. This
 	  proprietary controller is unnecessary because the SDHCI driver
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 3877c87e6da26e699a730959104dc61ce5992290..3027250b8555c400de880aac32b6b9f3008974e4 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
 obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
+obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o
 obj-$(CONFIG_MMC_RICOH_MMC)	+= ricoh_mmc.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a3dd6cc7bf7deac77d203a41164f49ac062b772
--- /dev/null
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -0,0 +1,486 @@
+/*  linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus interface
+ *
+ *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * Thanks to the following companies for their support:
+ *
+ *     - JMicron (hardware and technical support)
+ */
+
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/mmc/host.h>
+
+#include <asm/scatterlist.h>
+#include <asm/io.h>
+
+#include "sdhci.h"
+
+/*
+ * PCI registers
+ */
+
+#define PCI_SDHCI_IFPIO			0x00
+#define PCI_SDHCI_IFDMA			0x01
+#define PCI_SDHCI_IFVENDOR		0x02
+
+#define PCI_SLOT_INFO			0x40	/* 8 bits */
+#define  PCI_SLOT_INFO_SLOTS(x)		((x >> 4) & 7)
+#define  PCI_SLOT_INFO_FIRST_BAR_MASK	0x07
+
+#define MAX_SLOTS			8
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_VENDOR_ID_IBM,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+				  SDHCI_QUIRK_FORCE_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_VENDOR_ID_SAMSUNG,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
+				  SDHCI_QUIRK_NO_CARD_NO_RESET,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C822,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_TI,
+		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB714_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_ENE,
+		.device		= PCI_DEVICE_ID_ENE_CB714_SD_2,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor         = PCI_VENDOR_ID_MARVELL,
+		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+				  SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
+	},
+
+	{
+		.vendor		= PCI_VENDOR_ID_JMICRON,
+		.device		= PCI_DEVICE_ID_JMICRON_JMB38X_SD,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= SDHCI_QUIRK_32BIT_DMA_ADDR |
+				  SDHCI_QUIRK_32BIT_DMA_SIZE |
+				  SDHCI_QUIRK_RESET_AFTER_REQUEST,
+	},
+
+	{	/* Generic SD host controller */
+		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+	},
+
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+struct sdhci_pci_chip;
+
+struct sdhci_pci_slot {
+	struct sdhci_pci_chip	*chip;
+	struct sdhci_host	*host;
+
+	int			pci_bar;
+};
+
+struct sdhci_pci_chip {
+	struct pci_dev		*pdev;
+	unsigned int		 quirks;
+
+	int			num_slots;	/* Slots on controller */
+	struct sdhci_pci_slot	*slots[MAX_SLOTS]; /* Pointers to host slots */
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * SDHCI core callbacks                                                      *
+ *                                                                           *
+\*****************************************************************************/
+
+static int sdhci_pci_enable_dma(struct sdhci_host *host)
+{
+	struct sdhci_pci_slot *slot;
+	struct pci_dev *pdev;
+	int ret;
+
+	slot = sdhci_priv(host);
+	pdev = slot->chip->pdev;
+
+	if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
+		((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
+		(host->flags & SDHCI_USE_DMA)) {
+		dev_warn(&pdev->dev, "Will use DMA mode even though HW "
+			"doesn't fully claim to support it.\n");
+	}
+
+	ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (ret)
+		return ret;
+
+	pci_set_master(pdev);
+
+	return 0;
+}
+
+static struct sdhci_ops sdhci_pci_ops = {
+	.enable_dma	= sdhci_pci_enable_dma,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Suspend/resume                                                            *
+ *                                                                           *
+\*****************************************************************************/
+
+#ifdef CONFIG_PM
+
+static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+{
+	struct sdhci_pci_chip *chip;
+	struct sdhci_pci_slot *slot;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	for (i = 0;i < chip->num_slots;i++) {
+		slot = chip->slots[i];
+		if (!slot)
+			continue;
+
+		ret = sdhci_suspend_host(slot->host, state);
+
+		if (ret) {
+			for (i--;i >= 0;i--)
+				sdhci_resume_host(chip->slots[i]->host);
+			return ret;
+		}
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int sdhci_pci_resume (struct pci_dev *pdev)
+{
+	struct sdhci_pci_chip *chip;
+	struct sdhci_pci_slot *slot;
+	int i, ret;
+
+	chip = pci_get_drvdata(pdev);
+	if (!chip)
+		return 0;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	for (i = 0;i < chip->num_slots;i++) {
+		slot = chip->slots[i];
+		if (!slot)
+			continue;
+
+		ret = sdhci_resume_host(slot->host);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define sdhci_pci_suspend NULL
+#define sdhci_pci_resume NULL
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
+	struct pci_dev *pdev, struct sdhci_pci_chip *chip, int bar)
+{
+	struct sdhci_pci_slot *slot;
+	struct sdhci_host *host;
+
+	resource_size_t addr;
+
+	int ret;
+
+	if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
+		return ERR_PTR(-ENODEV);
+	}
+
+	if (pci_resource_len(pdev, bar) != 0x100) {
+		dev_err(&pdev->dev, "Invalid iomem size. You may "
+			"experience problems.\n");
+	}
+
+	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+		dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+		dev_err(&pdev->dev, "Unknown interface. Aborting.\n");
+		return ERR_PTR(-ENODEV);
+	}
+
+	host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
+	if (IS_ERR(host)) {
+		ret = PTR_ERR(host);
+		goto unmap;
+	}
+
+	slot = sdhci_priv(host);
+
+	slot->chip = chip;
+	slot->host = host;
+	slot->pci_bar = bar;
+
+	host->hw_name = "PCI";
+	host->ops = &sdhci_pci_ops;
+	host->quirks = chip->quirks;
+
+	host->irq = pdev->irq;
+
+	ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
+	if (ret) {
+		dev_err(&pdev->dev, "cannot request region\n");
+		return ERR_PTR(ret);
+	}
+
+	addr = pci_resource_start(pdev, bar);
+	host->ioaddr = ioremap_nocache(addr, pci_resource_len(pdev, bar));
+	if (!host->ioaddr) {
+		dev_err(&pdev->dev, "failed to remap registers\n");
+		goto release;
+	}
+
+	ret = sdhci_add_host(host);
+	if (ret)
+		goto unmap;
+
+	return slot;
+
+unmap:
+	iounmap(host->ioaddr);
+
+release:
+	pci_release_region(pdev, bar);
+	sdhci_free_host(host);
+
+	return ERR_PTR(ret);
+}
+
+static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
+{
+	sdhci_remove_host(slot->host);
+	pci_release_region(slot->chip->pdev, slot->pci_bar);
+	sdhci_free_host(slot->host);
+}
+
+static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct sdhci_pci_chip *chip;
+	struct sdhci_pci_slot *slot;
+
+	u8 slots, rev, first_bar;
+	int ret, i;
+
+	BUG_ON(pdev == NULL);
+	BUG_ON(ent == NULL);
+
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+	dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
+		 (int)pdev->vendor, (int)pdev->device, (int)rev);
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
+	if (ret)
+		return ret;
+
+	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
+	dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
+	if (slots == 0)
+		return -ENODEV;
+
+	BUG_ON(slots > MAX_SLOTS);
+
+	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
+	if (ret)
+		return ret;
+
+	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+
+	if (first_bar > 5) {
+		dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
+		return -ENODEV;
+	}
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+
+	chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
+	if (!chip) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	chip->pdev = pdev;
+	chip->quirks = ent->driver_data;
+	chip->num_slots = slots;
+
+	pci_set_drvdata(pdev, chip);
+
+	for (i = 0;i < slots;i++) {
+		slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
+		if (IS_ERR(slot)) {
+			for (i--;i >= 0;i--)
+				sdhci_pci_remove_slot(chip->slots[i]);
+			ret = PTR_ERR(slot);
+			goto free;
+		}
+
+		chip->slots[i] = slot;
+	}
+
+	return 0;
+
+free:
+	pci_set_drvdata(pdev, NULL);
+	kfree(chip);
+
+err:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
+{
+	int i;
+	struct sdhci_pci_chip *chip;
+
+	chip = pci_get_drvdata(pdev);
+
+	if (chip) {
+		for (i = 0;i < chip->num_slots; i++)
+			sdhci_pci_remove_slot(chip->slots[i]);
+
+		pci_set_drvdata(pdev, NULL);
+		kfree(chip);
+	}
+
+	pci_disable_device(pdev);
+}
+
+static struct pci_driver sdhci_driver = {
+	.name = 	"sdhci-pci",
+	.id_table =	pci_ids,
+	.probe = 	sdhci_pci_probe,
+	.remove =	__devexit_p(sdhci_pci_remove),
+	.suspend =	sdhci_pci_suspend,
+	.resume	=	sdhci_pci_resume,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_drv_init(void)
+{
+	return pci_register_driver(&sdhci_driver);
+}
+
+static void __exit sdhci_drv_exit(void)
+{
+	pci_unregister_driver(&sdhci_driver);
+}
+
+module_init(sdhci_drv_init);
+module_exit(sdhci_drv_exit);
+
+MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 9b06c6042d971aa1f0264a74eda0924f1cb0de85..8ce01d434ea8ce2439c57556adf68ab019c8e550 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -15,7 +15,7 @@
 
 #include <linux/delay.h>
 #include <linux/highmem.h>
-#include <linux/pci.h>
+#include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <linux/scatterlist.h>
 
@@ -32,135 +32,6 @@
 
 static unsigned int debug_quirks = 0;
 
-/*
- * Different quirks to handle when the hardware deviates from a strict
- * interpretation of the SDHCI specification.
- */
-
-/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
-/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA				(1<<1)
-/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
-/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
-/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
-/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
-/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<6)
-/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
-/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
-/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
-/* Controller has an off-by-one issue with timeout value */
-#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL		(1<<10)
-
-static const struct pci_device_id pci_ids[] __devinitdata = {
-	{
-		.vendor		= PCI_VENDOR_ID_RICOH,
-		.device		= PCI_DEVICE_ID_RICOH_R5C822,
-		.subvendor	= PCI_VENDOR_ID_IBM,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_CLOCK_BEFORE_RESET |
-				  SDHCI_QUIRK_FORCE_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_RICOH,
-		.device		= PCI_DEVICE_ID_RICOH_R5C822,
-		.subvendor	= PCI_VENDOR_ID_SAMSUNG,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
-				  SDHCI_QUIRK_NO_CARD_NO_RESET,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_RICOH,
-		.device		= PCI_DEVICE_ID_RICOH_R5C822,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_TI,
-		.device		= PCI_DEVICE_ID_TI_XX21_XX11_SD,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_ENE,
-		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_BROKEN_DMA,
-	},
-
-	{
-		.vendor		= PCI_VENDOR_ID_ENE,
-		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
-		.subvendor	= PCI_ANY_ID,
-		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_BROKEN_DMA,
-	},
-
-	{
-		.vendor         = PCI_VENDOR_ID_ENE,
-		.device         = PCI_DEVICE_ID_ENE_CB714_SD,
-		.subvendor      = PCI_ANY_ID,
-		.subdevice      = PCI_ANY_ID,
-		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
-				  SDHCI_QUIRK_BROKEN_DMA,
-	},
-
-	{
-		.vendor         = PCI_VENDOR_ID_ENE,
-		.device         = PCI_DEVICE_ID_ENE_CB714_SD_2,
-		.subvendor      = PCI_ANY_ID,
-		.subdevice      = PCI_ANY_ID,
-		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
-				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
-				  SDHCI_QUIRK_BROKEN_DMA,
-	},
-
-	{
-		.vendor         = PCI_VENDOR_ID_MARVELL,
-		.device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
-		.subvendor      = PCI_ANY_ID,
-		.subdevice      = PCI_ANY_ID,
-		.driver_data    = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
-				  SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
-	},
-
-	{
-		.vendor         = PCI_VENDOR_ID_JMICRON,
-		.device         = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
-		.subvendor      = PCI_ANY_ID,
-		.subdevice      = PCI_ANY_ID,
-		.driver_data    = SDHCI_QUIRK_32BIT_DMA_ADDR |
-				  SDHCI_QUIRK_32BIT_DMA_SIZE |
-				  SDHCI_QUIRK_RESET_AFTER_REQUEST,
-	},
-
-	{	/* Generic SD host controller */
-		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
-	},
-
-	{ /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
 static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
 static void sdhci_finish_data(struct sdhci_host *);
 
@@ -215,7 +86,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
 	unsigned long timeout;
 
-	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+	if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
 		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
 			SDHCI_CARD_PRESENT))
 			return;
@@ -488,7 +359,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 	 * Compensate for an off-by-one error in the CaFe hardware; otherwise,
 	 * a too-small count gives us interrupt timeouts.
 	 */
-	if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
+	if ((host->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
 		count++;
 
 	if (count >= 0xF) {
@@ -503,7 +374,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 		host->flags |= SDHCI_REQ_USE_DMA;
 
 	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
-		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
+		(host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
 		((data->blksz * data->blocks) & 0x3))) {
 		DBG("Reverting to PIO because of transfer size (%d)\n",
 			data->blksz * data->blocks);
@@ -515,7 +386,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 	 * translation to device address space.
 	 */
 	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
-		(host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+		(host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
 		(data->sg->offset & 0x3))) {
 		DBG("Reverting to PIO because of bad alignment\n");
 		host->flags &= ~SDHCI_REQ_USE_DMA;
@@ -524,11 +395,13 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 	if (host->flags & SDHCI_REQ_USE_DMA) {
 		int count;
 
-		count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len,
-			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
-		BUG_ON(count != 1);
+		count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+				(data->flags & MMC_DATA_READ) ?
+					DMA_FROM_DEVICE : DMA_TO_DEVICE);
+		WARN_ON(count != 1);
 
-		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);
+		writel(sg_dma_address(data->sg),
+			host->ioaddr + SDHCI_DMA_ADDRESS);
 	} else {
 		host->cur_sg = data->sg;
 		host->num_sg = data->sg_len;
@@ -574,8 +447,9 @@ static void sdhci_finish_data(struct sdhci_host *host)
 	host->data = NULL;
 
 	if (host->flags & SDHCI_REQ_USE_DMA) {
-		pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
-			(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
+		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+			(data->flags & MMC_DATA_READ) ?
+				DMA_FROM_DEVICE : DMA_TO_DEVICE);
 	}
 
 	/*
@@ -770,7 +644,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	 * Spec says that we should clear the power reg before setting
 	 * a new value. Some controllers don't seem to like this though.
 	 */
-	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+	if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 
 	pwr = SDHCI_POWER_ON;
@@ -795,7 +669,7 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	 * At least the CaFe chip gets confused if we set the voltage
 	 * and set turn on power at the same time, so set the voltage first.
 	 */
-	if ((host->chip->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
+	if ((host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER))
 		writeb(pwr & ~SDHCI_POWER_ON,
 				host->ioaddr + SDHCI_POWER_CONTROL);
 
@@ -883,7 +757,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	 * signalling timeout and CRC errors even on CMD0. Resetting
 	 * it on each ios seems to solve the problem.
 	 */
-	if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+	if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
 		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
 	mmiowb();
@@ -994,10 +868,10 @@ static void sdhci_tasklet_finish(unsigned long param)
 	if (mrq->cmd->error ||
 		(mrq->data && (mrq->data->error ||
 		(mrq->data->stop && mrq->data->stop->error))) ||
-		(host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
+		(host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
 
 		/* Some controllers need this kick or reset won't work here */
-		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+		if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
 			unsigned int clock;
 
 			/* This is to force an update */
@@ -1229,165 +1103,90 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
 #ifdef CONFIG_PM
 
-static int sdhci_suspend (struct pci_dev *pdev, pm_message_t state)
+int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
 {
-	struct sdhci_chip *chip;
-	int i, ret;
-
-	chip = pci_get_drvdata(pdev);
-	if (!chip)
-		return 0;
-
-	DBG("Suspending...\n");
-
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		ret = mmc_suspend_host(chip->hosts[i]->mmc, state);
-		if (ret) {
-			for (i--;i >= 0;i--)
-				mmc_resume_host(chip->hosts[i]->mmc);
-			return ret;
-		}
-	}
-
-	pci_save_state(pdev);
-	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+	int ret;
 
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		free_irq(chip->hosts[i]->irq, chip->hosts[i]);
-	}
+	ret = mmc_suspend_host(host->mmc, state);
+	if (ret)
+		return ret;
 
-	pci_disable_device(pdev);
-	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	free_irq(host->irq, host);
 
 	return 0;
 }
 
-static int sdhci_resume (struct pci_dev *pdev)
-{
-	struct sdhci_chip *chip;
-	int i, ret;
+EXPORT_SYMBOL_GPL(sdhci_suspend_host);
 
-	chip = pci_get_drvdata(pdev);
-	if (!chip)
-		return 0;
+int sdhci_resume_host(struct sdhci_host *host)
+{
+	int ret;
 
-	DBG("Resuming...\n");
+	if (host->flags & SDHCI_USE_DMA) {
+		if (host->ops->enable_dma)
+			host->ops->enable_dma(host);
+	}
 
-	pci_set_power_state(pdev, PCI_D0);
-	pci_restore_state(pdev);
-	ret = pci_enable_device(pdev);
+	ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
+			  mmc_hostname(host->mmc), host);
 	if (ret)
 		return ret;
 
-	for (i = 0;i < chip->num_slots;i++) {
-		if (!chip->hosts[i])
-			continue;
-		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
-			pci_set_master(pdev);
-		ret = request_irq(chip->hosts[i]->irq, sdhci_irq,
-			IRQF_SHARED, mmc_hostname(chip->hosts[i]->mmc),
-			chip->hosts[i]);
-		if (ret)
-			return ret;
-		sdhci_init(chip->hosts[i]);
-		mmiowb();
-		ret = mmc_resume_host(chip->hosts[i]->mmc);
-		if (ret)
-			return ret;
-	}
+	sdhci_init(host);
+	mmiowb();
+
+	ret = mmc_resume_host(host->mmc);
+	if (ret)
+		return ret;
 
 	return 0;
 }
 
-#else /* CONFIG_PM */
-
-#define sdhci_suspend NULL
-#define sdhci_resume NULL
+EXPORT_SYMBOL_GPL(sdhci_resume_host);
 
 #endif /* CONFIG_PM */
 
 /*****************************************************************************\
  *                                                                           *
- * Device probing/removal                                                    *
+ * Device allocation/registration                                            *
  *                                                                           *
 \*****************************************************************************/
 
-static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
+struct sdhci_host *sdhci_alloc_host(struct device *dev,
+	size_t priv_size)
 {
-	int ret;
-	unsigned int version;
-	struct sdhci_chip *chip;
 	struct mmc_host *mmc;
 	struct sdhci_host *host;
 
-	u8 first_bar;
-	unsigned int caps;
-
-	chip = pci_get_drvdata(pdev);
-	BUG_ON(!chip);
-
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
-	if (ret)
-		return ret;
-
-	first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
+	WARN_ON(dev == NULL);
 
-	if (first_bar > 5) {
-		printk(KERN_ERR DRIVER_NAME ": Invalid first BAR. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if (!(pci_resource_flags(pdev, first_bar + slot) & IORESOURCE_MEM)) {
-		printk(KERN_ERR DRIVER_NAME ": BAR is not iomem. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if (pci_resource_len(pdev, first_bar + slot) != 0x100) {
-		printk(KERN_ERR DRIVER_NAME ": Invalid iomem size. "
-			"You may experience problems.\n");
-	}
-
-	if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
-		printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
-		return -ENODEV;
-	}
-
-	if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
-		printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
-		return -ENODEV;
-	}
-
-	mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
+	mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);
 	if (!mmc)
-		return -ENOMEM;
+		return ERR_PTR(-ENOMEM);
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
 
-	host->chip = chip;
-	chip->hosts[slot] = host;
+	return host;
+}
 
-	host->bar = first_bar + slot;
+EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 
-	host->addr = pci_resource_start(pdev, host->bar);
-	host->irq = pdev->irq;
+int sdhci_add_host(struct sdhci_host *host)
+{
+	struct mmc_host *mmc;
+	unsigned int caps;
+	unsigned int version;
+	int ret;
 
-	DBG("slot %d at 0x%08lx, irq %d\n", slot, host->addr, host->irq);
+	WARN_ON(host == NULL);
+	if (host == NULL)
+		return -EINVAL;
 
-	ret = pci_request_region(pdev, host->bar, mmc_hostname(mmc));
-	if (ret)
-		goto free;
+	mmc = host->mmc;
 
-	host->ioaddr = ioremap_nocache(host->addr,
-		pci_resource_len(pdev, host->bar));
-	if (!host->ioaddr) {
-		ret = -ENOMEM;
-		goto release;
-	}
+	if (debug_quirks)
+		host->quirks = debug_quirks;
 
 	sdhci_reset(host, SDHCI_RESET_ALL);
 
@@ -1401,46 +1200,40 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
 	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 
-	if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+	if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
 		host->flags |= SDHCI_USE_DMA;
 	else if (!(caps & SDHCI_CAN_DO_DMA))
 		DBG("Controller doesn't have DMA capability\n");
 	else
 		host->flags |= SDHCI_USE_DMA;
 
-	if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+	if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
 		(host->flags & SDHCI_USE_DMA)) {
 		DBG("Disabling DMA as it is marked broken\n");
 		host->flags &= ~SDHCI_USE_DMA;
 	}
 
-	if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
-		(host->flags & SDHCI_USE_DMA)) {
-		printk(KERN_WARNING "%s: Will use DMA "
-			"mode even though HW doesn't fully "
-			"claim to support it.\n", mmc_hostname(mmc));
-	}
-
 	if (host->flags & SDHCI_USE_DMA) {
-		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
-			printk(KERN_WARNING "%s: No suitable DMA available. "
-				"Falling back to PIO.\n", mmc_hostname(mmc));
-			host->flags &= ~SDHCI_USE_DMA;
+		if (host->ops->enable_dma) {
+			if (host->ops->enable_dma(host)) {
+				printk(KERN_WARNING "%s: No suitable DMA "
+					"available. Falling back to PIO.\n",
+					mmc_hostname(mmc));
+				host->flags &= ~SDHCI_USE_DMA;
+			}
 		}
 	}
 
-	if (host->flags & SDHCI_USE_DMA)
-		pci_set_master(pdev);
-	else /* XXX: Hack to get MMC layer to avoid highmem */
-		pdev->dma_mask = 0;
+	/* XXX: Hack to get MMC layer to avoid highmem */
+	if (!(host->flags & SDHCI_USE_DMA))
+		mmc_dev(host->mmc)->dma_mask = 0;
 
 	host->max_clk =
 		(caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
 	if (host->max_clk == 0) {
 		printk(KERN_ERR "%s: Hardware doesn't specify base clock "
 			"frequency.\n", mmc_hostname(mmc));
-		ret = -ENODEV;
-		goto unmap;
+		return -ENODEV;
 	}
 	host->max_clk *= 1000000;
 
@@ -1449,8 +1242,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 	if (host->timeout_clk == 0) {
 		printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
 			"frequency.\n", mmc_hostname(mmc));
-		ret = -ENODEV;
-		goto unmap;
+		return -ENODEV;
 	}
 	if (caps & SDHCI_TIMEOUT_CLK_UNIT)
 		host->timeout_clk *= 1000;
@@ -1477,8 +1269,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 	if (mmc->ocr_avail == 0) {
 		printk(KERN_ERR "%s: Hardware doesn't report any "
 			"support voltages.\n", mmc_hostname(mmc));
-		ret = -ENODEV;
-		goto unmap;
+		return -ENODEV;
 	}
 
 	spin_lock_init(&host->lock);
@@ -1548,7 +1339,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 	host->led.default_trigger = mmc_hostname(mmc);
 	host->led.brightness_set = sdhci_led_control;
 
-	ret = led_classdev_register(&pdev->dev, &host->led);
+	ret = led_classdev_register(mmc_dev(mmc), &host->led);
 	if (ret)
 		goto reset;
 #endif
@@ -1557,8 +1348,8 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
 	mmc_add_host(mmc);
 
-	printk(KERN_INFO "%s: SDHCI at 0x%08lx irq %d %s\n",
-		mmc_hostname(mmc), host->addr, host->irq,
+	printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n",
+		mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id,
 		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
 
 	return 0;
@@ -1571,29 +1362,15 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 untasklet:
 	tasklet_kill(&host->card_tasklet);
 	tasklet_kill(&host->finish_tasklet);
-unmap:
-	iounmap(host->ioaddr);
-release:
-	pci_release_region(pdev, host->bar);
-free:
-	mmc_free_host(mmc);
 
 	return ret;
 }
 
-static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
-{
-	struct sdhci_chip *chip;
-	struct mmc_host *mmc;
-	struct sdhci_host *host;
-
-	chip = pci_get_drvdata(pdev);
-	host = chip->hosts[slot];
-	mmc = host->mmc;
-
-	chip->hosts[slot] = NULL;
+EXPORT_SYMBOL_GPL(sdhci_add_host);
 
-	mmc_remove_host(mmc);
+void sdhci_remove_host(struct sdhci_host *host)
+{
+	mmc_remove_host(host->mmc);
 
 #ifdef CONFIG_LEDS_CLASS
 	led_classdev_unregister(&host->led);
@@ -1607,107 +1384,16 @@ static void sdhci_remove_slot(struct pci_dev *pdev, int slot)
 
 	tasklet_kill(&host->card_tasklet);
 	tasklet_kill(&host->finish_tasklet);
-
-	iounmap(host->ioaddr);
-
-	pci_release_region(pdev, host->bar);
-
-	mmc_free_host(mmc);
 }
 
-static int __devinit sdhci_probe(struct pci_dev *pdev,
-	const struct pci_device_id *ent)
-{
-	int ret, i;
-	u8 slots, rev;
-	struct sdhci_chip *chip;
-
-	BUG_ON(pdev == NULL);
-	BUG_ON(ent == NULL);
-
-	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
-
-	printk(KERN_INFO DRIVER_NAME
-		": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
-		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
-		(int)rev);
-
-	ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
-	if (ret)
-		return ret;
-
-	slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
-	DBG("found %d slot(s)\n", slots);
-	if (slots == 0)
-		return -ENODEV;
+EXPORT_SYMBOL_GPL(sdhci_remove_host);
 
-	ret = pci_enable_device(pdev);
-	if (ret)
-		return ret;
-
-	chip = kzalloc(sizeof(struct sdhci_chip) +
-		sizeof(struct sdhci_host*) * slots, GFP_KERNEL);
-	if (!chip) {
-		ret = -ENOMEM;
-		goto err;
-	}
-
-	chip->pdev = pdev;
-	chip->quirks = ent->driver_data;
-
-	if (debug_quirks)
-		chip->quirks = debug_quirks;
-
-	chip->num_slots = slots;
-	pci_set_drvdata(pdev, chip);
-
-	for (i = 0;i < slots;i++) {
-		ret = sdhci_probe_slot(pdev, i);
-		if (ret) {
-			for (i--;i >= 0;i--)
-				sdhci_remove_slot(pdev, i);
-			goto free;
-		}
-	}
-
-	return 0;
-
-free:
-	pci_set_drvdata(pdev, NULL);
-	kfree(chip);
-
-err:
-	pci_disable_device(pdev);
-	return ret;
-}
-
-static void __devexit sdhci_remove(struct pci_dev *pdev)
+void sdhci_free_host(struct sdhci_host *host)
 {
-	int i;
-	struct sdhci_chip *chip;
-
-	chip = pci_get_drvdata(pdev);
-
-	if (chip) {
-		for (i = 0;i < chip->num_slots;i++)
-			sdhci_remove_slot(pdev, i);
-
-		pci_set_drvdata(pdev, NULL);
-
-		kfree(chip);
-	}
-
-	pci_disable_device(pdev);
+	mmc_free_host(host->mmc);
 }
 
-static struct pci_driver sdhci_driver = {
-	.name = 	DRIVER_NAME,
-	.id_table =	pci_ids,
-	.probe = 	sdhci_probe,
-	.remove =	__devexit_p(sdhci_remove),
-	.suspend =	sdhci_suspend,
-	.resume	=	sdhci_resume,
-};
+EXPORT_SYMBOL_GPL(sdhci_free_host);
 
 /*****************************************************************************\
  *                                                                           *
@@ -1721,14 +1407,11 @@ static int __init sdhci_drv_init(void)
 		": Secure Digital Host Controller Interface driver\n");
 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
 
-	return pci_register_driver(&sdhci_driver);
+	return 0;
 }
 
 static void __exit sdhci_drv_exit(void)
 {
-	DBG("Exiting\n");
-
-	pci_unregister_driver(&sdhci_driver);
 }
 
 module_init(sdhci_drv_init);
@@ -1737,7 +1420,7 @@ module_exit(sdhci_drv_exit);
 module_param(debug_quirks, uint, 0444);
 
 MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
+MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
 MODULE_LICENSE("GPL");
 
 MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 299118de8933e892c1953ac66856af7f12dd3a8e..22fc258b12aa6b720862882ce8bc2e5b6c5b90db 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -9,18 +9,6 @@
  * your option) any later version.
  */
 
-/*
- * PCI registers
- */
-
-#define PCI_SDHCI_IFPIO			0x00
-#define PCI_SDHCI_IFDMA			0x01
-#define PCI_SDHCI_IFVENDOR		0x02
-
-#define PCI_SLOT_INFO			0x40	/* 8 bits */
-#define  PCI_SLOT_INFO_SLOTS(x)		((x >> 4) & 7)
-#define  PCI_SLOT_INFO_FIRST_BAR_MASK	0x07
-
 /*
  * Controller registers
  */
@@ -162,10 +150,43 @@
 #define  SDHCI_SPEC_VER_MASK	0x00FF
 #define  SDHCI_SPEC_VER_SHIFT	0
 
-struct sdhci_chip;
+struct sdhci_ops;
 
 struct sdhci_host {
-	struct sdhci_chip	*chip;
+	/* Data set by hardware interface driver */
+	const char		*hw_name;	/* Hardware bus name */
+
+	unsigned int		quirks;		/* Deviations from spec. */
+
+/* Controller doesn't honor resets unless we touch the clock register */
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
+/* Controller has bad caps bits, but really supports DMA */
+#define SDHCI_QUIRK_FORCE_DMA				(1<<1)
+/* Controller doesn't like to be reset when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
+/* Controller doesn't like clearing the power reg before a change */
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
+/* Controller has an unusable DMA engine */
+#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<6)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
+/* Controller has an off-by-one issue with timeout value */
+#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL		(1<<10)
+
+	int			irq;		/* Device IRQ */
+	void __iomem *		ioaddr;		/* Mapped address */
+
+	const struct sdhci_ops	*ops;		/* Low level hw interface */
+
+	/* Internal data */
 	struct mmc_host		*mmc;		/* MMC structure */
 
 #ifdef CONFIG_LEDS_CLASS
@@ -194,22 +215,33 @@ struct sdhci_host {
 	int			offset;		/* Offset into current sg */
 	int			remain;		/* Bytes left in current */
 
-	int			irq;		/* Device IRQ */
-	int			bar;		/* PCI BAR index */
-	unsigned long		addr;		/* Bus address */
-	void __iomem *		ioaddr;		/* Mapped address */
-
 	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
 	struct tasklet_struct	finish_tasklet;
 
 	struct timer_list	timer;		/* Timer for timeouts */
-};
 
-struct sdhci_chip {
-	struct pci_dev		*pdev;
+	unsigned long		private[0] ____cacheline_aligned;
+};
 
-	unsigned long		quirks;
 
-	int			num_slots;	/* Slots on controller */
-	struct sdhci_host	*hosts[0];	/* Pointers to hosts */
+struct sdhci_ops {
+	int		(*enable_dma)(struct sdhci_host *host);
 };
+
+
+extern struct sdhci_host *sdhci_alloc_host(struct device *dev,
+	size_t priv_size);
+extern void sdhci_free_host(struct sdhci_host *host);
+
+static inline void *sdhci_priv(struct sdhci_host *host)
+{
+	return (void *)host->private;
+}
+
+extern int sdhci_add_host(struct sdhci_host *host);
+extern void sdhci_remove_host(struct sdhci_host *host);
+
+#ifdef CONFIG_PM
+extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
+extern int sdhci_resume_host(struct sdhci_host *host);
+#endif