sunxi: driver refresh for 3.13
[openwrt/svn-archive/archive.git] / target / linux / sunxi / patches-3.13 / 160-7-ahci-platform-add-resource-helpers.patch
diff --git a/target/linux/sunxi/patches-3.13/160-7-ahci-platform-add-resource-helpers.patch b/target/linux/sunxi/patches-3.13/160-7-ahci-platform-add-resource-helpers.patch
new file mode 100644 (file)
index 0000000..0fdc87d
--- /dev/null
@@ -0,0 +1,211 @@
+From 05d5a60ae336c122e478cc002afccc880d462b3b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 20 Jan 2014 14:54:40 +0100
+Subject: [PATCH] ahci-platform: Add enable_ / disable_resources helper
+ functions
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ 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.8.5.5
+