static int brcm_ahci_probe()

in ahci_brcm.c [434:545]


static int brcm_ahci_probe(struct platform_device *pdev)
{
	const struct of_device_id *of_id;
	struct device *dev = &pdev->dev;
	struct brcm_ahci_priv *priv;
	struct ahci_host_priv *hpriv;
	struct resource *res;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	of_id = of_match_node(ahci_of_match, pdev->dev.of_node);
	if (!of_id)
		return -ENODEV;

	priv->version = (enum brcm_ahci_version)of_id->data;
	priv->dev = dev;

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
	priv->top_ctrl = devm_ioremap_resource(dev, res);
	if (IS_ERR(priv->top_ctrl))
		return PTR_ERR(priv->top_ctrl);

	if (priv->version == BRCM_SATA_BCM7216) {
		priv->rcdev_rescal = devm_reset_control_get_optional_shared(
			&pdev->dev, "rescal");
		if (IS_ERR(priv->rcdev_rescal))
			return PTR_ERR(priv->rcdev_rescal);
	}
	priv->rcdev_ahci = devm_reset_control_get_optional(&pdev->dev, "ahci");
	if (IS_ERR(priv->rcdev_ahci))
		return PTR_ERR(priv->rcdev_ahci);

	hpriv = ahci_platform_get_resources(pdev, 0);
	if (IS_ERR(hpriv))
		return PTR_ERR(hpriv);

	hpriv->plat_data = priv;
	hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP | AHCI_HFLAG_NO_WRITE_TO_RO;

	switch (priv->version) {
	case BRCM_SATA_BCM7425:
		hpriv->flags |= AHCI_HFLAG_DELAY_ENGINE;
		fallthrough;
	case BRCM_SATA_NSP:
		hpriv->flags |= AHCI_HFLAG_NO_NCQ;
		priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
		break;
	default:
		break;
	}

	ret = reset_control_reset(priv->rcdev_rescal);
	if (ret)
		return ret;
	ret = reset_control_deassert(priv->rcdev_ahci);
	if (ret)
		return ret;

	ret = ahci_platform_enable_clks(hpriv);
	if (ret)
		goto out_reset;

	ret = ahci_platform_enable_regulators(hpriv);
	if (ret)
		goto out_disable_clks;

	/* Must be first so as to configure endianness including that
	 * of the standard AHCI register space.
	 */
	brcm_sata_init(priv);

	/* Initializes priv->port_mask which is used below */
	priv->port_mask = brcm_ahci_get_portmask(hpriv, priv);
	if (!priv->port_mask) {
		ret = -ENODEV;
		goto out_disable_regulators;
	}

	/* Must be done before ahci_platform_enable_phys() */
	brcm_sata_phys_enable(priv);

	brcm_sata_alpm_init(hpriv);

	ret = ahci_platform_enable_phys(hpriv);
	if (ret)
		goto out_disable_phys;

	ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
				      &ahci_platform_sht);
	if (ret)
		goto out_disable_platform_phys;

	dev_info(dev, "Broadcom AHCI SATA3 registered\n");

	return 0;

out_disable_platform_phys:
	ahci_platform_disable_phys(hpriv);
out_disable_phys:
	brcm_sata_phys_disable(priv);
out_disable_regulators:
	ahci_platform_disable_regulators(hpriv);
out_disable_clks:
	ahci_platform_disable_clks(hpriv);
out_reset:
	reset_control_assert(priv->rcdev_ahci);
	reset_control_rearm(priv->rcdev_rescal);
	return ret;
}