diff options
author | Ohad Ben-Cohen <ohad@wizery.com> | 2010-10-02 07:54:11 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2010-10-23 09:11:18 -0400 |
commit | 40bba0c1ca83a370f749c8bc9afda71cf79ebd91 (patch) | |
tree | 1d2725b031284717468b22b90df59d5939506187 | |
parent | 81968561bd69536c82be7ee654b04c68cd3e1746 (diff) |
mmc: sdio: enable runtime PM for SDIO functions
Enable runtime PM for SDIO functions.
SDIO functions are initialized with a disabled runtime PM state,
and are set active (and their usage count is incremented)
only before potential drivers are probed.
SDIO function drivers that support runtime PM should call
pm_runtime_put_noidle() in their probe routine, and
pm_runtime_get_noresume() in their remove routine (very
similarly to PCI drivers).
In case a matching driver does not support runtime PM, power will
always be kept high (since the usage count is positive).
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Tested-by: Luciano Coelho <luciano.coelho@nokia.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/core/sdio.c | 5 | ||||
-rw-r--r-- | drivers/mmc/core/sdio_bus.c | 38 |
2 files changed, 40 insertions, 3 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 0dbd6fe66660..85561dde4c9d 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
@@ -734,6 +734,11 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr) | |||
734 | err = sdio_init_func(host->card, i + 1); | 734 | err = sdio_init_func(host->card, i + 1); |
735 | if (err) | 735 | if (err) |
736 | goto remove; | 736 | goto remove; |
737 | |||
738 | /* | ||
739 | * Enable Runtime PM for this func | ||
740 | */ | ||
741 | pm_runtime_enable(&card->sdio_func[i]->dev); | ||
737 | } | 742 | } |
738 | 743 | ||
739 | mmc_release_host(host); | 744 | mmc_release_host(host); |
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 256a968774a0..36374834fcff 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c | |||
@@ -126,21 +126,46 @@ static int sdio_bus_probe(struct device *dev) | |||
126 | if (!id) | 126 | if (!id) |
127 | return -ENODEV; | 127 | return -ENODEV; |
128 | 128 | ||
129 | /* Unbound SDIO functions are always suspended. | ||
130 | * During probe, the function is set active and the usage count | ||
131 | * is incremented. If the driver supports runtime PM, | ||
132 | * it should call pm_runtime_put_noidle() in its probe routine and | ||
133 | * pm_runtime_get_noresume() in its remove routine. | ||
134 | */ | ||
135 | ret = pm_runtime_get_sync(dev); | ||
136 | if (ret < 0) | ||
137 | goto out; | ||
138 | |||
129 | /* Set the default block size so the driver is sure it's something | 139 | /* Set the default block size so the driver is sure it's something |
130 | * sensible. */ | 140 | * sensible. */ |
131 | sdio_claim_host(func); | 141 | sdio_claim_host(func); |
132 | ret = sdio_set_block_size(func, 0); | 142 | ret = sdio_set_block_size(func, 0); |
133 | sdio_release_host(func); | 143 | sdio_release_host(func); |
134 | if (ret) | 144 | if (ret) |
135 | return ret; | 145 | goto disable_runtimepm; |
146 | |||
147 | ret = drv->probe(func, id); | ||
148 | if (ret) | ||
149 | goto disable_runtimepm; | ||
136 | 150 | ||
137 | return drv->probe(func, id); | 151 | return 0; |
152 | |||
153 | disable_runtimepm: | ||
154 | pm_runtime_put_noidle(dev); | ||
155 | out: | ||
156 | return ret; | ||
138 | } | 157 | } |
139 | 158 | ||
140 | static int sdio_bus_remove(struct device *dev) | 159 | static int sdio_bus_remove(struct device *dev) |
141 | { | 160 | { |
142 | struct sdio_driver *drv = to_sdio_driver(dev->driver); | 161 | struct sdio_driver *drv = to_sdio_driver(dev->driver); |
143 | struct sdio_func *func = dev_to_sdio_func(dev); | 162 | struct sdio_func *func = dev_to_sdio_func(dev); |
163 | int ret; | ||
164 | |||
165 | /* Make sure card is powered before invoking ->remove() */ | ||
166 | ret = pm_runtime_get_sync(dev); | ||
167 | if (ret < 0) | ||
168 | goto out; | ||
144 | 169 | ||
145 | drv->remove(func); | 170 | drv->remove(func); |
146 | 171 | ||
@@ -152,7 +177,14 @@ static int sdio_bus_remove(struct device *dev) | |||
152 | sdio_release_host(func); | 177 | sdio_release_host(func); |
153 | } | 178 | } |
154 | 179 | ||
155 | return 0; | 180 | /* First, undo the increment made directly above */ |
181 | pm_runtime_put_noidle(dev); | ||
182 | |||
183 | /* Then undo the runtime PM settings in sdio_bus_probe() */ | ||
184 | pm_runtime_put_noidle(dev); | ||
185 | |||
186 | out: | ||
187 | return ret; | ||
156 | } | 188 | } |
157 | 189 | ||
158 | #ifdef CONFIG_PM_RUNTIME | 190 | #ifdef CONFIG_PM_RUNTIME |