static int mv_platform_probe()

in sata_mv.c [4042:4203]


static int mv_platform_probe(struct platform_device *pdev)
{
	const struct mv_sata_platform_data *mv_platform_data;
	const struct mbus_dram_target_info *dram;
	const struct ata_port_info *ppi[] =
	    { &mv_port_info[chip_soc], NULL };
	struct ata_host *host;
	struct mv_host_priv *hpriv;
	struct resource *res;
	int n_ports = 0, irq = 0;
	int rc;
	int port;

	ata_print_version_once(&pdev->dev, DRV_VERSION);

	/*
	 * Simple resource validation ..
	 */
	if (unlikely(pdev->num_resources != 2)) {
		dev_err(&pdev->dev, "invalid number of resources\n");
		return -EINVAL;
	}

	/*
	 * Get the register base first
	 */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL)
		return -EINVAL;

	/* allocate host */
	if (pdev->dev.of_node) {
		rc = of_property_read_u32(pdev->dev.of_node, "nr-ports",
					   &n_ports);
		if (rc) {
			dev_err(&pdev->dev,
				"error parsing nr-ports property: %d\n", rc);
			return rc;
		}

		if (n_ports <= 0) {
			dev_err(&pdev->dev, "nr-ports must be positive: %d\n",
				n_ports);
			return -EINVAL;
		}

		irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
	} else {
		mv_platform_data = dev_get_platdata(&pdev->dev);
		n_ports = mv_platform_data->n_ports;
		irq = platform_get_irq(pdev, 0);
	}
	if (irq < 0)
		return irq;
	if (!irq)
		return -EINVAL;

	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
	hpriv = devm_kzalloc(&pdev->dev, sizeof(*hpriv), GFP_KERNEL);

	if (!host || !hpriv)
		return -ENOMEM;
	hpriv->port_clks = devm_kcalloc(&pdev->dev,
					n_ports, sizeof(struct clk *),
					GFP_KERNEL);
	if (!hpriv->port_clks)
		return -ENOMEM;
	hpriv->port_phys = devm_kcalloc(&pdev->dev,
					n_ports, sizeof(struct phy *),
					GFP_KERNEL);
	if (!hpriv->port_phys)
		return -ENOMEM;
	host->private_data = hpriv;
	hpriv->board_idx = chip_soc;

	host->iomap = NULL;
	hpriv->base = devm_ioremap(&pdev->dev, res->start,
				   resource_size(res));
	if (!hpriv->base)
		return -ENOMEM;

	hpriv->base -= SATAHC0_REG_BASE;

	hpriv->clk = clk_get(&pdev->dev, NULL);
	if (IS_ERR(hpriv->clk))
		dev_notice(&pdev->dev, "cannot get optional clkdev\n");
	else
		clk_prepare_enable(hpriv->clk);

	for (port = 0; port < n_ports; port++) {
		char port_number[16];
		sprintf(port_number, "%d", port);
		hpriv->port_clks[port] = clk_get(&pdev->dev, port_number);
		if (!IS_ERR(hpriv->port_clks[port]))
			clk_prepare_enable(hpriv->port_clks[port]);

		sprintf(port_number, "port%d", port);
		hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev,
							       port_number);
		if (IS_ERR(hpriv->port_phys[port])) {
			rc = PTR_ERR(hpriv->port_phys[port]);
			hpriv->port_phys[port] = NULL;
			if (rc != -EPROBE_DEFER)
				dev_warn(&pdev->dev, "error getting phy %d", rc);

			/* Cleanup only the initialized ports */
			hpriv->n_ports = port;
			goto err;
		} else
			phy_power_on(hpriv->port_phys[port]);
	}

	/* All the ports have been initialized */
	hpriv->n_ports = n_ports;

	/*
	 * (Re-)program MBUS remapping windows if we are asked to.
	 */
	dram = mv_mbus_dram_info();
	if (dram)
		mv_conf_mbus_windows(hpriv, dram);

	rc = mv_create_dma_pools(hpriv, &pdev->dev);
	if (rc)
		goto err;

	/*
	 * To allow disk hotplug on Armada 370/XP SoCs, the PHY speed must be
	 * updated in the LP_PHY_CTL register.
	 */
	if (pdev->dev.of_node &&
		of_device_is_compatible(pdev->dev.of_node,
					"marvell,armada-370-sata"))
		hpriv->hp_flags |= MV_HP_FIX_LP_PHY_CTL;

	/* initialize adapter */
	rc = mv_init_host(host);
	if (rc)
		goto err;

	dev_info(&pdev->dev, "slots %u ports %d\n",
		 (unsigned)MV_MAX_Q_DEPTH, host->n_ports);

	rc = ata_host_activate(host, irq, mv_interrupt, IRQF_SHARED, &mv6_sht);
	if (!rc)
		return 0;

err:
	if (!IS_ERR(hpriv->clk)) {
		clk_disable_unprepare(hpriv->clk);
		clk_put(hpriv->clk);
	}
	for (port = 0; port < hpriv->n_ports; port++) {
		if (!IS_ERR(hpriv->port_clks[port])) {
			clk_disable_unprepare(hpriv->port_clks[port]);
			clk_put(hpriv->port_clks[port]);
		}
		phy_power_off(hpriv->port_phys[port]);
	}

	return rc;
}