struct clk              *clk_bus[MAX_BUS_CLK];
 };
 
+/**
+ * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
+ * @sdhci_quirks: sdhci host specific quirks.
+ *
+ * Specifies platform specific configuration of sdhci controller.
+ * Note: A structure for driver specific platform data is used for future
+ * expansion of its usage.
+ */
+struct sdhci_s3c_drv_data {
+       unsigned int    sdhci_quirks;
+};
+
 static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
 {
        return sdhci_priv(host);
                return UINT_MAX;
 
        /*
-        * Clock divider's step is different as 1 from that of host controller
-        * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
+        * If controller uses a non-standard clock division, find the best clock
+        * speed possible with selected clock source and skip the division.
         */
-       if (ourhost->pdata->clk_type) {
+       if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
                rate = clk_round_rate(clksrc, wanted);
                return wanted - rate;
        }
 static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
+       unsigned long timeout;
+       u16 clk = 0;
 
        /* don't bother if the clock is going off */
        if (clock == 0)
        clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
 
        host->clock = clock;
+
+       clk = SDHCI_CLOCK_INT_EN;
+       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+       /* Wait max 20 ms */
+       timeout = 20;
+       while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
+               & SDHCI_CLOCK_INT_STABLE)) {
+               if (timeout == 0) {
+                       printk(KERN_ERR "%s: Internal clock never "
+                               "stabilised.\n", mmc_hostname(host->mmc));
+                       return;
+               }
+               timeout--;
+               mdelay(1);
+       }
+
+       clk |= SDHCI_CLOCK_CARD_EN;
+       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 }
 
 /**
        }
 }
 
+static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
+                       struct platform_device *pdev)
+{
+       return (struct sdhci_s3c_drv_data *)
+                       platform_get_device_id(pdev)->driver_data;
+}
+
 static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
 {
        struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
+       struct sdhci_s3c_drv_data *drv_data;
        struct device *dev = &pdev->dev;
        struct sdhci_host *host;
        struct sdhci_s3c *sc;
                return PTR_ERR(host);
        }
 
+       drv_data = sdhci_s3c_get_driver_data(pdev);
        sc = sdhci_priv(host);
 
        sc->host = host;
        /* Setup quirks for the controller */
        host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
        host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
+       if (drv_data)
+               host->quirks |= drv_data->sdhci_quirks;
 
 #ifndef CONFIG_MMC_SDHCI_S3C_DMA
 
         * If controller does not have internal clock divider,
         * we can use overriding functions instead of default.
         */
-       if (pdata->clk_type) {
+       if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
                sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
                sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
                sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
 #define SDHCI_S3C_PMOPS NULL
 #endif
 
+#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
+static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
+       .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
+};
+#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
+#else
+#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL)
+#endif
+
+static struct platform_device_id sdhci_s3c_driver_ids[] = {
+       {
+               .name           = "s3c-sdhci",
+               .driver_data    = (kernel_ulong_t)NULL,
+       }, {
+               .name           = "exynos4-sdhci",
+               .driver_data    = EXYNOS4_SDHCI_DRV_DATA,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
+
 static struct platform_driver sdhci_s3c_driver = {
        .probe          = sdhci_s3c_probe,
        .remove         = __devexit_p(sdhci_s3c_remove),
+       .id_table       = sdhci_s3c_driver_ids,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c-sdhci",