ata: ahci_platform: add support for AHCI controller regulator
authorCorentin Labbe <clabbe.montjoie@gmail.com>
Mon, 3 Sep 2018 10:01:54 +0000 (12:01 +0200)
committerJens Axboe <axboe@kernel.dk>
Mon, 3 Sep 2018 14:17:12 +0000 (08:17 -0600)
The SoC R40 AHCI controller need a regulator to work.
So this patch add a way to add an optional regulator on AHCI controller.

Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/ata/ahci.h
drivers/ata/libahci_platform.c

index 6a1515f..1415f10 100644 (file)
@@ -352,6 +352,7 @@ struct ahci_host_priv {
        struct clk              *clks[AHCI_MAX_CLKS]; /* Optional */
        struct reset_control    *rsts;          /* Optional */
        struct regulator        **target_pwrs;  /* Optional */
+       struct regulator        *ahci_regulator;/* Optional */
        /*
         * If platform uses PHYs. There is a 1:1 relation between the port number and
         * the PHY position in this array.
index 8ac2be8..e56f3a9 100644 (file)
@@ -139,7 +139,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
  * ahci_platform_enable_regulators - Enable regulators
  * @hpriv: host private area to store config values
  *
- * This function enables all the regulators found in
+ * This function enables all the regulators found in controller and
  * hpriv->target_pwrs, if any.  If a regulator fails to be enabled, it
  * disables all the regulators already enabled in reverse order and
  * returns an error.
@@ -151,6 +151,12 @@ int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
 {
        int rc, i;
 
+       if (hpriv->ahci_regulator) {
+               rc = regulator_enable(hpriv->ahci_regulator);
+               if (rc)
+                       return rc;
+       }
+
        for (i = 0; i < hpriv->nports; i++) {
                if (!hpriv->target_pwrs[i])
                        continue;
@@ -167,6 +173,8 @@ disable_target_pwrs:
                if (hpriv->target_pwrs[i])
                        regulator_disable(hpriv->target_pwrs[i]);
 
+       if (hpriv->ahci_regulator)
+               regulator_disable(hpriv->ahci_regulator);
        return rc;
 }
 EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
@@ -175,7 +183,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
  * ahci_platform_disable_regulators - Disable regulators
  * @hpriv: host private area to store config values
  *
- * This function disables all regulators found in hpriv->target_pwrs.
+ * This function disables all regulators found in hpriv->target_pwrs and
+ * AHCI controller.
  */
 void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
 {
@@ -186,6 +195,9 @@ void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
                        continue;
                regulator_disable(hpriv->target_pwrs[i]);
        }
+
+       if (hpriv->ahci_regulator)
+               regulator_disable(hpriv->ahci_regulator);
 }
 EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
 /**
@@ -351,6 +363,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
  *
  * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
  * 2) regulator for controlling the targets power (optional)
+ *    regulator for controlling the AHCI controller (optional)
  * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
  *    or for non devicetree enabled platforms a single clock
  * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional)
@@ -408,6 +421,15 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
                hpriv->clks[i] = clk;
        }
 
+       hpriv->ahci_regulator = devm_regulator_get_optional(dev, "ahci");
+       if (IS_ERR(hpriv->ahci_regulator)) {
+               rc = PTR_ERR(hpriv->ahci_regulator);
+               if (rc == -EPROBE_DEFER)
+                       goto err_out;
+               rc = 0;
+               hpriv->ahci_regulator = NULL;
+       }
+
        if (flags & AHCI_PLATFORM_GET_RESETS) {
                hpriv->rsts = devm_reset_control_array_get_optional_shared(dev);
                if (IS_ERR(hpriv->rsts)) {