mmc: Support of PCI mode in the dw_mmc driver

Support of PCI mode for the dw_mmc driver. This Patch adds the
support for the scenario where the Synopsys Designware IP
is present on the PCI bus. The patch adds the minimal modifications
necessary for the driver to work on PCI platform. Also added separate
files for PCI and PLATFORM modes of operation.

Signed-off-by: Shashidhar Hiremath <shashidharh@vayavyalabs.com>
Acked-by: James Hogan <james.hogan@imgtec.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 00fcbed..0c9b3b1 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -533,6 +533,31 @@
 	  Designware Mobile Storage IP block. This disables the external DMA
 	  interface.
 
+config MMC_DW_PLTFM
+	tristate "Synopsys Designware MCI Support as platform device"
+	depends on MMC_DW
+	default y
+	help
+	  This selects the common helper functions support for Host Controller
+	  Interface based platform driver. Please select this option if the IP
+	  is present as a platform device. This is the common interface for the
+	  Synopsys Designware IP.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say Y.
+
+config MMC_DW_PCI
+	tristate "Synopsys Designware MCI support on PCI bus"
+	depends on MMC_DW && PCI
+	help
+	  This selects the PCI bus for the Synopsys Designware Mobile Storage IP.
+	  Select this option if the IP is present on PCI platform.
+
+	  If you have a controller with this interface, say Y or M here.
+
+	  If unsure, say N.
+
 config MMC_SH_MMCIF
 	tristate "SuperH Internal MMCIF support"
 	depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 745f8fc..3e7e26d 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -39,6 +39,8 @@
 obj-$(CONFIG_MMC_VIA_SDMMC)	+= via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
+obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
+obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)	+= vub300.o
diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c
new file mode 100644
index 0000000..dc0d25a
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pci.c
@@ -0,0 +1,158 @@
+/*
+ * Synopsys DesignWare Multimedia Card PCI Interface driver
+ *
+ * Copyright (C) 2012 Vayavya Labs Pvt. Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+#define PCI_BAR_NO 2
+#define COMPLETE_BAR 0
+#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
+#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
+/* Defining the Capabilities */
+#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\
+				MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\
+				MMC_CAP_SDIO_IRQ)
+
+static struct dw_mci_board pci_board_data = {
+	.num_slots			= 1,
+	.caps				= DW_MCI_CAPABILITIES,
+	.bus_hz				= 33 * 1000 * 1000,
+	.detect_delay_ms		= 200,
+	.fifo_depth			= 32,
+};
+
+static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *entries)
+{
+	struct dw_mci *host;
+	int ret;
+
+	ret = pci_enable_device(pdev);
+	if (ret)
+		return ret;
+	if (pci_request_regions(pdev, "dw_mmc_pci")) {
+		ret = -ENODEV;
+		goto err_disable_dev;
+	}
+
+	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+	if (!host) {
+		ret = -ENOMEM;
+		goto err_release;
+	}
+
+	host->irq = pdev->irq;
+	host->irq_flags = IRQF_SHARED;
+	host->dev = pdev->dev;
+	host->pdata = &pci_board_data;
+
+	host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
+	if (!host->regs) {
+		ret = -EIO;
+		goto err_unmap;
+	}
+
+	pci_set_drvdata(pdev, host);
+	ret = dw_mci_probe(host);
+	if (ret)
+		goto err_probe_failed;
+	return ret;
+
+err_probe_failed:
+	pci_iounmap(pdev, host->regs);
+err_unmap:
+	kfree(host);
+err_release:
+	pci_release_regions(pdev);
+err_disable_dev:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit dw_mci_pci_remove(struct pci_dev *pdev)
+{
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	dw_mci_remove(host);
+	pci_set_drvdata(pdev, NULL);
+	pci_release_regions(pdev);
+	pci_iounmap(pdev, host->regs);
+	kfree(host);
+	pci_disable_device(pdev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dw_mci_pci_suspend(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	ret = dw_mci_suspend(host);
+	return ret;
+}
+
+static int dw_mci_pci_resume(struct device *dev)
+{
+	int ret;
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct dw_mci *host = pci_get_drvdata(pdev);
+
+	ret = dw_mci_resume(host);
+	return ret;
+}
+#else
+#define dw_mci_pci_suspend	NULL
+#define dw_mci_pci_resume	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
+
+static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = {
+	{ PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
+	{}
+};
+MODULE_DEVICE_TABLE(pci, dw_mci_pci_id);
+
+static struct pci_driver dw_mci_pci_driver = {
+	.name		= "dw_mmc_pci",
+	.id_table	= dw_mci_pci_id,
+	.probe		= dw_mci_pci_probe,
+	.remove		= dw_mci_pci_remove,
+	.driver		=	{
+		.pm =   &dw_mci_pci_pmops
+	},
+};
+
+static int __init dw_mci_init(void)
+{
+	return pci_register_driver(&dw_mci_pci_driver);
+}
+
+static void __exit dw_mci_exit(void)
+{
+	pci_unregister_driver(&dw_mci_pci_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
+MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
new file mode 100644
index 0000000..92ec3eb
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -0,0 +1,134 @@
+/*
+ * Synopsys DesignWare Multimedia Card Interface driver
+ *
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2009, 2010 Imagination Technologies Ltd.
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/dw_mmc.h>
+#include "dw_mmc.h"
+
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+	struct dw_mci *host;
+	struct resource	*regs;
+	int ret;
+
+	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
+	if (!host)
+		return -ENOMEM;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		ret = -ENXIO;
+		goto err_free;
+	}
+
+	host->irq = platform_get_irq(pdev, 0);
+	if (host->irq < 0) {
+		ret = host->irq;
+		goto err_free;
+	}
+
+	host->dev = pdev->dev;
+	host->irq_flags = 0;
+	host->pdata = pdev->dev.platform_data;
+	ret = -ENOMEM;
+	host->regs = ioremap(regs->start, resource_size(regs));
+	if (!host->regs)
+		goto err_free;
+	platform_set_drvdata(pdev, host);
+	ret = dw_mci_probe(host);
+	if (ret)
+		goto err_out;
+	return ret;
+err_out:
+	iounmap(host->regs);
+err_free:
+	kfree(host);
+	return ret;
+}
+
+static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+	struct dw_mci *host = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	dw_mci_remove(host);
+	iounmap(host->regs);
+	kfree(host);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/*
+ * TODO: we should probably disable the clock to the card in the suspend path.
+ */
+static int dw_mci_pltfm_suspend(struct device *dev)
+{
+	int ret;
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	ret = dw_mci_suspend(host);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int dw_mci_pltfm_resume(struct device *dev)
+{
+	int ret;
+	struct dw_mci *host = dev_get_drvdata(dev);
+
+	ret = dw_mci_resume(host);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#else
+#define dw_mci_pltfm_suspend	NULL
+#define dw_mci_pltfm_resume	NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
+
+static struct platform_driver dw_mci_pltfm_driver = {
+	.remove		= __exit_p(dw_mci_pltfm_remove),
+	.driver		= {
+		.name		= "dw_mmc",
+		.pm		= &dw_mci_pltfm_pmops,
+	},
+};
+
+static int __init dw_mci_init(void)
+{
+	return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
+}
+
+static void __exit dw_mci_exit(void)
+{
+	platform_driver_unregister(&dw_mci_pltfm_driver);
+}
+
+module_init(dw_mci_init);
+module_exit(dw_mci_exit);
+
+MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
+MODULE_AUTHOR("NXP Semiconductor VietNam");
+MODULE_AUTHOR("Imagination Technologies Ltd");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 1dfcdef..987a265 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -268,7 +268,7 @@
 				 struct mmc_command *cmd, u32 cmd_flags)
 {
 	host->cmd = cmd;
-	dev_vdbg(&host->pdev->dev,
+	dev_vdbg(&host->dev,
 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
 		 cmd->arg, cmd_flags);
 
@@ -301,7 +301,7 @@
 	struct mmc_data *data = host->data;
 
 	if (data)
-		dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+		dma_unmap_sg(&host->dev, data->sg, data->sg_len,
 			     ((data->flags & MMC_DATA_WRITE)
 			      ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
 }
@@ -326,7 +326,7 @@
 {
 	struct mmc_data *data = host->data;
 
-	dev_vdbg(&host->pdev->dev, "DMA complete\n");
+	dev_vdbg(&host->dev, "DMA complete\n");
 
 	host->dma_ops->cleanup(host);
 
@@ -462,10 +462,10 @@
 	else
 		direction = DMA_TO_DEVICE;
 
-	sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len,
+	sg_len = dma_map_sg(&host->dev, data->sg, data->sg_len,
 			    direction);
 
-	dev_vdbg(&host->pdev->dev,
+	dev_vdbg(&host->dev,
 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
 		 sg_len);
@@ -821,12 +821,12 @@
 		slot = list_entry(host->queue.next,
 				  struct dw_mci_slot, queue_node);
 		list_del(&slot->queue_node);
-		dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+		dev_vdbg(&host->dev, "list not empty: %s is next\n",
 			 mmc_hostname(slot->mmc));
 		host->state = STATE_SENDING_CMD;
 		dw_mci_start_request(host, slot);
 	} else {
-		dev_vdbg(&host->pdev->dev, "list empty\n");
+		dev_vdbg(&host->dev, "list empty\n");
 		host->state = STATE_IDLE;
 	}
 
@@ -965,7 +965,7 @@
 					data->bytes_xfered = 0;
 					data->error = -ETIMEDOUT;
 				} else {
-					dev_err(&host->pdev->dev,
+					dev_err(&host->dev,
 						"data FIFO error "
 						"(status=%08x)\n",
 						status);
@@ -1682,7 +1682,7 @@
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
 
-	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->pdev->dev);
+	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
 	if (!mmc)
 		return -ENOMEM;
 
@@ -1794,10 +1794,10 @@
 static void dw_mci_init_dma(struct dw_mci *host)
 {
 	/* Alloc memory for sg translation */
-	host->sg_cpu = dma_alloc_coherent(&host->pdev->dev, PAGE_SIZE,
+	host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
 					  &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
-		dev_err(&host->pdev->dev, "%s: could not alloc DMA memory\n",
+		dev_err(&host->dev, "%s: could not alloc DMA memory\n",
 			__func__);
 		goto no_dma;
 	}
@@ -1805,7 +1805,7 @@
 	/* Determine which DMA interface to use */
 #ifdef CONFIG_MMC_DW_IDMAC
 	host->dma_ops = &dw_mci_idmac_ops;
-	dev_info(&host->pdev->dev, "Using internal DMA controller.\n");
+	dev_info(&host->dev, "Using internal DMA controller.\n");
 #endif
 
 	if (!host->dma_ops)
@@ -1813,12 +1813,12 @@
 
 	if (host->dma_ops->init) {
 		if (host->dma_ops->init(host)) {
-			dev_err(&host->pdev->dev, "%s: Unable to initialize "
+			dev_err(&host->dev, "%s: Unable to initialize "
 				"DMA Controller.\n", __func__);
 			goto no_dma;
 		}
 	} else {
-		dev_err(&host->pdev->dev, "DMA initialization not found.\n");
+		dev_err(&host->dev, "DMA initialization not found.\n");
 		goto no_dma;
 	}
 
@@ -1826,7 +1826,7 @@
 	return;
 
 no_dma:
-	dev_info(&host->pdev->dev, "Using PIO mode.\n");
+	dev_info(&host->dev, "Using PIO mode.\n");
 	host->use_dma = 0;
 	return;
 }
@@ -1852,61 +1852,37 @@
 	return false;
 }
 
-static int dw_mci_probe(struct platform_device *pdev)
+int dw_mci_probe(struct dw_mci *host)
 {
-	struct dw_mci *host;
-	struct resource	*regs;
-	struct dw_mci_board *pdata;
-	int irq, ret, i, width;
+	int width, i, ret = 0;
 	u32 fifo_size;
 
-	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!regs)
-		return -ENXIO;
-
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
-		return irq;
-
-	host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
-	if (!host)
-		return -ENOMEM;
-
-	host->pdev = pdev;
-	host->pdata = pdata = pdev->dev.platform_data;
-	if (!pdata || !pdata->init) {
-		dev_err(&pdev->dev,
+	if (!host->pdata || !host->pdata->init) {
+		dev_err(&host->dev,
 			"Platform data must supply init function\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	if (!pdata->select_slot && pdata->num_slots > 1) {
-		dev_err(&pdev->dev,
+	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
+		dev_err(&host->dev,
 			"Platform data must supply select_slot function\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	if (!pdata->bus_hz) {
-		dev_err(&pdev->dev,
+	if (!host->pdata->bus_hz) {
+		dev_err(&host->dev,
 			"Platform data must supply bus speed\n");
-		ret = -ENODEV;
-		goto err_freehost;
+		return -ENODEV;
 	}
 
-	host->bus_hz = pdata->bus_hz;
-	host->quirks = pdata->quirks;
+	host->bus_hz = host->pdata->bus_hz;
+	host->quirks = host->pdata->quirks;
 
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
-	ret = -ENOMEM;
-	host->regs = ioremap(regs->start, resource_size(regs));
-	if (!host->regs)
-		goto err_freehost;
 
-	host->dma_ops = pdata->dma_ops;
+	host->dma_ops = host->pdata->dma_ops;
 	dw_mci_init_dma(host);
 
 	/*
@@ -1936,7 +1912,7 @@
 	}
 
 	/* Reset all blocks */
-	if (!mci_wait_reset(&pdev->dev, host)) {
+	if (!mci_wait_reset(&host->dev, host)) {
 		ret = -ENODEV;
 		goto err_dmaunmap;
 	}
@@ -1979,13 +1955,10 @@
 	if (!dw_mci_card_workqueue)
 		goto err_dmaunmap;
 	INIT_WORK(&host->card_work, dw_mci_work_routine_card);
-
-	ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+	ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
 	if (ret)
 		goto err_workqueue;
 
-	platform_set_drvdata(pdev, host);
-
 	if (host->pdata->num_slots)
 		host->num_slots = host->pdata->num_slots;
 	else
@@ -2005,7 +1978,7 @@
 	 * Need to check the version-id and set data-offset for DATA register.
 	 */
 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-	dev_info(&pdev->dev, "Version ID is %04x\n", host->verid);
+	dev_info(&host->dev, "Version ID is %04x\n", host->verid);
 
 	if (host->verid < DW_MMC_240A)
 		host->data_offset = DATA_OFFSET;
@@ -2022,12 +1995,12 @@
 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-	dev_info(&pdev->dev, "DW MMC controller at irq %d, "
+	dev_info(&host->dev, "DW MMC controller at irq %d, "
 		 "%d bit host data width, "
 		 "%u deep fifo\n",
-		 irq, width, fifo_size);
+		 host->irq, width, fifo_size);
 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-		dev_info(&pdev->dev, "Internal DMAC interrupt fix enabled.\n");
+		dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
 
 	return 0;
 
@@ -2038,7 +2011,7 @@
 			dw_mci_cleanup_slot(host->slot[i], i);
 		i--;
 	}
-	free_irq(irq, host);
+	free_irq(host->irq, host);
 
 err_workqueue:
 	destroy_workqueue(dw_mci_card_workqueue);
@@ -2046,33 +2019,26 @@
 err_dmaunmap:
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
-	dma_free_coherent(&host->pdev->dev, PAGE_SIZE,
+	dma_free_coherent(&host->dev, PAGE_SIZE,
 			  host->sg_cpu, host->sg_dma);
-	iounmap(host->regs);
 
 	if (host->vmmc) {
 		regulator_disable(host->vmmc);
 		regulator_put(host->vmmc);
 	}
-
-
-err_freehost:
-	kfree(host);
 	return ret;
 }
+EXPORT_SYMBOL(dw_mci_probe);
 
-static int __exit dw_mci_remove(struct platform_device *pdev)
+void dw_mci_remove(struct dw_mci *host)
 {
-	struct dw_mci *host = platform_get_drvdata(pdev);
 	int i;
 
 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
-	platform_set_drvdata(pdev, NULL);
-
 	for (i = 0; i < host->num_slots; i++) {
-		dev_dbg(&pdev->dev, "remove slot %d\n", i);
+		dev_dbg(&host->dev, "remove slot %d\n", i);
 		if (host->slot[i])
 			dw_mci_cleanup_slot(host->slot[i], i);
 	}
@@ -2081,9 +2047,9 @@
 	mci_writel(host, CLKENA, 0);
 	mci_writel(host, CLKSRC, 0);
 
-	free_irq(platform_get_irq(pdev, 0), host);
+	free_irq(host->irq, host);
 	destroy_workqueue(dw_mci_card_workqueue);
-	dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
@@ -2093,20 +2059,18 @@
 		regulator_put(host->vmmc);
 	}
 
-	iounmap(host->regs);
-
-	kfree(host);
-	return 0;
 }
+EXPORT_SYMBOL(dw_mci_remove);
+
+
 
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
-static int dw_mci_suspend(struct device *dev)
+int dw_mci_suspend(struct dw_mci *host)
 {
-	int i, ret;
-	struct dw_mci *host = dev_get_drvdata(dev);
+	int i, ret = 0;
 
 	for (i = 0; i < host->num_slots; i++) {
 		struct dw_mci_slot *slot = host->slot[i];
@@ -2128,11 +2092,11 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(dw_mci_suspend);
 
-static int dw_mci_resume(struct device *dev)
+int dw_mci_resume(struct dw_mci *host)
 {
 	int i, ret;
-	struct dw_mci *host = dev_get_drvdata(dev);
 
 	if (host->vmmc)
 		regulator_enable(host->vmmc);
@@ -2140,7 +2104,7 @@
 	if (host->dma_ops->init)
 		host->dma_ops->init(host);
 
-	if (!mci_wait_reset(dev, host)) {
+	if (!mci_wait_reset(&host->dev, host)) {
 		ret = -ENODEV;
 		return ret;
 	}
@@ -2162,32 +2126,19 @@
 		if (ret < 0)
 			return ret;
 	}
-
 	return 0;
 }
-#else
-#define dw_mci_suspend	NULL
-#define dw_mci_resume	NULL
+EXPORT_SYMBOL(dw_mci_resume);
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(dw_mci_pmops, dw_mci_suspend, dw_mci_resume);
-
-static struct platform_driver dw_mci_driver = {
-	.remove		= __exit_p(dw_mci_remove),
-	.driver		= {
-		.name		= "dw_mmc",
-		.pm		= &dw_mci_pmops,
-	},
-};
-
 static int __init dw_mci_init(void)
 {
-	return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+	printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
+	return 0;
 }
 
 static void __exit dw_mci_exit(void)
 {
-	platform_driver_unregister(&dw_mci_driver);
 }
 
 module_init(dw_mci_init);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index df392a1..15c27e1 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -175,4 +175,11 @@
 	(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
 #endif
 
+extern int dw_mci_probe(struct dw_mci *host);
+extern void dw_mci_remove(struct dw_mci *host);
+#ifdef CONFIG_PM
+extern int dw_mci_suspend(struct dw_mci *host);
+extern int dw_mci_resume(struct dw_mci *host);
+#endif
+
 #endif /* _DW_MMC_H_ */