summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libahci_platform.c
diff options
context:
space:
mode:
authorKunihiko Hayashi <hayashi.kunihiko@socionext.com>2018-08-22 21:13:02 +0900
committerTejun Heo <tj@kernel.org>2018-08-22 08:08:27 -0700
commit9d2ab99573970838108add835442a03e23f8577b (patch)
treebb6c8eb9824775a21c550fe24a8f5d03c83b5cb4 /drivers/ata/libahci_platform.c
parent16af2d65842d343c2f95733c3993a0b5baab08f9 (diff)
downloadtalos-op-linux-9d2ab99573970838108add835442a03e23f8577b.tar.gz
talos-op-linux-9d2ab99573970838108add835442a03e23f8577b.zip
ata: libahci_platform: add reset control support
Add support to get and control a list of resets for the device as optional and shared. These resets must be kept de-asserted until the device is enabled. This is specified as shared because some SoCs like UniPhier series have common reset controls with all ahci controller instances. However, according to Thierry's view, https://www.spinics.net/lists/linux-ide/msg55357.html some hardware-specific drivers already use their own resets, and the common reset make a path to occur double controls of resets. The ahci_platform_get_resources() can get and control the reset only when the second argument includes AHCI_PLATFORM_GET_RESETS bit. Suggested-by: Hans de Goede <hdegoede@redhat.com> Cc: Thierry Reding <thierry.reding@gmail.com> Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'drivers/ata/libahci_platform.c')
-rw-r--r--drivers/ata/libahci_platform.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 679f763410c0..c92c10d55374 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -25,6 +25,7 @@
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
#include <linux/of_platform.h>
+#include <linux/reset.h>
#include "ahci.h"
static void ahci_host_stop(struct ata_host *host);
@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
* following order:
* 1) Regulator
* 2) Clocks (through ahci_platform_enable_clks)
- * 3) Phys
+ * 3) Resets
+ * 4) Phys
*
* If resource enabling fails at any point the previous enabled resources
* are disabled in reverse order.
@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
if (rc)
goto disable_regulator;
- rc = ahci_platform_enable_phys(hpriv);
+ rc = reset_control_deassert(hpriv->rsts);
if (rc)
goto disable_clks;
+ rc = ahci_platform_enable_phys(hpriv);
+ if (rc)
+ goto disable_resets;
+
return 0;
+disable_resets:
+ reset_control_assert(hpriv->rsts);
+
disable_clks:
ahci_platform_disable_clks(hpriv);
@@ -238,13 +247,16 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
* This function disables all ahci_platform managed resources in the
* following order:
* 1) Phys
- * 2) Clocks (through ahci_platform_disable_clks)
- * 3) Regulator
+ * 2) Resets
+ * 3) Clocks (through ahci_platform_disable_clks)
+ * 4) Regulator
*/
void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
{
ahci_platform_disable_phys(hpriv);
+ reset_control_assert(hpriv->rsts);
+
ahci_platform_disable_clks(hpriv);
ahci_platform_disable_regulators(hpriv);
@@ -341,7 +353,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
* 2) regulator for controlling the targets power (optional)
* 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
* or for non devicetree enabled platforms a single clock
- * 4) phys (optional)
+ * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
+ * 5) phys (optional)
*
* RETURNS:
* The allocated ahci_host_priv on success, otherwise an ERR_PTR value
@@ -395,6 +408,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
hpriv->clks[i] = clk;
}
+ if (flags & AHCI_PLATFORM_GET_RESETS) {
+ hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
+ if (IS_ERR(hpriv->rsts)) {
+ rc = PTR_ERR(hpriv->rsts);
+ goto err_out;
+ }
+ }
+
hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
/*
OpenPOWER on IntegriCloud