mmc: tmio: add callbacks to enable-update and disable the interface clock
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Wed, 20 Jun 2012 17:10:31 +0000 (19:10 +0200)
committerChris Ball <cjb@laptop.org>
Sat, 21 Jul 2012 04:02:10 +0000 (00:02 -0400)
Every time the clock is enabled after possibly being disabled, we have
to re-read its frequency and update our configuration.

Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/tmio_mmc_pio.c
include/linux/mfd/tmio.h

index 4318c1a74ba0fe257d93c3bfe850f05bdc79666f..c6c0334a20e1e7cc0b387d4bb3359110ac9da857 100644 (file)
@@ -752,6 +752,22 @@ fail:
        mmc_request_done(mmc, mrq);
 }
 
+static int tmio_mmc_clk_update(struct mmc_host *mmc)
+{
+       struct tmio_mmc_host *host = mmc_priv(mmc);
+       struct tmio_mmc_data *pdata = host->pdata;
+       int ret;
+
+       if (!pdata->clk_enable)
+               return -ENOTSUPP;
+
+       ret = pdata->clk_enable(host->pdev, &mmc->f_max);
+       if (!ret)
+               mmc->f_min = mmc->f_max / 512;
+
+       return ret;
+}
+
 /* Set MMC clock / power.
  * Note: This controller uses a simple divider scheme therefore it cannot
  * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@@ -798,6 +814,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
         */
        if (ios->power_mode == MMC_POWER_ON && ios->clock) {
                if (!host->power) {
+                       tmio_mmc_clk_update(mmc);
                        pm_runtime_get_sync(dev);
                        host->power = true;
                }
@@ -811,9 +828,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
                        host->set_pwr(host->pdev, 0);
                if (host->power) {
+                       struct tmio_mmc_data *pdata = host->pdata;
                        tmio_mmc_clk_stop(host);
                        host->power = false;
                        pm_runtime_put(dev);
+                       if (pdata->clk_disable)
+                               pdata->clk_disable(host->pdev);
                }
        }
 
@@ -907,8 +927,6 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
 
        mmc->ops = &tmio_mmc_ops;
        mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
-       mmc->f_max = pdata->hclk;
-       mmc->f_min = mmc->f_max / 512;
        mmc->max_segs = 32;
        mmc->max_blk_size = 512;
        mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
@@ -930,6 +948,11 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (ret < 0)
                goto pm_disable;
 
+       if (tmio_mmc_clk_update(mmc) < 0) {
+               mmc->f_max = pdata->hclk;
+               mmc->f_min = mmc->f_max / 512;
+       }
+
        /*
         * There are 4 different scenarios for the card detection:
         *  1) an external gpio irq handles the cd (best for power savings)
@@ -975,7 +998,13 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
        /* See if we also get DMA */
        tmio_mmc_request_dma(_host, pdata);
 
-       mmc_add_host(mmc);
+       ret = mmc_add_host(mmc);
+       if (pdata->clk_disable)
+               pdata->clk_disable(pdev);
+       if (ret < 0) {
+               tmio_mmc_host_remove(_host);
+               return ret;
+       }
 
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
index f5171dbf8850c5c036e2e431ade03382bbe21983..b332c4c7857bcab2bd232179e200754f1a8596a5 100644 (file)
@@ -110,6 +110,9 @@ struct tmio_mmc_data {
        void (*set_clk_div)(struct platform_device *host, int state);
        int (*get_cd)(struct platform_device *host);
        int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+       /* clock management callbacks */
+       int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
+       void (*clk_disable)(struct platform_device *pdev);
 };
 
 /*