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;
}