Signed-off-by: Shashidhar Hiremath <[email protected]>
---
drivers/mmc/host/Kconfig | 11 ++++
drivers/mmc/host/dw_mmc.c | 126 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/dw_mmc.h | 12 ++++
include/linux/mmc/dw_mmc.h | 4 ++
4 files changed, 153 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 8c87096..84d8908 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -526,6 +526,17 @@ config MMC_DW
block, this provides host support for SD and MMC interfaces, in both
PIO and external DMA modes.
+config MMC_DW_PCI
+ bool "MMC_DW Support On PCI bus"
+ depends on MMC_DW && PCI
+ help
+ This selects the PCI for the Synopsys Designware Mobile Storage IP.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
+
config MMC_DW_IDMAC
bool "Internal DMAC interface"
depends on MMC_DW
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index ff0f714..74f28a5 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -21,7 +21,11 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#ifdef CONFIG_MMC_DW_PCI
+#include <linux/pci.h>
+#else
#include <linux/platform_device.h>
+#endif
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -101,6 +105,18 @@ struct dw_mci_slot {
int last_detect_state;
};
+#ifdef CONFIG_MMC_DW_PCI
+static struct pci_device_id dw_mci_id = { PCI_DEVICE(DEVICE_ID, VENDOR_ID) };
+
+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,
+};
+#endif
+
static struct workqueue_struct *dw_mci_card_workqueue;
#if defined(CONFIG_DEBUG_FS)
@@ -682,6 +698,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct
mmc_ios *ios)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
u32 regs;
+#ifdef CONFIG_MMC_DW_PCI
+ u32 card_detect;
+#endif
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
@@ -716,7 +735,15 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct
mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
+#ifdef CONFIG_MMC_DW_PCI
+ /* Enable Power to the card that has been detected */
+ card_detect = mci_readl(slot->host, CDETECT);
+ mci_writel(slot->host, PWREN, ((~card_detect) & 0x1));
+ break;
+ case MMC_POWER_OFF:
+ mci_writel(slot->host, PWREN, 0);
break;
+#endif
default:
break;
}
@@ -1775,7 +1802,12 @@ static bool mci_wait_reset(struct device *dev, struct
dw_mci *host)
return false;
}
+#ifdef CONFIG_MMC_DW_PCI
+static int __devinit dw_mci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *entries)
+#else
static int dw_mci_probe(struct platform_device *pdev)
+#endif
{
struct dw_mci *host;
struct resource *regs;
@@ -1783,6 +1815,16 @@ static int dw_mci_probe(struct platform_device *pdev)
int irq, ret, i, width;
u32 fifo_size;
+#ifdef CONFIG_MMC_DW_PCI
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+ if (pci_request_regions(pdev, "dw_mmc")) {
+ ret = -ENODEV;
+ goto err_freehost;
+ }
+ irq = pdev->irq;
+#else
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs)
return -ENXIO;
@@ -1790,19 +1832,26 @@ static int dw_mci_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
+#endif
host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
if (!host)
return -ENOMEM;
host->pdev = pdev;
+#ifdef CONFIG_MMC_DW_PCI
+ host->pdata = pdata = &pci_board_data;
+#else
host->pdata = pdata = pdev->dev.platform_data;
+#endif
+#ifndef CONFIG_MMC_DW_PCI
if (!pdata || !pdata->init) {
dev_err(&pdev->dev,
"Platform data must supply init function\n");
ret = -ENODEV;
goto err_freehost;
}
+#endif
if (!pdata->select_slot && pdata->num_slots > 1) {
dev_err(&pdev->dev,
@@ -1825,9 +1874,17 @@ static int dw_mci_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&host->queue);
ret = -ENOMEM;
+#ifdef CONFIG_MMC_DW_PCI
+ host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
+ if (!host->regs) {
+ ret = -EIO;
+ goto err_free_res;
+ }
+#else
host->regs = ioremap(regs->start, resource_size(regs));
if (!host->regs)
goto err_freehost;
+#endif
host->dma_ops = pdata->dma_ops;
dw_mci_init_dma(host);
@@ -1903,11 +1960,19 @@ static int dw_mci_probe(struct platform_device *pdev)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
+#ifdef CONFIG_MMC_DW_PCI
+ ret = request_irq(irq, dw_mci_interrupt, IRQF_SHARED, "dw-mci", host);
+#else
ret = request_irq(irq, dw_mci_interrupt, 0, "dw-mci", host);
+#endif
if (ret)
goto err_workqueue;
+#ifdef CONFIG_MMC_DW_PCI
+ pci_set_drvdata(pdev, host);
+#else
platform_set_drvdata(pdev, host);
+#endif
if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots;
@@ -1966,21 +2031,38 @@ err_dmaunmap:
regulator_put(host->vmmc);
}
+#ifdef CONFIG_MMC_DW_PCI
+err_free_res:
+ pci_release_regions(pdev);
+#endif
err_freehost:
kfree(host);
return ret;
}
+#ifdef CONFIG_MMC_DW_PCI
+static void __devexit dw_mci_remove(struct pci_dev *pdev)
+#else
static int __exit dw_mci_remove(struct platform_device *pdev)
+#endif
{
+
+#ifdef CONFIG_MMC_DW_PCI
+ struct dw_mci *host = pci_get_drvdata(pdev);
+#else
struct dw_mci *host = platform_get_drvdata(pdev);
+#endif
int i;
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
+#ifdef CONFIG_MMC_DW_PCI
+ pci_set_drvdata(pdev, NULL);
+#else
platform_set_drvdata(pdev, NULL);
+#endif
for (i = 0; i < host->num_slots; i++) {
dev_dbg(&pdev->dev, "remove slot %d\n", i);
@@ -1992,7 +2074,11 @@ static int __exit dw_mci_remove(struct platform_device
*pdev)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
+#ifdef CONFIG_MMC_DW_PCI
+ free_irq(pdev->irq, host);
+#else
free_irq(platform_get_irq(pdev, 0), host);
+#endif
destroy_workqueue(dw_mci_card_workqueue);
dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
@@ -2006,18 +2092,31 @@ static int __exit dw_mci_remove(struct platform_device
*pdev)
iounmap(host->regs);
+#ifdef CONFIG_MMC_DW_PCI
+ pci_release_regions(pdev);
+#endif
kfree(host);
+#ifndef CONFIG_MMC_DW_PCI
return 0;
+#endif
}
#ifdef CONFIG_PM
/*
* TODO: we should probably disable the clock to the card in the suspend path.
*/
+#ifdef CONFIG_MMC_DW_PCI
+static int dw_mci_suspend(struct pci_dev *pdev, pm_message_t mesg)
+#else
static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
+#endif
{
int i, ret;
+#ifdef CONFIG_MMC_DW_PCI
+ struct dw_mci *host = pci_get_drvdata(pdev);
+#else
struct dw_mci *host = platform_get_drvdata(pdev);
+#endif
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
@@ -2040,10 +2139,18 @@ static int dw_mci_suspend(struct platform_device *pdev,
pm_message_t mesg)
return 0;
}
+#ifdef CONFIG_MMC_DW_PCI
+static int dw_mci_resume(struct pci_dev *pdev)
+#else
static int dw_mci_resume(struct platform_device *pdev)
+#endif
{
int i, ret;
+#ifdef CONFIG_MMC_DW_PCI
+ struct dw_mci *host = pci_get_drvdata(pdev);
+#else
struct dw_mci *host = platform_get_drvdata(pdev);
+#endif
if (host->vmmc)
regulator_enable(host->vmmc);
@@ -2081,6 +2188,16 @@ static int dw_mci_resume(struct platform_device *pdev)
#define dw_mci_resume NULL
#endif /* CONFIG_PM */
+#ifdef CONFIG_MMC_DW_PCI
+static struct pci_driver dw_mci_driver = {
+ .name = "dw_mmc",
+ .id_table = &dw_mci_id,
+ .probe = dw_mci_probe,
+ .remove = dw_mci_remove,
+ .suspend = dw_mci_suspend,
+ .resume = dw_mci_resume,
+};
+#else
static struct platform_driver dw_mci_driver = {
.remove = __exit_p(dw_mci_remove),
.suspend = dw_mci_suspend,
@@ -2089,15 +2206,24 @@ static struct platform_driver dw_mci_driver = {
.name = "dw_mmc",
},
};
+#endif
static int __init dw_mci_init(void)
{
+#ifdef CONFIG_MMC_DW_PCI
+ return pci_register_driver(&dw_mci_driver);
+#else
return platform_driver_probe(&dw_mci_driver, dw_mci_probe);
+#endif
}
static void __exit dw_mci_exit(void)
{
+#ifdef CONFIG_MMC_DW_PCI
+ pci_unregister_driver(&dw_mci_driver);
+#else
platform_driver_unregister(&dw_mci_driver);
+#endif
}
module_init(dw_mci_init);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 027d377..3b1e459 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -164,4 +164,16 @@
(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
#endif
+/* PCI Specific macros */
+#ifdef CONFIG_MMC_DW_PCI
+#define PCI_BAR_NO 2
+#define COMPLETE_BAR 0
+/* Dummy Device Id and Vendor Id */
+#define VENDOR_ID 0x700
+#define 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)
+#endif
+
#endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 6b46819..87af5a6 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -147,7 +147,11 @@ struct dw_mci {
u32 current_speed;
u32 num_slots;
u32 fifoth_val;
+#ifdef CONFIG_MMC_DW_PCI
+ struct pci_dev *pdev;
+#else
struct platform_device *pdev;
+#endif
struct dw_mci_board *pdata;
struct dw_mci_slot *slot[MAX_MCI_SLOTS];
--
1.7.2.3
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html