diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2013-06-06 10:35:44 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-06-06 11:48:04 -0400 |
commit | e83b7a8acc420923cbe8a30901d9eb60677f54fb (patch) | |
tree | 27784dc589543f97678574af7c529c0b6c473b2d | |
parent | 19f1ba51c79f133aec3ce558b8292e3b081363f3 (diff) |
mmc: tmio: fix unbalanced power-on calls with clock-gating enabled
With MMC clock gating enabled the MMC core currently calls MMC host driver's
.set_ios() method with .power_mode == MMC_POWER_ON and the clock value set
either to 0 or to the target rate. The tmio MMC driver then wrongly
translates the latter calls to card slot power-on requests, even when the
slot already was on. This patch fixes the driver to avoid needlessly
incrementing power-supplying regulator's use count.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski+renesas@gmail.com>
Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/tmio_mmc.h | 20 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc_pio.c | 27 |
2 files changed, 35 insertions, 12 deletions
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 759d8f4f130c..86fd21e00099 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h | |||
@@ -40,6 +40,22 @@ | |||
40 | 40 | ||
41 | struct tmio_mmc_data; | 41 | struct tmio_mmc_data; |
42 | 42 | ||
43 | /* | ||
44 | * We differentiate between the following 3 power states: | ||
45 | * 1. card slot powered off, controller stopped. This is used, when either there | ||
46 | * is no card in the slot, or the card really has to be powered down. | ||
47 | * 2. card slot powered on, controller stopped. This is used, when a card is in | ||
48 | * the slot, but no activity is currently taking place. This is a power- | ||
49 | * saving mode with card-state preserved. This state can be entered, e.g. | ||
50 | * when MMC clock-gating is used. | ||
51 | * 3. card slot powered on, controller running. This is the actual active state. | ||
52 | */ | ||
53 | enum tmio_mmc_power { | ||
54 | TMIO_MMC_OFF_STOP, /* card power off, controller stopped */ | ||
55 | TMIO_MMC_ON_STOP, /* card power on, controller stopped */ | ||
56 | TMIO_MMC_ON_RUN, /* card power on, controller running */ | ||
57 | }; | ||
58 | |||
43 | struct tmio_mmc_host { | 59 | struct tmio_mmc_host { |
44 | void __iomem *ctl; | 60 | void __iomem *ctl; |
45 | unsigned long bus_shift; | 61 | unsigned long bus_shift; |
@@ -48,8 +64,8 @@ struct tmio_mmc_host { | |||
48 | struct mmc_data *data; | 64 | struct mmc_data *data; |
49 | struct mmc_host *mmc; | 65 | struct mmc_host *mmc; |
50 | 66 | ||
51 | /* Controller power state */ | 67 | /* Controller and card power state */ |
52 | bool power; | 68 | enum tmio_mmc_power power; |
53 | 69 | ||
54 | /* Callbacks for clock / power control */ | 70 | /* Callbacks for clock / power control */ |
55 | void (*set_pwr)(struct platform_device *host, int state); | 71 | void (*set_pwr)(struct platform_device *host, int state); |
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 435cc4d2520f..67d96428e62a 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c | |||
@@ -859,7 +859,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
859 | * is kept positive, so no suspending actually takes place. | 859 | * is kept positive, so no suspending actually takes place. |
860 | */ | 860 | */ |
861 | if (ios->power_mode == MMC_POWER_ON && ios->clock) { | 861 | if (ios->power_mode == MMC_POWER_ON && ios->clock) { |
862 | if (!host->power) { | 862 | if (host->power != TMIO_MMC_ON_RUN) { |
863 | tmio_mmc_clk_update(mmc); | 863 | tmio_mmc_clk_update(mmc); |
864 | pm_runtime_get_sync(dev); | 864 | pm_runtime_get_sync(dev); |
865 | if (host->resuming) { | 865 | if (host->resuming) { |
@@ -868,27 +868,34 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
868 | } | 868 | } |
869 | } | 869 | } |
870 | tmio_mmc_set_clock(host, ios->clock); | 870 | tmio_mmc_set_clock(host, ios->clock); |
871 | if (!host->power) { | 871 | if (host->power == TMIO_MMC_OFF_STOP) |
872 | /* power up SD card and the bus */ | 872 | /* power up SD card and the bus */ |
873 | tmio_mmc_power_on(host, ios->vdd); | 873 | tmio_mmc_power_on(host, ios->vdd); |
874 | host->power = true; | 874 | host->power = TMIO_MMC_ON_RUN; |
875 | } | ||
876 | /* start bus clock */ | 875 | /* start bus clock */ |
877 | tmio_mmc_clk_start(host); | 876 | tmio_mmc_clk_start(host); |
878 | } else if (ios->power_mode != MMC_POWER_UP) { | 877 | } else if (ios->power_mode != MMC_POWER_UP) { |
879 | if (host->power) { | 878 | struct tmio_mmc_data *pdata = host->pdata; |
880 | struct tmio_mmc_data *pdata = host->pdata; | 879 | unsigned int old_power = host->power; |
881 | if (ios->power_mode == MMC_POWER_OFF) | 880 | |
881 | if (old_power != TMIO_MMC_OFF_STOP) { | ||
882 | if (ios->power_mode == MMC_POWER_OFF) { | ||
882 | tmio_mmc_power_off(host); | 883 | tmio_mmc_power_off(host); |
884 | host->power = TMIO_MMC_OFF_STOP; | ||
885 | } else { | ||
886 | host->power = TMIO_MMC_ON_STOP; | ||
887 | } | ||
888 | } | ||
889 | |||
890 | if (old_power == TMIO_MMC_ON_RUN) { | ||
883 | tmio_mmc_clk_stop(host); | 891 | tmio_mmc_clk_stop(host); |
884 | host->power = false; | ||
885 | pm_runtime_put(dev); | 892 | pm_runtime_put(dev); |
886 | if (pdata->clk_disable) | 893 | if (pdata->clk_disable) |
887 | pdata->clk_disable(host->pdev); | 894 | pdata->clk_disable(host->pdev); |
888 | } | 895 | } |
889 | } | 896 | } |
890 | 897 | ||
891 | if (host->power) { | 898 | if (host->power != TMIO_MMC_OFF_STOP) { |
892 | switch (ios->bus_width) { | 899 | switch (ios->bus_width) { |
893 | case MMC_BUS_WIDTH_1: | 900 | case MMC_BUS_WIDTH_1: |
894 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); | 901 | sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0); |
@@ -1029,7 +1036,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, | |||
1029 | mmc->caps & MMC_CAP_NONREMOVABLE || | 1036 | mmc->caps & MMC_CAP_NONREMOVABLE || |
1030 | mmc->slot.cd_irq >= 0); | 1037 | mmc->slot.cd_irq >= 0); |
1031 | 1038 | ||
1032 | _host->power = false; | 1039 | _host->power = TMIO_MMC_OFF_STOP; |
1033 | pm_runtime_enable(&pdev->dev); | 1040 | pm_runtime_enable(&pdev->dev); |
1034 | ret = pm_runtime_resume(&pdev->dev); | 1041 | ret = pm_runtime_resume(&pdev->dev); |
1035 | if (ret < 0) | 1042 | if (ret < 0) |