static int sdhci_arasan_probe()

in host/sdhci-of-arasan.c [1567:1729]


static int sdhci_arasan_probe(struct platform_device *pdev)
{
	int ret;
	struct device_node *node;
	struct clk *clk_xin;
	struct sdhci_host *host;
	struct sdhci_pltfm_host *pltfm_host;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	struct sdhci_arasan_data *sdhci_arasan;
	const struct sdhci_arasan_of_data *data;

	data = of_device_get_match_data(dev);
	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*sdhci_arasan));

	if (IS_ERR(host))
		return PTR_ERR(host);

	pltfm_host = sdhci_priv(host);
	sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
	sdhci_arasan->host = host;

	sdhci_arasan->soc_ctl_map = data->soc_ctl_map;
	sdhci_arasan->clk_ops = data->clk_ops;

	node = of_parse_phandle(np, "arasan,soc-ctl-syscon", 0);
	if (node) {
		sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node);
		of_node_put(node);

		if (IS_ERR(sdhci_arasan->soc_ctl_base)) {
			ret = dev_err_probe(dev,
					    PTR_ERR(sdhci_arasan->soc_ctl_base),
					    "Can't get syscon\n");
			goto err_pltfm_free;
		}
	}

	sdhci_get_of_property(pdev);

	sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb");
	if (IS_ERR(sdhci_arasan->clk_ahb)) {
		ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb),
				    "clk_ahb clock not found.\n");
		goto err_pltfm_free;
	}

	clk_xin = devm_clk_get(dev, "clk_xin");
	if (IS_ERR(clk_xin)) {
		ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n");
		goto err_pltfm_free;
	}

	ret = clk_prepare_enable(sdhci_arasan->clk_ahb);
	if (ret) {
		dev_err(dev, "Unable to enable AHB clock.\n");
		goto err_pltfm_free;
	}

	/* If clock-frequency property is set, use the provided value */
	if (pltfm_host->clock &&
	    pltfm_host->clock != clk_get_rate(clk_xin)) {
		ret = clk_set_rate(clk_xin, pltfm_host->clock);
		if (ret) {
			dev_err(&pdev->dev, "Failed to set SD clock rate\n");
			goto clk_dis_ahb;
		}
	}

	ret = clk_prepare_enable(clk_xin);
	if (ret) {
		dev_err(dev, "Unable to enable SD clock.\n");
		goto clk_dis_ahb;
	}

	if (of_property_read_bool(np, "xlnx,fails-without-test-cd"))
		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_FORCE_CDTEST;

	if (of_property_read_bool(np, "xlnx,int-clock-stable-broken"))
		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_UNSTABLE;

	pltfm_host->clk = clk_xin;

	if (of_device_is_compatible(np, "rockchip,rk3399-sdhci-5.1"))
		sdhci_arasan_update_clockmultiplier(host, 0x0);

	if (of_device_is_compatible(np, "intel,keembay-sdhci-5.1-emmc") ||
	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sd") ||
	    of_device_is_compatible(np, "intel,keembay-sdhci-5.1-sdio") ||
	    of_device_is_compatible(np, "intel,thunderbay-sdhci-5.1")) {
		sdhci_arasan_update_clockmultiplier(host, 0x0);
		sdhci_arasan_update_support64b(host, 0x0);

		host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
	}

	sdhci_arasan_update_baseclkfreq(host);

	ret = sdhci_arasan_register_sdclk(sdhci_arasan, clk_xin, dev);
	if (ret)
		goto clk_disable_all;

	if (of_device_is_compatible(np, "xlnx,zynqmp-8.9a")) {
		host->mmc_host_ops.execute_tuning =
			arasan_zynqmp_execute_tuning;

		sdhci_arasan->quirks |= SDHCI_ARASAN_QUIRK_CLOCK_25_BROKEN;
		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
	}

	arasan_dt_parse_clk_phases(dev, &sdhci_arasan->clk_data);

	ret = mmc_of_parse(host->mmc);
	if (ret) {
		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
		goto unreg_clk;
	}

	sdhci_arasan->phy = ERR_PTR(-ENODEV);
	if (of_device_is_compatible(np, "arasan,sdhci-5.1")) {
		sdhci_arasan->phy = devm_phy_get(dev, "phy_arasan");
		if (IS_ERR(sdhci_arasan->phy)) {
			ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->phy),
					    "No phy for arasan,sdhci-5.1.\n");
			goto unreg_clk;
		}

		ret = phy_init(sdhci_arasan->phy);
		if (ret < 0) {
			dev_err(dev, "phy_init err.\n");
			goto unreg_clk;
		}

		host->mmc_host_ops.hs400_enhanced_strobe =
					sdhci_arasan_hs400_enhanced_strobe;
		host->mmc_host_ops.start_signal_voltage_switch =
					sdhci_arasan_voltage_switch;
		sdhci_arasan->has_cqe = true;
		host->mmc->caps2 |= MMC_CAP2_CQE;

		if (!of_property_read_bool(np, "disable-cqe-dcmd"))
			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
	}

	ret = sdhci_arasan_add_host(sdhci_arasan);
	if (ret)
		goto err_add_host;

	return 0;

err_add_host:
	if (!IS_ERR(sdhci_arasan->phy))
		phy_exit(sdhci_arasan->phy);
unreg_clk:
	sdhci_arasan_unregister_sdclk(dev);
clk_disable_all:
	clk_disable_unprepare(clk_xin);
clk_dis_ahb:
	clk_disable_unprepare(sdhci_arasan->clk_ahb);
err_pltfm_free:
	sdhci_pltfm_free(pdev);
	return ret;
}