#include "dw_mmc.h"
 
-int dw_mci_pltfm_register(struct platform_device *pdev)
+int dw_mci_pltfm_register(struct platform_device *pdev,
+                               struct dw_mci_drv_data *drv_data)
 {
        struct dw_mci *host;
        struct resource *regs;
        if (host->irq < 0)
                return host->irq;
 
+       host->drv_data = drv_data;
        host->dev = &pdev->dev;
        host->irq_flags = 0;
        host->pdata = pdev->dev.platform_data;
        if (!host->regs)
                return -ENOMEM;
 
+       if (host->drv_data->init) {
+               ret = host->drv_data->init(host);
+               if (ret)
+                       return ret;
+       }
+
        platform_set_drvdata(pdev, host);
        ret = dw_mci_probe(host);
        return ret;
 
 static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev)
 {
-       return dw_mci_pltfm_register(pdev);
+       return dw_mci_pltfm_register(pdev, NULL);
 }
 
 static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev)
 
 #ifndef _DW_MMC_PLTFM_H_
 #define _DW_MMC_PLTFM_H_
 
-extern int dw_mci_pltfm_register(struct platform_device *pdev);
+extern int dw_mci_pltfm_register(struct platform_device *pdev,
+                               struct dw_mci_drv_data *drv_data);
 extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev);
 extern const struct dev_pm_ops dw_mci_pltfm_pmops;
 
 
 static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
+       struct dw_mci_slot *slot = mmc_priv(mmc);
        u32 cmdr;
        cmd->error = -EINPROGRESS;
 
                        cmdr |= SDMMC_CMD_DAT_WR;
        }
 
+       if (slot->host->drv_data->prepare_command)
+               slot->host->drv_data->prepare_command(slot->host, &cmdr);
+
        return cmdr;
 }
 
                slot->clock = ios->clock;
        }
 
+       if (slot->host->drv_data->set_ios)
+               slot->host->drv_data->set_ios(slot->host, ios);
+
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
 {
        struct mmc_host *mmc;
        struct dw_mci_slot *slot;
+       int ctrl_id, ret;
        u8 bus_width;
 
        mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
 
+       if (host->dev->of_node) {
+               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+               if (ctrl_id < 0)
+                       ctrl_id = 0;
+       } else {
+               ctrl_id = to_platform_device(host->dev)->id;
+       }
+       if (host->drv_data && host->drv_data->caps)
+               mmc->caps |= host->drv_data->caps[ctrl_id];
+
        if (host->pdata->caps2)
                mmc->caps2 = host->pdata->caps2;
 
        else
                bus_width = 1;
 
+       if (host->drv_data->setup_bus) {
+               struct device_node *slot_np;
+               slot_np = dw_mci_of_find_slot_node(host->dev, slot->id);
+               ret = host->drv_data->setup_bus(host, slot_np, bus_width);
+               if (ret)
+                       goto err_setup_bus;
+       }
+
        switch (bus_width) {
        case 8:
                mmc->caps |= MMC_CAP_8_BIT_DATA;
        queue_work(host->card_workqueue, &host->card_work);
 
        return 0;
+
+err_setup_bus:
+       mmc_free_host(mmc);
+       return -EINVAL;
 }
 
 static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
        struct dw_mci_board *pdata;
        struct device *dev = host->dev;
        struct device_node *np = dev->of_node;
-       int idx;
+       int idx, ret;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata) {
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
+       if (host->drv_data->parse_dt) {
+               ret = host->drv_data->parse_dt(host);
+               if (ret)
+                       return ERR_PTR(ret);
+       }
+
        return pdata;
 }
 
        else
                host->bus_hz = clk_get_rate(host->ciu_clk);
 
+       if (host->drv_data->setup_clock) {
+               ret = host->drv_data->setup_clock(host);
+               if (ret) {
+                       dev_err(host->dev,
+                               "implementation specific clock setup failed\n");
+                       goto err_clk_ciu;
+               }
+       }
+
        if (!host->bus_hz) {
                dev_err(host->dev,
                        "Platform data must supply bus speed\n");
 
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 
+/**
+ * dw_mci driver data - dw-mshc implementation specific driver data.
+ * @caps: mmc subsystem specified capabilities of the controller(s).
+ * @init: early implementation specific initialization.
+ * @setup_clock: implementation specific clock configuration.
+ * @prepare_command: handle CMD register extensions.
+ * @set_ios: handle bus specific extensions.
+ * @parse_dt: parse implementation specific device tree properties.
+ * @setup_bus: initialize io-interface
+ *
+ * Provide controller implementation specific extensions. The usage of this
+ * data structure is fully optional and usage of each member in this structure
+ * is optional as well.
+ */
+struct dw_mci_drv_data {
+       unsigned long   *caps;
+       int             (*init)(struct dw_mci *host);
+       int             (*setup_clock)(struct dw_mci *host);
+       void            (*prepare_command)(struct dw_mci *host, u32 *cmdr);
+       void            (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
+       int             (*parse_dt)(struct dw_mci *host);
+       int             (*setup_bus)(struct dw_mci *host,
+                               struct device_node *slot_np, u8 bus_width);
+};
 #endif /* _DW_MMC_H_ */
 
  * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
+ * @drv_data: Driver specific data for identified variant of the controller
+ * @priv: Implementation defined private data.
  * @biu_clk: Pointer to bus interface unit clock instance.
  * @ciu_clk: Pointer to card interface unit clock instance.
  * @slot: Slots sharing this MMC controller.
        u16                     data_offset;
        struct device           *dev;
        struct dw_mci_board     *pdata;
+       struct dw_mci_drv_data  *drv_data;
+       void                    *priv;
        struct clk              *biu_clk;
        struct clk              *ciu_clk;
        struct dw_mci_slot      *slot[MAX_MCI_SLOTS];