diff options
-rw-r--r-- | drivers/amba/bus.c | 57 | ||||
-rw-r--r-- | drivers/spi/spi-pl022.c | 80 |
2 files changed, 102 insertions, 35 deletions
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index d74926e0939e..84bdaace56c8 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c | |||
@@ -365,6 +365,40 @@ static int amba_pm_restore_noirq(struct device *dev) | |||
365 | 365 | ||
366 | #endif /* !CONFIG_HIBERNATE_CALLBACKS */ | 366 | #endif /* !CONFIG_HIBERNATE_CALLBACKS */ |
367 | 367 | ||
368 | #ifdef CONFIG_PM_RUNTIME | ||
369 | /* | ||
370 | * Hooks to provide runtime PM of the pclk (bus clock). It is safe to | ||
371 | * enable/disable the bus clock at runtime PM suspend/resume as this | ||
372 | * does not result in loss of context. However, disabling vcore power | ||
373 | * would do, so we leave that to the driver. | ||
374 | */ | ||
375 | static int amba_pm_runtime_suspend(struct device *dev) | ||
376 | { | ||
377 | struct amba_device *pcdev = to_amba_device(dev); | ||
378 | int ret = pm_generic_runtime_suspend(dev); | ||
379 | |||
380 | if (ret == 0 && dev->driver) | ||
381 | clk_disable(pcdev->pclk); | ||
382 | |||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | static int amba_pm_runtime_resume(struct device *dev) | ||
387 | { | ||
388 | struct amba_device *pcdev = to_amba_device(dev); | ||
389 | int ret; | ||
390 | |||
391 | if (dev->driver) { | ||
392 | ret = clk_enable(pcdev->pclk); | ||
393 | /* Failure is probably fatal to the system, but... */ | ||
394 | if (ret) | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | return pm_generic_runtime_resume(dev); | ||
399 | } | ||
400 | #endif | ||
401 | |||
368 | #ifdef CONFIG_PM | 402 | #ifdef CONFIG_PM |
369 | 403 | ||
370 | static const struct dev_pm_ops amba_pm = { | 404 | static const struct dev_pm_ops amba_pm = { |
@@ -383,8 +417,8 @@ static const struct dev_pm_ops amba_pm = { | |||
383 | .poweroff_noirq = amba_pm_poweroff_noirq, | 417 | .poweroff_noirq = amba_pm_poweroff_noirq, |
384 | .restore_noirq = amba_pm_restore_noirq, | 418 | .restore_noirq = amba_pm_restore_noirq, |
385 | SET_RUNTIME_PM_OPS( | 419 | SET_RUNTIME_PM_OPS( |
386 | pm_generic_runtime_suspend, | 420 | amba_pm_runtime_suspend, |
387 | pm_generic_runtime_resume, | 421 | amba_pm_runtime_resume, |
388 | pm_generic_runtime_idle | 422 | pm_generic_runtime_idle |
389 | ) | 423 | ) |
390 | }; | 424 | }; |
@@ -494,10 +528,18 @@ static int amba_probe(struct device *dev) | |||
494 | if (ret) | 528 | if (ret) |
495 | break; | 529 | break; |
496 | 530 | ||
531 | pm_runtime_get_noresume(dev); | ||
532 | pm_runtime_set_active(dev); | ||
533 | pm_runtime_enable(dev); | ||
534 | |||
497 | ret = pcdrv->probe(pcdev, id); | 535 | ret = pcdrv->probe(pcdev, id); |
498 | if (ret == 0) | 536 | if (ret == 0) |
499 | break; | 537 | break; |
500 | 538 | ||
539 | pm_runtime_disable(dev); | ||
540 | pm_runtime_set_suspended(dev); | ||
541 | pm_runtime_put_noidle(dev); | ||
542 | |||
501 | amba_put_disable_pclk(pcdev); | 543 | amba_put_disable_pclk(pcdev); |
502 | amba_put_disable_vcore(pcdev); | 544 | amba_put_disable_vcore(pcdev); |
503 | } while (0); | 545 | } while (0); |
@@ -509,7 +551,16 @@ static int amba_remove(struct device *dev) | |||
509 | { | 551 | { |
510 | struct amba_device *pcdev = to_amba_device(dev); | 552 | struct amba_device *pcdev = to_amba_device(dev); |
511 | struct amba_driver *drv = to_amba_driver(dev->driver); | 553 | struct amba_driver *drv = to_amba_driver(dev->driver); |
512 | int ret = drv->remove(pcdev); | 554 | int ret; |
555 | |||
556 | pm_runtime_get_sync(dev); | ||
557 | ret = drv->remove(pcdev); | ||
558 | pm_runtime_put_noidle(dev); | ||
559 | |||
560 | /* Undo the runtime PM settings in amba_probe() */ | ||
561 | pm_runtime_disable(dev); | ||
562 | pm_runtime_set_suspended(dev); | ||
563 | pm_runtime_put_noidle(dev); | ||
513 | 564 | ||
514 | amba_put_disable_pclk(pcdev); | 565 | amba_put_disable_pclk(pcdev); |
515 | amba_put_disable_vcore(pcdev); | 566 | amba_put_disable_vcore(pcdev); |
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 730b4a37b823..078338f59481 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c | |||
@@ -515,9 +515,6 @@ static void giveback(struct pl022 *pl022) | |||
515 | if (msg->complete) | 515 | if (msg->complete) |
516 | msg->complete(msg->context); | 516 | msg->complete(msg->context); |
517 | /* This message is completed, so let's turn off the clocks & power */ | 517 | /* This message is completed, so let's turn off the clocks & power */ |
518 | clk_disable(pl022->clk); | ||
519 | amba_pclk_disable(pl022->adev); | ||
520 | amba_vcore_disable(pl022->adev); | ||
521 | pm_runtime_put(&pl022->adev->dev); | 518 | pm_runtime_put(&pl022->adev->dev); |
522 | } | 519 | } |
523 | 520 | ||
@@ -1545,9 +1542,6 @@ static void pump_messages(struct work_struct *work) | |||
1545 | * (poll/interrupt/DMA) | 1542 | * (poll/interrupt/DMA) |
1546 | */ | 1543 | */ |
1547 | pm_runtime_get_sync(&pl022->adev->dev); | 1544 | pm_runtime_get_sync(&pl022->adev->dev); |
1548 | amba_vcore_enable(pl022->adev); | ||
1549 | amba_pclk_enable(pl022->adev); | ||
1550 | clk_enable(pl022->clk); | ||
1551 | restore_state(pl022); | 1545 | restore_state(pl022); |
1552 | flush(pl022); | 1546 | flush(pl022); |
1553 | 1547 | ||
@@ -2186,8 +2180,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2186 | } | 2180 | } |
2187 | printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", | 2181 | printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", |
2188 | adev->res.start, pl022->virtbase); | 2182 | adev->res.start, pl022->virtbase); |
2189 | pm_runtime_enable(dev); | ||
2190 | pm_runtime_resume(dev); | ||
2191 | 2183 | ||
2192 | pl022->clk = clk_get(&adev->dev, NULL); | 2184 | pl022->clk = clk_get(&adev->dev, NULL); |
2193 | if (IS_ERR(pl022->clk)) { | 2185 | if (IS_ERR(pl022->clk)) { |
@@ -2195,7 +2187,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2195 | dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); | 2187 | dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); |
2196 | goto err_no_clk; | 2188 | goto err_no_clk; |
2197 | } | 2189 | } |
2198 | |||
2199 | /* Disable SSP */ | 2190 | /* Disable SSP */ |
2200 | writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), | 2191 | writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), |
2201 | SSP_CR1(pl022->virtbase)); | 2192 | SSP_CR1(pl022->virtbase)); |
@@ -2235,12 +2226,9 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2235 | goto err_spi_register; | 2226 | goto err_spi_register; |
2236 | } | 2227 | } |
2237 | dev_dbg(dev, "probe succeeded\n"); | 2228 | dev_dbg(dev, "probe succeeded\n"); |
2238 | /* | 2229 | |
2239 | * Disable the silicon block pclk and any voltage domain and just | 2230 | /* let runtime pm put suspend */ |
2240 | * power it up and clock it when it's needed | 2231 | pm_runtime_put(dev); |
2241 | */ | ||
2242 | amba_pclk_disable(adev); | ||
2243 | amba_vcore_disable(adev); | ||
2244 | return 0; | 2232 | return 0; |
2245 | 2233 | ||
2246 | err_spi_register: | 2234 | err_spi_register: |
@@ -2249,7 +2237,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) | |||
2249 | destroy_queue(pl022); | 2237 | destroy_queue(pl022); |
2250 | pl022_dma_remove(pl022); | 2238 | pl022_dma_remove(pl022); |
2251 | free_irq(adev->irq[0], pl022); | 2239 | free_irq(adev->irq[0], pl022); |
2252 | pm_runtime_disable(&adev->dev); | ||
2253 | err_no_irq: | 2240 | err_no_irq: |
2254 | clk_put(pl022->clk); | 2241 | clk_put(pl022->clk); |
2255 | err_no_clk: | 2242 | err_no_clk: |
@@ -2271,6 +2258,12 @@ pl022_remove(struct amba_device *adev) | |||
2271 | if (!pl022) | 2258 | if (!pl022) |
2272 | return 0; | 2259 | return 0; |
2273 | 2260 | ||
2261 | /* | ||
2262 | * undo pm_runtime_put() in probe. I assume that we're not | ||
2263 | * accessing the primecell here. | ||
2264 | */ | ||
2265 | pm_runtime_get_noresume(&adev->dev); | ||
2266 | |||
2274 | /* Remove the queue */ | 2267 | /* Remove the queue */ |
2275 | if (destroy_queue(pl022) != 0) | 2268 | if (destroy_queue(pl022) != 0) |
2276 | dev_err(&adev->dev, "queue remove failed\n"); | 2269 | dev_err(&adev->dev, "queue remove failed\n"); |
@@ -2288,10 +2281,10 @@ pl022_remove(struct amba_device *adev) | |||
2288 | return 0; | 2281 | return 0; |
2289 | } | 2282 | } |
2290 | 2283 | ||
2291 | #ifdef CONFIG_PM | 2284 | #ifdef CONFIG_SUSPEND |
2292 | static int pl022_suspend(struct amba_device *adev, pm_message_t state) | 2285 | static int pl011_suspend(struct device *dev) |
2293 | { | 2286 | { |
2294 | struct pl022 *pl022 = amba_get_drvdata(adev); | 2287 | struct pl022 *pl022 = dev_get_drvdata(dev); |
2295 | int status = 0; | 2288 | int status = 0; |
2296 | 2289 | ||
2297 | status = stop_queue(pl022); | 2290 | status = stop_queue(pl022); |
@@ -2300,34 +2293,58 @@ static int pl022_suspend(struct amba_device *adev, pm_message_t state) | |||
2300 | return status; | 2293 | return status; |
2301 | } | 2294 | } |
2302 | 2295 | ||
2303 | amba_vcore_enable(adev); | 2296 | amba_vcore_enable(pl022->adev); |
2304 | amba_pclk_enable(adev); | 2297 | amba_pclk_enable(pl022->adev); |
2305 | load_ssp_default_config(pl022); | 2298 | load_ssp_default_config(pl022); |
2306 | amba_pclk_disable(adev); | 2299 | amba_pclk_disable(pl022->adev); |
2307 | amba_vcore_disable(adev); | 2300 | amba_vcore_disable(pl022->adev); |
2308 | dev_dbg(&adev->dev, "suspended\n"); | 2301 | dev_dbg(&adev->dev, "suspended\n"); |
2309 | return 0; | 2302 | return 0; |
2310 | } | 2303 | } |
2311 | 2304 | ||
2312 | static int pl022_resume(struct amba_device *adev) | 2305 | static int pl022_resume(struct device *dev) |
2313 | { | 2306 | { |
2314 | struct pl022 *pl022 = amba_get_drvdata(adev); | 2307 | struct pl022 *pl022 = dev_get_drvdata(dev); |
2315 | int status = 0; | 2308 | int status = 0; |
2316 | 2309 | ||
2317 | /* Start the queue running */ | 2310 | /* Start the queue running */ |
2318 | status = start_queue(pl022); | 2311 | status = start_queue(pl022); |
2319 | if (status) | 2312 | if (status) |
2320 | dev_err(&adev->dev, "problem starting queue (%d)\n", status); | 2313 | dev_err(dev, "problem starting queue (%d)\n", status); |
2321 | else | 2314 | else |
2322 | dev_dbg(&adev->dev, "resumed\n"); | 2315 | dev_dbg(dev, "resumed\n"); |
2323 | 2316 | ||
2324 | return status; | 2317 | return status; |
2325 | } | 2318 | } |
2326 | #else | ||
2327 | #define pl022_suspend NULL | ||
2328 | #define pl022_resume NULL | ||
2329 | #endif /* CONFIG_PM */ | 2319 | #endif /* CONFIG_PM */ |
2330 | 2320 | ||
2321 | #ifdef CONFIG_PM_RUNTIME | ||
2322 | static int pl022_runtime_suspend(struct device *dev) | ||
2323 | { | ||
2324 | struct pl022 *pl022 = dev_get_drvdata(dev); | ||
2325 | |||
2326 | clk_disable(pl022->clk); | ||
2327 | amba_vcore_disable(pl022->adev); | ||
2328 | |||
2329 | return 0; | ||
2330 | } | ||
2331 | |||
2332 | static int pl022_runtime_resume(struct device *dev) | ||
2333 | { | ||
2334 | struct pl022 *pl022 = dev_get_drvdata(dev); | ||
2335 | |||
2336 | amba_vcore_enable(pl022->adev); | ||
2337 | clk_enable(pl022->clk); | ||
2338 | |||
2339 | return 0; | ||
2340 | } | ||
2341 | #endif | ||
2342 | |||
2343 | static const struct dev_pm_ops pl022_dev_pm_ops = { | ||
2344 | SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) | ||
2345 | SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) | ||
2346 | }; | ||
2347 | |||
2331 | static struct vendor_data vendor_arm = { | 2348 | static struct vendor_data vendor_arm = { |
2332 | .fifodepth = 8, | 2349 | .fifodepth = 8, |
2333 | .max_bpw = 16, | 2350 | .max_bpw = 16, |
@@ -2407,12 +2424,11 @@ static struct amba_id pl022_ids[] = { | |||
2407 | static struct amba_driver pl022_driver = { | 2424 | static struct amba_driver pl022_driver = { |
2408 | .drv = { | 2425 | .drv = { |
2409 | .name = "ssp-pl022", | 2426 | .name = "ssp-pl022", |
2427 | .pm = &pl022_dev_pm_ops, | ||
2410 | }, | 2428 | }, |
2411 | .id_table = pl022_ids, | 2429 | .id_table = pl022_ids, |
2412 | .probe = pl022_probe, | 2430 | .probe = pl022_probe, |
2413 | .remove = __devexit_p(pl022_remove), | 2431 | .remove = __devexit_p(pl022_remove), |
2414 | .suspend = pl022_suspend, | ||
2415 | .resume = pl022_resume, | ||
2416 | }; | 2432 | }; |
2417 | 2433 | ||
2418 | 2434 | ||