Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- drivers/ata/ahci_platform.c | 112 ++++++++++++++++++++++++++++-------------- include/linux/ahci_platform.h | 2 + 2 files changed, 77 insertions(+), 37 deletions(-) diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 907c076..6ebbc17 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -139,6 +139,68 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) } EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); +/** + * ahci_platform_enable_resources - Enable platform resources + * @hpriv: host private area to store config values + * + * This function enables all ahci_platform managed resources in + * the following order: + * 1) Regulator + * 2) Clocks (through ahci_platform_enable_clks) + * + * If resource enabling fails at any point the previous enabled + * resources are disabled in reverse order. + * + * LOCKING: + * None. + * + * RETURNS: + * 0 on success otherwise a negative error code + */ +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) +{ + int rc; + + if (hpriv->target_pwr) { + rc = regulator_enable(hpriv->target_pwr); + if (rc) + return rc; + } + + rc = ahci_platform_enable_clks(hpriv); + if (rc) + goto disable_regulator; + + return 0; + +disable_regulator: + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); + return rc; +} +EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); + +/** + * ahci_platform_disable_resources - Disable platform resources + * @hpriv: host private area to store config values + * + * This function disables all ahci_platform managed resources in + * the following order: + * 1) Clocks (through ahci_platform_disable_clks) + * 2) Regulator + * + * LOCKING: + * None. + */ +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) +{ + ahci_platform_disable_clks(hpriv); + + if (hpriv->target_pwr) + regulator_disable(hpriv->target_pwr); +} +EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); + static void ahci_put_clks(struct ahci_host_priv *hpriv) { int c; @@ -221,15 +283,9 @@ static int ahci_probe(struct platform_device *pdev) hpriv->clks[i] = clk; } - if (hpriv->target_pwr) { - rc = regulator_enable(hpriv->target_pwr); - if (rc) - goto free_clk; - } - - rc = ahci_enable_clks(dev, hpriv); + rc = ahci_platform_enable_resources(hpriv); if (rc) - goto disable_regulator; + goto free_clk; /* * Some platforms might need to prepare for mmio region access, @@ -240,7 +296,7 @@ static int ahci_probe(struct platform_device *pdev) if (pdata && pdata->init) { rc = pdata->init(dev, hpriv->mmio); if (rc) - goto disable_unprepare_clk; + goto disable_resources; } ahci_save_initial_config(dev, hpriv, @@ -310,11 +366,8 @@ static int ahci_probe(struct platform_device *pdev) pdata_exit: if (pdata && pdata->exit) pdata->exit(dev); -disable_unprepare_clk: - ahci_disable_clks(hpriv); -disable_regulator: - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); +disable_resources: + ahci_platform_disable_resources(hpriv); free_clk: ahci_put_clks(hpriv); return rc; @@ -329,11 +382,8 @@ static void ahci_host_stop(struct ata_host *host) if (pdata && pdata->exit) pdata->exit(dev); - ahci_disable_clks(hpriv); + ahci_platform_disable_resources(hpriv); ahci_put_clks(hpriv); - - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); } #ifdef CONFIG_PM_SLEEP @@ -368,10 +418,7 @@ static int ahci_suspend(struct device *dev) if (pdata && pdata->suspend) return pdata->suspend(dev); - ahci_disable_clks(hpriv); - - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); + ahci_platform_disable_resources(hpriv); return 0; } @@ -383,26 +430,20 @@ static int ahci_resume(struct device *dev) struct ahci_host_priv *hpriv = host->private_data; int rc; - if (hpriv->target_pwr) { - rc = regulator_enable(hpriv->target_pwr); - if (rc) - return rc; - } - - rc = ahci_enable_clks(dev, hpriv); + rc = ahci_platform_enable_resources(hpriv); if (rc) - goto disable_regulator; + return rc; if (pdata && pdata->resume) { rc = pdata->resume(dev); if (rc) - goto disable_unprepare_clk; + goto disable_resources; } if (dev->power.power_state.event == PM_EVENT_SUSPEND) { rc = ahci_reset_controller(host); if (rc) - goto disable_unprepare_clk; + goto disable_resources; ahci_init_controller(host); } @@ -411,11 +452,8 @@ static int ahci_resume(struct device *dev) return 0; -disable_unprepare_clk: - ahci_disable_clks(hpriv); -disable_regulator: - if (hpriv->target_pwr) - regulator_disable(hpriv->target_pwr); +disable_resources: + ahci_platform_disable_resources(hpriv); return rc; } diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h index 769d065..b674b01 100644 --- a/include/linux/ahci_platform.h +++ b/include/linux/ahci_platform.h @@ -33,5 +33,7 @@ struct ahci_platform_data { int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv); #endif /* _AHCI_PLATFORM_H */ -- 1.9.0 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html