Skip to content

Commit

Permalink
ata: libahci_platform: add reset control support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kunihiko Hayashi authored and Tejun Heo committed Aug 22, 2018
1 parent 16af2d6 commit 9d2ab99
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 5 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/ata/ahci-platform.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ compatible:
Optional properties:
- dma-coherent : Present if dma operations are coherent
- clocks : a list of phandle + clock specifier pairs
- resets : a list of phandle + reset specifier pairs
- target-supply : regulator for SATA target power
- phys : reference to the SATA PHY node
- phy-names : must be "sata-phy"
Expand Down
1 change: 1 addition & 0 deletions drivers/ata/ahci.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
bool got_runtime_pm; /* Did we do pm_runtime_get? */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
struct reset_control *rsts; /* Optional */
struct regulator **target_pwrs; /* Optional */
/*
* If platform uses PHYs. There is a 1:1 relation between the port number and
Expand Down
31 changes: 26 additions & 5 deletions drivers/ata/libahci_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);

/*
Expand Down
2 changes: 2 additions & 0 deletions include/linux/ahci_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ int ahci_platform_resume_host(struct device *dev);
int ahci_platform_suspend(struct device *dev);
int ahci_platform_resume(struct device *dev);

#define AHCI_PLATFORM_GET_RESETS 0x01

#endif /* _AHCI_PLATFORM_H */

0 comments on commit 9d2ab99

Please sign in to comment.