diff options
author | Patrice Chotard <patrice.chotard@stericsson.com> | 2012-10-17 08:27:24 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-10-17 09:14:25 -0400 |
commit | d8f18420c552de6d38e5464074133e0e9730abcd (patch) | |
tree | 2fa18925654779319b0ca85cbdda36ecba6fc1bc /drivers/spi | |
parent | 4964a26df72c4a82e56c6b40818648d54bde93cc (diff) |
spi/pl022: add IDLE state pin management
This commit allow to put pins in IDLE state in
runtime_suspend and in SLEEP state in suspend, corresponding
to defined semantics in <linux/pinctrl/pinctrl-state.h>.
To do this, just add a boolean parameter runtime
to pl022_resume_resources/pl022_suspend_resources which
indicates if it's called from PM_RUNTIME callbacks or not.
Signed-off-by: Patrice Chotard <patrice.chotard@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-pl022.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index c220c2346276..7e3c4166e8f8 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c | |||
@@ -371,6 +371,7 @@ struct pl022 { | |||
371 | /* Two optional pin states - default & sleep */ | 371 | /* Two optional pin states - default & sleep */ |
372 | struct pinctrl *pinctrl; | 372 | struct pinctrl *pinctrl; |
373 | struct pinctrl_state *pins_default; | 373 | struct pinctrl_state *pins_default; |
374 | struct pinctrl_state *pins_idle; | ||
374 | struct pinctrl_state *pins_sleep; | 375 | struct pinctrl_state *pins_sleep; |
375 | struct spi_master *master; | 376 | struct spi_master *master; |
376 | struct pl022_ssp_controller *master_info; | 377 | struct pl022_ssp_controller *master_info; |
@@ -2116,6 +2117,11 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2116 | } else | 2117 | } else |
2117 | dev_err(dev, "could not get default pinstate\n"); | 2118 | dev_err(dev, "could not get default pinstate\n"); |
2118 | 2119 | ||
2120 | pl022->pins_idle = pinctrl_lookup_state(pl022->pinctrl, | ||
2121 | PINCTRL_STATE_IDLE); | ||
2122 | if (IS_ERR(pl022->pins_idle)) | ||
2123 | dev_dbg(dev, "could not get idle pinstate\n"); | ||
2124 | |||
2119 | pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl, | 2125 | pl022->pins_sleep = pinctrl_lookup_state(pl022->pinctrl, |
2120 | PINCTRL_STATE_SLEEP); | 2126 | PINCTRL_STATE_SLEEP); |
2121 | if (IS_ERR(pl022->pins_sleep)) | 2127 | if (IS_ERR(pl022->pins_sleep)) |
@@ -2305,35 +2311,47 @@ pl022_remove(struct amba_device *adev) | |||
2305 | * the runtime counterparts to handle external resources like | 2311 | * the runtime counterparts to handle external resources like |
2306 | * clocks, pins and regulators when going to sleep. | 2312 | * clocks, pins and regulators when going to sleep. |
2307 | */ | 2313 | */ |
2308 | static void pl022_suspend_resources(struct pl022 *pl022) | 2314 | static void pl022_suspend_resources(struct pl022 *pl022, bool runtime) |
2309 | { | 2315 | { |
2310 | int ret; | 2316 | int ret; |
2317 | struct pinctrl_state *pins_state; | ||
2311 | 2318 | ||
2312 | clk_disable(pl022->clk); | 2319 | clk_disable(pl022->clk); |
2313 | 2320 | ||
2321 | pins_state = runtime ? pl022->pins_idle : pl022->pins_sleep; | ||
2314 | /* Optionally let pins go into sleep states */ | 2322 | /* Optionally let pins go into sleep states */ |
2315 | if (!IS_ERR(pl022->pins_sleep)) { | 2323 | if (!IS_ERR(pins_state)) { |
2316 | ret = pinctrl_select_state(pl022->pinctrl, | 2324 | ret = pinctrl_select_state(pl022->pinctrl, pins_state); |
2317 | pl022->pins_sleep); | ||
2318 | if (ret) | 2325 | if (ret) |
2319 | dev_err(&pl022->adev->dev, | 2326 | dev_err(&pl022->adev->dev, "could not set %s pins\n", |
2320 | "could not set pins to sleep state\n"); | 2327 | runtime ? "idle" : "sleep"); |
2321 | } | 2328 | } |
2322 | } | 2329 | } |
2323 | 2330 | ||
2324 | static void pl022_resume_resources(struct pl022 *pl022) | 2331 | static void pl022_resume_resources(struct pl022 *pl022, bool runtime) |
2325 | { | 2332 | { |
2326 | int ret; | 2333 | int ret; |
2327 | 2334 | ||
2328 | /* Optionaly enable pins to be muxed in and configured */ | 2335 | /* Optionaly enable pins to be muxed in and configured */ |
2336 | /* First go to the default state */ | ||
2329 | if (!IS_ERR(pl022->pins_default)) { | 2337 | if (!IS_ERR(pl022->pins_default)) { |
2330 | ret = pinctrl_select_state(pl022->pinctrl, | 2338 | ret = pinctrl_select_state(pl022->pinctrl, pl022->pins_default); |
2331 | pl022->pins_default); | ||
2332 | if (ret) | 2339 | if (ret) |
2333 | dev_err(&pl022->adev->dev, | 2340 | dev_err(&pl022->adev->dev, |
2334 | "could not set default pins\n"); | 2341 | "could not set default pins\n"); |
2335 | } | 2342 | } |
2336 | 2343 | ||
2344 | if (!runtime) { | ||
2345 | /* Then let's idle the pins until the next transfer happens */ | ||
2346 | if (!IS_ERR(pl022->pins_idle)) { | ||
2347 | ret = pinctrl_select_state(pl022->pinctrl, | ||
2348 | pl022->pins_idle); | ||
2349 | if (ret) | ||
2350 | dev_err(&pl022->adev->dev, | ||
2351 | "could not set idle pins\n"); | ||
2352 | } | ||
2353 | } | ||
2354 | |||
2337 | clk_enable(pl022->clk); | 2355 | clk_enable(pl022->clk); |
2338 | } | 2356 | } |
2339 | #endif | 2357 | #endif |
@@ -2351,7 +2369,7 @@ static int pl022_suspend(struct device *dev) | |||
2351 | } | 2369 | } |
2352 | 2370 | ||
2353 | pm_runtime_get_sync(dev); | 2371 | pm_runtime_get_sync(dev); |
2354 | pl022_suspend_resources(pl022); | 2372 | pl022_suspend_resources(pl022, false); |
2355 | 2373 | ||
2356 | dev_dbg(dev, "suspended\n"); | 2374 | dev_dbg(dev, "suspended\n"); |
2357 | return 0; | 2375 | return 0; |
@@ -2362,7 +2380,7 @@ static int pl022_resume(struct device *dev) | |||
2362 | struct pl022 *pl022 = dev_get_drvdata(dev); | 2380 | struct pl022 *pl022 = dev_get_drvdata(dev); |
2363 | int ret; | 2381 | int ret; |
2364 | 2382 | ||
2365 | pl022_resume_resources(pl022); | 2383 | pl022_resume_resources(pl022, false); |
2366 | pm_runtime_put(dev); | 2384 | pm_runtime_put(dev); |
2367 | 2385 | ||
2368 | /* Start the queue running */ | 2386 | /* Start the queue running */ |
@@ -2381,7 +2399,7 @@ static int pl022_runtime_suspend(struct device *dev) | |||
2381 | { | 2399 | { |
2382 | struct pl022 *pl022 = dev_get_drvdata(dev); | 2400 | struct pl022 *pl022 = dev_get_drvdata(dev); |
2383 | 2401 | ||
2384 | pl022_suspend_resources(pl022); | 2402 | pl022_suspend_resources(pl022, true); |
2385 | return 0; | 2403 | return 0; |
2386 | } | 2404 | } |
2387 | 2405 | ||
@@ -2389,7 +2407,7 @@ static int pl022_runtime_resume(struct device *dev) | |||
2389 | { | 2407 | { |
2390 | struct pl022 *pl022 = dev_get_drvdata(dev); | 2408 | struct pl022 *pl022 = dev_get_drvdata(dev); |
2391 | 2409 | ||
2392 | pl022_resume_resources(pl022); | 2410 | pl022_resume_resources(pl022, true); |
2393 | return 0; | 2411 | return 0; |
2394 | } | 2412 | } |
2395 | #endif | 2413 | #endif |