aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/ahci_platform.c97
-rw-r--r--include/linux/ahci_platform.h5
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
435static 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 */
446int 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}
470EXPORT_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 */
483int 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}
500EXPORT_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 */
512int 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}
530EXPORT_SYMBOL_GPL(ahci_platform_suspend);
470 531
471static 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 */
542int 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}
570EXPORT_SYMBOL_GPL(ahci_platform_resume);
505#endif 571#endif
506 572
507static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); 573static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
574 ahci_platform_resume);
508 575
509static const struct of_device_id ahci_of_match[] = { 576static 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
53int ahci_platform_suspend_host(struct device *dev);
54int ahci_platform_resume_host(struct device *dev);
55int ahci_platform_suspend(struct device *dev);
56int ahci_platform_resume(struct device *dev);
57
53#endif /* _AHCI_PLATFORM_H */ 58#endif /* _AHCI_PLATFORM_H */