aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKunihiko Hayashi <hayashi.kunihiko@socionext.com>2018-08-22 08:13:02 -0400
committerTejun Heo <tj@kernel.org>2018-08-22 11:08:27 -0400
commit9d2ab99573970838108add835442a03e23f8577b (patch)
treebb6c8eb9824775a21c550fe24a8f5d03c83b5cb4
parent16af2d65842d343c2f95733c3993a0b5baab08f9 (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt1
-rw-r--r--drivers/ata/ahci.h1
-rw-r--r--drivers/ata/libahci_platform.c31
-rw-r--r--include/linux/ahci_platform.h2
4 files changed, 30 insertions, 5 deletions
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index c760ecb81381..f4006d3c9fdf 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -30,6 +30,7 @@ compatible:
30Optional properties: 30Optional properties:
31- dma-coherent : Present if dma operations are coherent 31- dma-coherent : Present if dma operations are coherent
32- clocks : a list of phandle + clock specifier pairs 32- clocks : a list of phandle + clock specifier pairs
33- resets : a list of phandle + reset specifier pairs
33- target-supply : regulator for SATA target power 34- target-supply : regulator for SATA target power
34- phys : reference to the SATA PHY node 35- phys : reference to the SATA PHY node
35- phy-names : must be "sata-phy" 36- phy-names : must be "sata-phy"
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 1609ebab4e23..6a1515f0da40 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -350,6 +350,7 @@ struct ahci_host_priv {
350 u32 em_msg_type; /* EM message type */ 350 u32 em_msg_type; /* EM message type */
351 bool got_runtime_pm; /* Did we do pm_runtime_get? */ 351 bool got_runtime_pm; /* Did we do pm_runtime_get? */
352 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 352 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
353 struct reset_control *rsts; /* Optional */
353 struct regulator **target_pwrs; /* Optional */ 354 struct regulator **target_pwrs; /* Optional */
354 /* 355 /*
355 * If platform uses PHYs. There is a 1:1 relation between the port number and 356 * If platform uses PHYs. There is a 1:1 relation between the port number and
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 @@
25#include <linux/phy/phy.h> 25#include <linux/phy/phy.h>
26#include <linux/pm_runtime.h> 26#include <linux/pm_runtime.h>
27#include <linux/of_platform.h> 27#include <linux/of_platform.h>
28#include <linux/reset.h>
28#include "ahci.h" 29#include "ahci.h"
29 30
30static void ahci_host_stop(struct ata_host *host); 31static void ahci_host_stop(struct ata_host *host);
@@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
195 * following order: 196 * following order:
196 * 1) Regulator 197 * 1) Regulator
197 * 2) Clocks (through ahci_platform_enable_clks) 198 * 2) Clocks (through ahci_platform_enable_clks)
198 * 3) Phys 199 * 3) Resets
200 * 4) Phys
199 * 201 *
200 * If resource enabling fails at any point the previous enabled resources 202 * If resource enabling fails at any point the previous enabled resources
201 * are disabled in reverse order. 203 * are disabled in reverse order.
@@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
215 if (rc) 217 if (rc)
216 goto disable_regulator; 218 goto disable_regulator;
217 219
218 rc = ahci_platform_enable_phys(hpriv); 220 rc = reset_control_deassert(hpriv->rsts);
219 if (rc) 221 if (rc)
220 goto disable_clks; 222 goto disable_clks;
221 223
224 rc = ahci_platform_enable_phys(hpriv);
225 if (rc)
226 goto disable_resets;
227
222 return 0; 228 return 0;
223 229
230disable_resets:
231 reset_control_assert(hpriv->rsts);
232
224disable_clks: 233disable_clks:
225 ahci_platform_disable_clks(hpriv); 234 ahci_platform_disable_clks(hpriv);
226 235
@@ -238,13 +247,16 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
238 * This function disables all ahci_platform managed resources in the 247 * This function disables all ahci_platform managed resources in the
239 * following order: 248 * following order:
240 * 1) Phys 249 * 1) Phys
241 * 2) Clocks (through ahci_platform_disable_clks) 250 * 2) Resets
242 * 3) Regulator 251 * 3) Clocks (through ahci_platform_disable_clks)
252 * 4) Regulator
243 */ 253 */
244void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) 254void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
245{ 255{
246 ahci_platform_disable_phys(hpriv); 256 ahci_platform_disable_phys(hpriv);
247 257
258 reset_control_assert(hpriv->rsts);
259
248 ahci_platform_disable_clks(hpriv); 260 ahci_platform_disable_clks(hpriv);
249 261
250 ahci_platform_disable_regulators(hpriv); 262 ahci_platform_disable_regulators(hpriv);
@@ -341,7 +353,8 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
341 * 2) regulator for controlling the targets power (optional) 353 * 2) regulator for controlling the targets power (optional)
342 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, 354 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
343 * or for non devicetree enabled platforms a single clock 355 * or for non devicetree enabled platforms a single clock
344 * 4) phys (optional) 356 * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
357 * 5) phys (optional)
345 * 358 *
346 * RETURNS: 359 * RETURNS:
347 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value 360 * 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,
395 hpriv->clks[i] = clk; 408 hpriv->clks[i] = clk;
396 } 409 }
397 410
411 if (flags & AHCI_PLATFORM_GET_RESETS) {
412 hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
413 if (IS_ERR(hpriv->rsts)) {
414 rc = PTR_ERR(hpriv->rsts);
415 goto err_out;
416 }
417 }
418
398 hpriv->nports = child_nodes = of_get_child_count(dev->of_node); 419 hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
399 420
400 /* 421 /*
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 6490be1f8a16..eaedca5fe6fc 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -43,4 +43,6 @@ int ahci_platform_resume_host(struct device *dev);
43int ahci_platform_suspend(struct device *dev); 43int ahci_platform_suspend(struct device *dev);
44int ahci_platform_resume(struct device *dev); 44int ahci_platform_resume(struct device *dev);
45 45
46#define AHCI_PLATFORM_GET_RESETS 0x01
47
46#endif /* _AHCI_PLATFORM_H */ 48#endif /* _AHCI_PLATFORM_H */