On Sun, Oct 08, 2017 at 04:35:41AM +0000, Icenowy Zheng wrote: > Allwinner R40 SoC has an AHCI SATA controller like the one in A10/A20, > but with a reset control and two dedicated VDD pins for this controller > (one 1.2v and one 2.5v). > > Add support for it. > > Signed-off-by: Icenowy Zheng <icenowy@xxxxxxx> > --- > drivers/ata/ahci_sunxi.c | 118 +++++++++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 115 insertions(+), 3 deletions(-) > > diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c > index b26437430163..a650fd6508be 100644 > --- a/drivers/ata/ahci_sunxi.c > +++ b/drivers/ata/ahci_sunxi.c > @@ -25,6 +25,7 @@ > #include <linux/of_device.h> > #include <linux/platform_device.h> > #include <linux/regulator/consumer.h> > +#include <linux/reset.h> > #include "ahci.h" > > #define DRV_NAME "ahci-sunxi" > @@ -58,6 +59,19 @@ MODULE_PARM_DESC(enable_pmp, > #define AHCI_P0PHYCR 0x0178 > #define AHCI_P0PHYSR 0x017c > > +struct ahci_sunxi_quirks { > + bool has_reset; > + bool has_vdd1v2; > + bool has_vdd2v5; > +}; > + > +struct ahci_sunxi_data { > + const struct ahci_sunxi_quirks *quirks; > + struct reset_control *reset; > + struct regulator *vdd1v2; > + struct regulator *vdd2v5; > +}; > + > static void sunxi_clrbits(void __iomem *reg, u32 clr_val) > { > u32 reg_val; > @@ -179,17 +193,69 @@ static int ahci_sunxi_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > struct ahci_host_priv *hpriv; > + struct ahci_sunxi_data *data; > int rc; > > + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + data->quirks = of_device_get_match_data(dev); > + if (!data->quirks) > + return -EINVAL; > + > + if (data->quirks->has_reset) { > + data->reset = devm_reset_control_get(dev, NULL); > + if (IS_ERR(data->reset)) { > + dev_err(dev, "Failed to get reset\n"); > + return PTR_ERR(data->reset); > + } > + } > + > + if (data->quirks->has_vdd1v2) { > + data->vdd1v2 = devm_regulator_get(dev, "vdd1v2"); > + if (IS_ERR(data->vdd1v2)) { > + dev_err(dev, "Failed to get 1.2v VDD regulator\n"); > + return PTR_ERR(data->vdd1v2); > + } > + } > + > + if (data->quirks->has_vdd2v5) { > + data->vdd2v5 = devm_regulator_get(dev, "vdd2v5"); > + if (IS_ERR(data->vdd2v5)) { > + dev_err(dev, "Failed to get 2.5v VDD regulator\n"); > + return PTR_ERR(data->vdd2v5); > + } > + } > + > hpriv = ahci_platform_get_resources(pdev); > if (IS_ERR(hpriv)) > return PTR_ERR(hpriv); > > + hpriv->plat_data = data; > hpriv->start_engine = ahci_sunxi_start_engine; > > + if (data->quirks->has_vdd1v2) { > + rc = regulator_enable(data->vdd1v2); > + if (rc) > + return rc; > + } > + > + if (data->quirks->has_vdd2v5) { > + rc = regulator_enable(data->vdd2v5); > + if (rc) > + goto disable_vdd1v2; > + } > + > + if (data->quirks->has_reset) { > + rc = reset_control_deassert(data->reset); > + if (rc) > + goto disable_vdd2v5; > + } > + This should all be dealt with the AHCI platform layer, just like the clocks, and well some regulators already. Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
Attachment:
signature.asc
Description: PGP signature