ahci-platform: "Library-ise" suspend / resume functionality

Split suspend / resume code into host suspend / resume functionality and
resource enable / disabling phases, and export the new suspend_ / resume_host
functions.

tj: Minor comment formatting updates.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
Hans de Goede 2014-02-22 16:53:35 +01:00 committed by Tejun Heo
parent 23b07d4cb3
commit 648cb6fd83
2 changed files with 87 additions and 15 deletions

View File

@ -432,14 +432,23 @@ static void ahci_host_stop(struct ata_host *host)
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int ahci_suspend(struct device *dev) /**
* ahci_platform_suspend_host - Suspend an ahci-platform host
* @dev: device pointer for the host
*
* This function does all the usual steps needed to suspend an
* ahci-platform host, note any necessary resources (ie clks, phy, etc.)
* must be disabled after calling this.
*
* RETURNS:
* 0 on success otherwise a negative error code
*/
int ahci_platform_suspend_host(struct device *dev)
{ {
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio; void __iomem *mmio = hpriv->mmio;
u32 ctl; u32 ctl;
int rc;
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
dev_err(dev, "firmware update required for suspend/resume\n"); dev_err(dev, "firmware update required for suspend/resume\n");
@ -456,7 +465,58 @@ static int ahci_suspend(struct device *dev)
writel(ctl, mmio + HOST_CTL); writel(ctl, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */ readl(mmio + HOST_CTL); /* flush */
rc = ata_host_suspend(host, PMSG_SUSPEND); return ata_host_suspend(host, PMSG_SUSPEND);
}
EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
/**
* ahci_platform_resume_host - Resume an ahci-platform host
* @dev: device pointer for the host
*
* This function does all the usual steps needed to resume an ahci-platform
* host, note any necessary resources (ie clks, phy, etc.) must be
* initialized / enabled before calling this.
*
* RETURNS:
* 0 on success otherwise a negative error code
*/
int ahci_platform_resume_host(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
int rc;
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
return rc;
ahci_init_controller(host);
}
ata_host_resume(host);
return 0;
}
EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
/**
* ahci_platform_suspend - Suspend an ahci-platform device
* @dev: the platform device to suspend
*
* This function suspends the host associated with the device, followed by
* disabling all the resources of the device.
*
* RETURNS:
* 0 on success otherwise a negative error code
*/
int ahci_platform_suspend(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
int rc;
rc = ahci_platform_suspend_host(dev);
if (rc) if (rc)
return rc; return rc;
@ -467,8 +527,19 @@ static int ahci_suspend(struct device *dev)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(ahci_platform_suspend);
static int ahci_resume(struct device *dev) /**
* ahci_platform_resume - Resume an ahci-platform device
* @dev: the platform device to resume
*
* This function enables all the resources of the device followed by
* resuming the host associated with the device.
*
* RETURNS:
* 0 on success otherwise a negative error code
*/
int ahci_platform_resume(struct device *dev)
{ {
struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
@ -485,15 +556,9 @@ static int ahci_resume(struct device *dev)
goto disable_resources; goto disable_resources;
} }
if (dev->power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_platform_resume_host(dev);
rc = ahci_reset_controller(host); if (rc)
if (rc) goto disable_resources;
goto disable_resources;
ahci_init_controller(host);
}
ata_host_resume(host);
return 0; return 0;
@ -502,9 +567,11 @@ disable_resources:
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(ahci_platform_resume);
#endif #endif
static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume); static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
ahci_platform_resume);
static const struct of_device_id ahci_of_match[] = { static const struct of_device_id ahci_of_match[] = {
{ .compatible = "snps,spear-ahci", }, { .compatible = "snps,spear-ahci", },

View File

@ -50,4 +50,9 @@ int ahci_platform_init_host(struct platform_device *pdev,
unsigned int force_port_map, unsigned int force_port_map,
unsigned int mask_port_map); unsigned int mask_port_map);
int ahci_platform_suspend_host(struct device *dev);
int ahci_platform_resume_host(struct device *dev);
int ahci_platform_suspend(struct device *dev);
int ahci_platform_resume(struct device *dev);
#endif /* _AHCI_PLATFORM_H */ #endif /* _AHCI_PLATFORM_H */