于 2018年7月13日 GMT+08:00 下午7:03:03, Corentin Labbe <clabbe@xxxxxxxxxxxx> 写到: >The SoC R40 AHCI controller need a port regulator to work. In fact it should be a PHY regulator. >We cannot use the "target-supply" since it's not a target power >regulator. >So this patch add a way to add an optional port regulator. > >Signed-off-by: Corentin Labbe <clabbe@xxxxxxxxxxxx> >--- > drivers/ata/ahci.h | 1 + >drivers/ata/libahci_platform.c | 47 >+++++++++++++++++++++++++++++++++++++----- > 2 files changed, 43 insertions(+), 5 deletions(-) > >diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h >index 274c1885a5ad..716fd679dd3e 100644 >--- a/drivers/ata/ahci.h >+++ b/drivers/ata/ahci.h >@@ -352,6 +352,7 @@ struct ahci_host_priv { > bool got_runtime_pm; /* Did we do pm_runtime_get? */ > struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ > struct regulator **target_pwrs; /* Optional */ >+ struct regulator **port_regulators;/* Optional */ > struct regulator *ahci_regulator;/* Optional */ > struct reset_control *ahci_reset; /* Optional */ > /* >diff --git a/drivers/ata/libahci_platform.c >b/drivers/ata/libahci_platform.c >index 1199ba411c15..d7574b3e1f6a 100644 >--- a/drivers/ata/libahci_platform.c >+++ b/drivers/ata/libahci_platform.c >@@ -148,7 +148,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); > */ > int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv) > { >- int rc, i; >+ int rc, i, j; > > if (hpriv->ahci_regulator) { > rc = regulator_enable(hpriv->ahci_regulator); >@@ -164,9 +164,21 @@ int ahci_platform_enable_regulators(struct >ahci_host_priv *hpriv) > if (rc) > goto disable_target_pwrs; > } >+ for (j = 0; j < hpriv->nports; j++) { >+ if (!hpriv->port_regulators[j]) >+ continue; >+ >+ rc = regulator_enable(hpriv->port_regulators[j]); >+ if (rc) >+ goto disable_port_regulators; >+ } > > return 0; > >+disable_port_regulators: >+ while (--j >= 0) >+ if (hpriv->port_regulators[j]) >+ regulator_disable(hpriv->port_regulators[j]); > disable_target_pwrs: > while (--i >= 0) > if (hpriv->target_pwrs[i]) >@@ -190,9 +202,10 @@ void ahci_platform_disable_regulators(struct >ahci_host_priv *hpriv) > int i; > > for (i = 0; i < hpriv->nports; i++) { >- if (!hpriv->target_pwrs[i]) >- continue; >- regulator_disable(hpriv->target_pwrs[i]); >+ if (hpriv->target_pwrs[i]) >+ regulator_disable(hpriv->target_pwrs[i]); >+ if (hpriv->port_regulators[i]) >+ regulator_disable(hpriv->port_regulators[i]); > } > > if (hpriv->ahci_regulator) >@@ -291,9 +304,12 @@ static void ahci_platform_put_resources(struct >device *dev, void *res) > * SATA device itself. So we can't use devm for automatically > * releasing them. We have to do it manually here. > */ >- for (c = 0; c < hpriv->nports; c++) >+ for (c = 0; c < hpriv->nports; c++) { > if (hpriv->target_pwrs && hpriv->target_pwrs[c]) > regulator_put(hpriv->target_pwrs[c]); >+ if (hpriv->port_regulators && hpriv->port_regulators[c]) >+ regulator_put(hpriv->port_regulators[c]); >+ } > } > >static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 >port, >@@ -338,6 +354,7 @@ static int ahci_platform_get_regulator(struct >ahci_host_priv *hpriv, u32 port, > struct device *dev) > { > struct regulator *target_pwr; >+ struct regulator *port_regulator; > int rc = 0; > > target_pwr = regulator_get_optional(dev, "target"); >@@ -346,6 +363,21 @@ static int ahci_platform_get_regulator(struct >ahci_host_priv *hpriv, u32 port, > hpriv->target_pwrs[port] = target_pwr; > else > rc = PTR_ERR(target_pwr); >+ /* Only EPROBE_DEFER is important since it's an optional regulator */ >+ if (rc != -EPROBE_DEFER) >+ rc = 0; >+ else >+ return rc; >+ >+ port_regulator = regulator_get_optional(dev, "port"); >+ >+ if (!IS_ERR(port_regulator)) >+ hpriv->port_regulators[port] = port_regulator; >+ else >+ rc = PTR_ERR(port_regulator); >+ /* Only EPROBE_DEFER is important since it's an optional regulator */ >+ if (rc != -EPROBE_DEFER) >+ rc = 0; > > return rc; > } >@@ -454,6 +486,11 @@ struct ahci_host_priv >*ahci_platform_get_resources(struct platform_device *pdev) > rc = -ENOMEM; > goto err_out; > } >+ hpriv->port_regulators = devm_kcalloc(dev, hpriv->nports, >sizeof(*hpriv->port_regulators), GFP_KERNEL); >+ if (!hpriv->port_regulators) { >+ rc = -ENOMEM; >+ goto err_out; >+ } > > if (child_nodes) { > for_each_child_of_node(dev->of_node, child) { -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html