diff options
-rw-r--r-- | drivers/ata/ahci_platform.c | 97 | ||||
-rw-r--r-- | include/linux/ahci_platform.h | 5 |
2 files changed, 87 insertions, 15 deletions
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 19e9eaafb1f2..01f7bbe65572 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c | |||
@@ -432,14 +432,23 @@ static void ahci_host_stop(struct ata_host *host) | |||
432 | } | 432 | } |
433 | 433 | ||
434 | #ifdef CONFIG_PM_SLEEP | 434 | #ifdef CONFIG_PM_SLEEP |
435 | static int ahci_suspend(struct device *dev) | 435 | /** |
436 | * ahci_platform_suspend_host - Suspend an ahci-platform host | ||
437 | * @dev: device pointer for the host | ||
438 | * | ||
439 | * This function does all the usual steps needed to suspend an | ||
440 | * ahci-platform host, note any necessary resources (ie clks, phy, etc.) | ||
441 | * must be disabled after calling this. | ||
442 | * | ||
443 | * RETURNS: | ||
444 | * 0 on success otherwise a negative error code | ||
445 | */ | ||
446 | int ahci_platform_suspend_host(struct device *dev) | ||
436 | { | 447 | { |
437 | struct ahci_platform_data *pdata = dev_get_platdata(dev); | ||
438 | struct ata_host *host = dev_get_drvdata(dev); | 448 | struct ata_host *host = dev_get_drvdata(dev); |
439 | struct ahci_host_priv *hpriv = host->private_data; | 449 | struct ahci_host_priv *hpriv = host->private_data; |
440 | void __iomem *mmio = hpriv->mmio; | 450 | void __iomem *mmio = hpriv->mmio; |
441 | u32 ctl; | 451 | u32 ctl; |
442 | int rc; | ||
443 | 452 | ||
444 | if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { | 453 | if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { |
445 | dev_err(dev, "firmware update required for suspend/resume\n"); | 454 | dev_err(dev, "firmware update required for suspend/resume\n"); |
@@ -456,7 +465,58 @@ static int ahci_suspend(struct device *dev) | |||
456 | writel(ctl, mmio + HOST_CTL); | 465 | writel(ctl, mmio + HOST_CTL); |
457 | readl(mmio + HOST_CTL); /* flush */ | 466 | readl(mmio + HOST_CTL); /* flush */ |
458 | 467 | ||
459 | rc = ata_host_suspend(host, PMSG_SUSPEND); | 468 | return ata_host_suspend(host, PMSG_SUSPEND); |
469 | } | ||
470 | EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); | ||
471 | |||
472 | /** | ||
473 | * ahci_platform_resume_host - Resume an ahci-platform host | ||
474 | * @dev: device pointer for the host | ||
475 | * | ||
476 | * This function does all the usual steps needed to resume an ahci-platform | ||
477 | * host, note any necessary resources (ie clks, phy, etc.) must be | ||
478 | * initialized / enabled before calling this. | ||
479 | * | ||
480 | * RETURNS: | ||
481 | * 0 on success otherwise a negative error code | ||
482 | */ | ||
483 | int ahci_platform_resume_host(struct device *dev) | ||
484 | { | ||
485 | struct ata_host *host = dev_get_drvdata(dev); | ||
486 | int rc; | ||
487 | |||
488 | if (dev->power.power_state.event == PM_EVENT_SUSPEND) { | ||
489 | rc = ahci_reset_controller(host); | ||
490 | if (rc) | ||
491 | return rc; | ||
492 | |||
493 | ahci_init_controller(host); | ||
494 | } | ||
495 | |||
496 | ata_host_resume(host); | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | EXPORT_SYMBOL_GPL(ahci_platform_resume_host); | ||
501 | |||
502 | /** | ||
503 | * ahci_platform_suspend - Suspend an ahci-platform device | ||
504 | * @dev: the platform device to suspend | ||
505 | * | ||
506 | * This function suspends the host associated with the device, followed by | ||
507 | * disabling all the resources of the device. | ||
508 | * | ||
509 | * RETURNS: | ||
510 | * 0 on success otherwise a negative error code | ||
511 | */ | ||
512 | int ahci_platform_suspend(struct device *dev) | ||
513 | { | ||
514 | struct ahci_platform_data *pdata = dev_get_platdata(dev); | ||
515 | struct ata_host *host = dev_get_drvdata(dev); | ||
516 | struct ahci_host_priv *hpriv = host->private_data; | ||
517 | int rc; | ||
518 | |||
519 | rc = ahci_platform_suspend_host(dev); | ||
460 | if (rc) | 520 | if (rc) |
461 | return rc; | 521 | return rc; |
462 | 522 | ||
@@ -467,8 +527,19 @@ static int ahci_suspend(struct device *dev) | |||
467 | 527 | ||
468 | return 0; | 528 | return 0; |
469 | } | 529 | } |
530 | EXPORT_SYMBOL_GPL(ahci_platform_suspend); | ||
470 | 531 | ||
471 | static int ahci_resume(struct device *dev) | 532 | /** |
533 | * ahci_platform_resume - Resume an ahci-platform device | ||
534 | * @dev: the platform device to resume | ||
535 | * | ||
536 | * This function enables all the resources of the device followed by | ||
537 | * resuming the host associated with the device. | ||
538 | * | ||
539 | * RETURNS: | ||
540 | * 0 on success otherwise a negative error code | ||
541 | */ | ||
542 | int ahci_platform_resume(struct device *dev) | ||
472 | { | 543 | { |
473 | struct ahci_platform_data *pdata = dev_get_platdata(dev); | 544 | struct ahci_platform_data *pdata = dev_get_platdata(dev); |
474 | struct ata_host *host = dev_get_drvdata(dev); | 545 | struct ata_host *host = dev_get_drvdata(dev); |
@@ -485,15 +556,9 @@ static int ahci_resume(struct device *dev) | |||
485 | goto disable_resources; | 556 | goto disable_resources; |
486 | } | 557 | } |
487 | 558 | ||
488 | if (dev->power.power_state.event == PM_EVENT_SUSPEND) { | 559 | rc = ahci_platform_resume_host(dev); |
489 | rc = ahci_reset_controller(host); | 560 | if (rc) |
490 | if (rc) | 561 | goto disable_resources; |
491 | goto disable_resources; | ||
492 | |||
493 | ahci_init_controller(host); | ||
494 | } | ||
495 | |||
496 | ata_host_resume(host); | ||
497 | 562 | ||
498 | return 0; | 563 | return 0; |
499 | 564 | ||
@@ -502,9 +567,11 @@ disable_resources: | |||
502 | 567 | ||
503 | return rc; | 568 | return rc; |
504 | } | 569 | } |
570 | EXPORT_SYMBOL_GPL(ahci_platform_resume); | ||
505 | #endif | 571 | #endif |
506 | 572 | ||
507 | static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); | 573 | static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, |
574 | ahci_platform_resume); | ||
508 | 575 | ||
509 | static const struct of_device_id ahci_of_match[] = { | 576 | static const struct of_device_id ahci_of_match[] = { |
510 | { .compatible = "snps,spear-ahci", }, | 577 | { .compatible = "snps,spear-ahci", }, |
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index b80c51c20f76..542f2686eb1d 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h | |||
@@ -50,4 +50,9 @@ int ahci_platform_init_host(struct platform_device *pdev, | |||
50 | unsigned int force_port_map, | 50 | unsigned int force_port_map, |
51 | unsigned int mask_port_map); | 51 | unsigned int mask_port_map); |
52 | 52 | ||
53 | int ahci_platform_suspend_host(struct device *dev); | ||
54 | int ahci_platform_resume_host(struct device *dev); | ||
55 | int ahci_platform_suspend(struct device *dev); | ||
56 | int ahci_platform_resume(struct device *dev); | ||
57 | |||
53 | #endif /* _AHCI_PLATFORM_H */ | 58 | #endif /* _AHCI_PLATFORM_H */ |