SDHCI: Split PCI support from SDHCI core Split the PCI support out of the SDHCI to provide support for generic and local bus connected controllers, such as found on the Samsung S3C24XX series of processors. The patch removes the struct sdhci_chip, and replaces it with a hardware driver private word for the interface layer to use. It becomes the interface layer's duty to reserve, allocate and map the resources needed by the driver. The interface layer deals with suspend, resume and optionally override of various control functions that may need specific quirks. The pci driver is updated to use the dev_dbg and associated reporting macros, so all output from the interface layer is tagged with the device information. Signed-off-by: Ben Dooks Index: linux-2.6.22-rc4-mmc1/drivers/mmc/host/Kconfig =================================================================== --- linux-2.6.22-rc4-mmc1.orig/drivers/mmc/host/Kconfig +++ linux-2.6.22-rc4-mmc1/drivers/mmc/host/Kconfig @@ -26,7 +26,7 @@ config MMC_PXA config MMC_SDHCI tristate "Secure Digital Host Controller Interface support (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL + depends on EXPERIMENTAL help This select the generic Secure Digital Host Controller Interface. It is used by manufacturers such as Texas Instruments(R), Ricoh(R) @@ -35,6 +35,16 @@ config MMC_SDHCI If unsure, say N. +config MMC_SDHCI_PCI + tristate "SDHCI support on PCI bus (EXPERIMENTAL)" + depends on MMC_SDHCI && PCI + help + Say Y here if you have an Secure Digital Host Controller device + connected via the PCI bus. This is generally used by devices by + Texas Instruments(R), Ricoh(R) and Toshiba(R). + + If unsure, say N. + config MMC_OMAP tristate "TI OMAP Multimedia Card Interface support" depends on ARCH_OMAP Index: linux-2.6.22-rc4-mmc1/drivers/mmc/host/Makefile =================================================================== --- linux-2.6.22-rc4-mmc1.orig/drivers/mmc/host/Makefile +++ linux-2.6.22-rc4-mmc1/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_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o Index: linux-2.6.22-rc4-mmc1/drivers/mmc/host/sdhci.c =================================================================== --- linux-2.6.22-rc4-mmc1.orig/drivers/mmc/host/sdhci.c +++ linux-2.6.22-rc4-mmc1/drivers/mmc/host/sdhci.c @@ -11,12 +11,12 @@ #include #include -#include #include #include #include +#include #include "sdhci.h" @@ -29,56 +29,6 @@ static unsigned int debug_nodma = 0; static unsigned int debug_forcedma = 0; static unsigned int debug_quirks = 0; -#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) -#define SDHCI_QUIRK_FORCE_DMA (1<<1) -/* Controller doesn't like some resets when there is no card inserted. */ -#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) -#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) - -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_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SDHCI_QUIRK_FORCE_DMA | - SDHCI_QUIRK_NO_CARD_NO_RESET, - }, - - { - .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, - }, - - { /* 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 *); @@ -133,7 +83,7 @@ static void sdhci_reset(struct sdhci_hos { 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; @@ -395,13 +345,9 @@ static void sdhci_prepare_data(struct sd writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); if (host->flags & SDHCI_USE_DMA) { - int count; + unsigned long addr = (host->hardware->map_sg)(host, data); - 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); - - writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS); + writel(addr, host->ioaddr + SDHCI_DMA_ADDRESS); } else { host->cur_sg = data->sg; host->num_sg = data->sg_len; @@ -448,8 +394,7 @@ static void sdhci_finish_data(struct sdh host->data = NULL; if (host->flags & SDHCI_USE_DMA) { - pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, - (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); + (host->hardware->unmap_sg)(host, data); } /* @@ -601,6 +546,11 @@ static void sdhci_set_clock(struct sdhci if (clock == host->clock) return; + if (host->hardware->set_clock) { + host->hardware->set_clock(host, clock); + goto out; + } + writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); if (clock == 0) @@ -653,7 +603,7 @@ static void sdhci_set_power(struct sdhci * 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; @@ -838,7 +788,7 @@ static void sdhci_tasklet_finish(unsigne (mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) { /* 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 */ @@ -977,7 +927,7 @@ static void sdhci_data_irq(struct sdhci_ } } -static irqreturn_t sdhci_irq(int irq, void *dev_id) +irqreturn_t sdhci_irq(int irq, void *dev_id) { irqreturn_t result; struct sdhci_host* host = dev_id; @@ -1041,6 +991,8 @@ out: return result; } +EXPORT_SYMBOL_GPL(sdhci_irq); + /*****************************************************************************\ * * * Suspend/resume * @@ -1049,84 +1001,31 @@ out: #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); - - for (i = 0;i < chip->num_slots;i++) { - if (!chip->hosts[i]) - continue; - free_irq(chip->hosts[i]->irq, chip->hosts[i]); - } - - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; + return mmc_suspend_host(host->mmc, state); } -static int sdhci_resume (struct pci_dev *pdev) +EXPORT_SYMBOL_GPL(sdhci_suspend_host); + +int sdhci_resume_host(struct sdhci_host *host) { - struct sdhci_chip *chip; - int i, ret; + int ret; - chip = pci_get_drvdata(pdev); - if (!chip) - return 0; + if (host->hardware->set_dma) + host->hardware->set_dma(host, host->flags & SDHCI_USE_DMA); - DBG("Resuming...\n"); + sdhci_init(host); + mmiowb(); - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); + ret = mmc_resume_host(host->mmc); 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, chip->hosts[i]->slot_descr, - 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; - } - return 0; } -#else /* CONFIG_PM */ - -#define sdhci_suspend NULL -#define sdhci_resume NULL +EXPORT_SYMBOL(sdhci_resume_host); #endif /* CONFIG_PM */ @@ -1136,80 +1035,53 @@ static int sdhci_resume (struct pci_dev * * \*****************************************************************************/ -static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) +struct sdhci_host __devinit *sdhci_alloc_host(struct device *dev, + struct sdhci_hardware *hw, + 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; - - 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; + if (hw == NULL || dev == NULL) { + printk(KERN_ERR "%s: passed bad arguments\n", __func__); + return ERR_PTR(-EINVAL); } - 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->priv = (host + 1); + host->hardware = hw; - 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_start_host(struct sdhci_host *host) +{ + struct sdhci_hardware *hw; + 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); + if (host == NULL) + return -EINVAL; - snprintf(host->slot_descr, 20, "sdhci:slot%d", slot); + mmc = host->mmc; + hw = host->hardware; - ret = pci_request_region(pdev, host->bar, host->slot_descr); - if (ret) - goto free; + if (hw->get_quirks) + host->quirks = hw->get_quirks(host); - 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; + + DBG("%s at 0x%08lx, irq %d\n", host->slot_descr, host->addr, host->irq); sdhci_reset(host, SDHCI_RESET_ALL); @@ -1223,53 +1095,54 @@ static int __devinit sdhci_probe_slot(st caps = readl(host->ioaddr + SDHCI_CAPABILITIES); + if (hw->update_caps) + caps = hw->update_caps(host, caps); + if (debug_nodma) DBG("DMA forced off\n"); else if (debug_forcedma) { DBG("DMA forced on\n"); host->flags |= SDHCI_USE_DMA; - } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA) + } else if (host->quirks & SDHCI_QUIRK_FORCE_DMA) host->flags |= SDHCI_USE_DMA; - else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) - DBG("Controller doesn't have DMA interface\n"); else if (!(caps & SDHCI_CAN_DO_DMA)) DBG("Controller doesn't have DMA capability\n"); else host->flags |= SDHCI_USE_DMA; - 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", host->slot_descr); - host->flags &= ~SDHCI_USE_DMA; + if (hw->set_dma) + hw->set_dma(host, host->flags & SDHCI_USE_DMA); + + if (hw->get_max_clk) { + host->max_clk = hw->get_max_clk(host); + } else { + 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", host->slot_descr); + ret = -ENODEV; + goto err; } - } - if (host->flags & SDHCI_USE_DMA) - pci_set_master(pdev); - else /* XXX: Hack to get MMC layer to avoid highmem */ - pdev->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", host->slot_descr); - ret = -ENODEV; - goto unmap; + host->max_clk *= 1000000; } - host->max_clk *= 1000000; - host->timeout_clk = - (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; - if (host->timeout_clk == 0) { - printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " - "frequency.\n", host->slot_descr); - ret = -ENODEV; - goto unmap; + if (hw->get_timeout_clk) { + host->timeout_clk = hw->get_timeout_clk(host); + } else { + host->timeout_clk = + (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT; + if (host->timeout_clk == 0) { + printk(KERN_ERR "%s: Hardware doesn't specify timeout clock " + "frequency.\n", host->slot_descr); + ret = -ENODEV; + goto err; + } + + if (caps & SDHCI_TIMEOUT_CLK_UNIT) + host->timeout_clk *= 1000; } - if (caps & SDHCI_TIMEOUT_CLK_UNIT) - host->timeout_clk *= 1000; /* * Set host parameters. @@ -1294,7 +1167,7 @@ static int __devinit sdhci_probe_slot(st printk(KERN_ERR "%s: Hardware doesn't report any " "support voltages.\n", host->slot_descr); ret = -ENODEV; - goto unmap; + goto err; } spin_lock_init(&host->lock); @@ -1329,7 +1202,7 @@ static int __devinit sdhci_probe_slot(st printk(KERN_ERR "%s: Invalid maximum block size.\n", host->slot_descr); ret = -ENODEV; - goto unmap; + goto err; } mmc->max_blk_size = 512 << mmc->max_blk_size; @@ -1349,7 +1222,7 @@ static int __devinit sdhci_probe_slot(st setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host); ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, - host->slot_descr, host); + host->slot_descr, host); if (ret) goto untasklet; @@ -1372,27 +1245,16 @@ static int __devinit sdhci_probe_slot(st 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); + err: 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; +EXPORT_SYMBOL_GPL(sdhci_start_host); - chip->hosts[slot] = NULL; +void sdhci_remove_host(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; mmc_remove_host(mmc); @@ -1404,139 +1266,23 @@ static void sdhci_remove_slot(struct pci 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; - - 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) -{ - 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); +EXPORT_SYMBOL_GPL(sdhci_remove_host); - pci_set_drvdata(pdev, NULL); - - kfree(chip); - } - - pci_disable_device(pdev); -} - -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, -}; - -/*****************************************************************************\ - * * - * Driver init/exit * - * * -\*****************************************************************************/ - -static int __init sdhci_drv_init(void) +void sdhci_free_host(struct sdhci_host *host) { - printk(KERN_INFO DRIVER_NAME - ": Secure Digital Host Controller Interface driver\n"); - printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); - - return pci_register_driver(&sdhci_driver); -} - -static void __exit sdhci_drv_exit(void) -{ - DBG("Exiting\n"); - - pci_unregister_driver(&sdhci_driver); + mmc_free_host(host->mmc); } -module_init(sdhci_drv_init); -module_exit(sdhci_drv_exit); +EXPORT_SYMBOL_GPL(sdhci_free_host); module_param(debug_nodma, uint, 0444); module_param(debug_forcedma, uint, 0444); module_param(debug_quirks, uint, 0444); MODULE_AUTHOR("Pierre Ossman "); -MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver"); +MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); MODULE_LICENSE("GPL"); MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)"); Index: linux-2.6.22-rc4-mmc1/drivers/mmc/host/sdhci.h =================================================================== --- linux-2.6.22-rc4-mmc1.orig/drivers/mmc/host/sdhci.h +++ linux-2.6.22-rc4-mmc1/drivers/mmc/host/sdhci.h @@ -161,18 +161,26 @@ #define SDHCI_SPEC_VER_MASK 0x00FF #define SDHCI_SPEC_VER_SHIFT 0 -struct sdhci_chip; +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +#define SDHCI_QUIRK_FORCE_DMA (1<<1) +/* Controller doesn't like some resets when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) + struct sdhci_hardwre; struct sdhci_host { - struct sdhci_chip *chip; + struct sdhci_hardware *hardware; /* SDHCI hardware */ struct mmc_host *mmc; /* MMC structure */ + void *priv; /* hardware private info */ + spinlock_t lock; /* Mutex */ int flags; /* Host attributes */ #define SDHCI_USE_DMA (1<<0) + unsigned int quirks; /* Host quirks */ unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int timeout_clk; /* Timeout freq (KHz) */ @@ -191,7 +199,6 @@ struct sdhci_host { char slot_descr[20]; /* Name for reservations */ int irq; /* Device IRQ */ - int bar; /* PCI BAR index */ unsigned long addr; /* Bus address */ void __iomem * ioaddr; /* Mapped address */ @@ -201,15 +208,6 @@ struct sdhci_host { struct timer_list timer; /* Timer for timeouts */ }; -struct sdhci_chip { - struct pci_dev *pdev; - - unsigned long quirks; - - int num_slots; /* Slots on controller */ - struct sdhci_host *hosts[0]; /* Pointers to hosts */ -}; - /* controller structure for defining the interface specific functions * that the core needs to know about the hardware. */ @@ -232,3 +230,18 @@ struct sdhci_hardware { void (*unmap_sg)(struct sdhci_host *host, struct mmc_data *data); }; + + +extern struct sdhci_host *sdhci_alloc_host(struct device *dev, + struct sdhci_hardware *hw, + size_t priv_size); + +extern int sdhci_start_host(struct sdhci_host *); + +extern void sdhci_remove_host(struct sdhci_host *host); +extern void sdhci_free_host(struct sdhci_host *host); + +extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); +extern int sdhci_resume_host(struct sdhci_host *host); + +extern irqreturn_t sdhci_irq(int irq, void *dev_id);