All of lore.kernel.org
 help / color / mirror / Atom feed
From: Krzysztof Kozlowski <krzk@kernel.org>
To: dongxuyang@eswincomputing.com, ulf.hansson@linaro.org,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	linux-mmc@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, adrian.hunter@intel.com,
	p.zabel@pengutronix.de, shanchun1218@gmail.com
Cc: ningyu@eswincomputing.com, linmin@eswincomputing.com,
	xuxiang@eswincomputing.com
Subject: Re: [PATCH v1 2/2] sdhci: eswin: Add eic7700 sdhci driver
Date: Fri, 16 May 2025 15:17:37 +0200	[thread overview]
Message-ID: <15bbeaaf-6dcc-49ce-baff-03692fcb90a9@kernel.org> (raw)
In-Reply-To: <20250516091727.887-1-dongxuyang@eswincomputing.com>

On 16/05/2025 11:17, dongxuyang@eswincomputing.com wrote:
> +	if (of_property_read_u32(np, "#clock-cells", &num_clks) < 0)
> +		return 0;
> +
> +	ret = eswin_sdhci_sdio_register_sdcardclk(eswin_sdhci_sdio, clk_xin,
> +						  dev);
> +	if (ret)
> +		return ret;
> +
> +	if (num_clks) {
> +		ret = eswin_sdhci_sdio_register_sampleclk(eswin_sdhci_sdio,
> +							  clk_xin, dev);
> +		if (ret) {
> +			eswin_sdhci_sdio_unregister_sdclk(dev);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int eswin_sdhci_sdio_add_host(struct eswin_sdhci_data *eswin_sdhci_sdio)
> +{
> +	struct sdhci_host *host = eswin_sdhci_sdio->host;

Why do you have two probes for one driver?

> +	struct cqhci_host *cq_host;
> +	bool dma64;
> +	int ret;
> +
> +	if (!eswin_sdhci_sdio->has_cqe)
> +		return sdhci_add_host(host);
> +
> +	ret = sdhci_setup_host(host);
> +	if (ret)
> +		return ret;
> +
> +	cq_host = devm_kzalloc(host->mmc->parent, sizeof(*cq_host), GFP_KERNEL);
> +	if (!cq_host) {
> +		ret = -ENOMEM;
> +		goto cleanup;
> +	}
> +
> +	cq_host->mmio = host->ioaddr + ESWIN_SDHCI_SD_CQE_BASE_ADDR;
> +	cq_host->ops = &eswin_sdhci_sdio_cqhci_ops;
> +
> +	dma64 = host->flags & SDHCI_USE_64_BIT_DMA;
> +	if (dma64)
> +		cq_host->caps |= CQHCI_TASK_DESC_SZ_128;
> +
> +	ret = cqhci_init(cq_host, host->mmc, dma64);
> +	if (ret)
> +		goto cleanup;
> +
> +	ret = __sdhci_add_host(host);
> +	if (ret)
> +		goto cleanup;
> +
> +	return 0;
> +
> +cleanup:
> +	sdhci_cleanup_host(host);
> +	return ret;
> +}
> +
> +static int eswin_sdhci_sdio_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct clk *clk_xin;
> +	struct clk *clk_spll2_fout3;
> +	struct clk *clk_mux;
> +	struct sdhci_host *host;
> +	struct sdhci_pltfm_host *pltfm_host;
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct eswin_sdhci_data *eswin_sdhci_sdio;
> +	const struct eswin_sdhci_of_data *data;
> +	unsigned int val = 0;
> +
> +	data = of_device_get_match_data(dev);
> +	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*eswin_sdhci_sdio));
> +
> +	if (IS_ERR(host))
> +		return PTR_ERR(host);
> +
> +	pltfm_host = sdhci_priv(host);
> +	eswin_sdhci_sdio = sdhci_pltfm_priv(pltfm_host);
> +	eswin_sdhci_sdio->host = host;
> +	eswin_sdhci_sdio->has_cqe = false;
> +
> +	sdhci_get_of_property(pdev);
> +
> +	eswin_sdhci_sdio->clk_ops = data->clk_ops;
> +	eswin_sdhci_sdio->clk_ahb = devm_clk_get(dev, "clk_ahb");
> +	if (IS_ERR(eswin_sdhci_sdio->clk_ahb)) {
> +		ret = dev_err_probe(dev, PTR_ERR(eswin_sdhci_sdio->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;
> +	}
> +
> +	clk_spll2_fout3 = devm_clk_get(dev, "clk_spll2_fout3");
> +
> +	if (IS_ERR(clk_spll2_fout3)) {
> +		ret = dev_err_probe(dev, PTR_ERR(clk_spll2_fout3),
> +				    "clk_spll2_fout3 clock not found.\n");
> +		goto err_pltfm_free;
> +	}
> +
> +	if (of_device_is_compatible(np, "eswin,sdhci-sdio")) {
> +		clk_mux = devm_clk_get(dev, "clk_mux1_1");
> +		if (IS_ERR(clk_mux)) {
> +			ret = dev_err_probe(dev, PTR_ERR(clk_mux),
> +					    "clk_mux1_1 clock not found.\n");
> +			goto err_pltfm_free;
> +		}
> +		/*switch the core clk source*/
> +		clk_set_parent(clk_mux, clk_spll2_fout3);
> +	}
> +
> +	ret = clk_prepare_enable(eswin_sdhci_sdio->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;
> +	}
> +
> +	pltfm_host->clk = clk_xin;
> +	ret = eswin_sdhci_sdio_register_sdclk(eswin_sdhci_sdio, clk_xin, dev);
> +	if (ret)
> +		goto clk_disable_all;
> +
> +	ret = eswin_sdhci_reset_init(dev, eswin_sdhci_sdio);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to reset\n");
> +		goto clk_disable_all;
> +	}
> +
> +	eswin_sdhci_sdio->crg_regmap = syscon_regmap_lookup_by_phandle(
> +		pdev->dev.of_node, "eswin,syscrg_csr");
> +	if (IS_ERR(eswin_sdhci_sdio->crg_regmap)) {
> +		dev_dbg(&pdev->dev, "No syscrg_csr phandle specified\n");
> +		goto clk_disable_all;
> +	}
> +
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 1, &eswin_sdhci_sdio->crg_core_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_core_clk (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 2, &eswin_sdhci_sdio->crg_aclk_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_aclk_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 3, &eswin_sdhci_sdio->crg_cfg_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_cfg_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +
> +	eswin_sdhci_sdio->hsp_regmap = syscon_regmap_lookup_by_phandle(
> +		dev->of_node, "eswin,hsp_sp_csr");
> +	if (IS_ERR(eswin_sdhci_sdio->hsp_regmap)) {
> +		dev_dbg(dev, "No hsp_sp_csr phandle specified\n");
> +		goto clk_disable_all;
> +	}
> +
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,hsp_sp_csr",
> +					 2, &eswin_sdhci_sdio->hsp_int_status);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get hsp_int_status (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,hsp_sp_csr",
> +					 3, &eswin_sdhci_sdio->hsp_pwr_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get hsp_pwr_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +
> +	regmap_write(eswin_sdhci_sdio->hsp_regmap,
> +		     eswin_sdhci_sdio->hsp_int_status, MSHC_INT_CLK_STABLE);
> +	regmap_write(eswin_sdhci_sdio->hsp_regmap,
> +		     eswin_sdhci_sdio->hsp_pwr_ctrl, MSHC_HOST_VAL_STABLE);
> +
> +	if (!of_property_read_u32(dev->of_node, "delay_code", &val))
> +		eswin_sdhci_sdio->phy.delay_code = val;
> +
> +	if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val))
> +		eswin_sdhci_sdio->phy.drive_impedance =
> +			eswin_convert_drive_impedance_ohm(pdev, val);
> +
> +	if (of_property_read_bool(dev->of_node, "enable-cmd-pullup"))
> +		eswin_sdhci_sdio->phy.enable_cmd_pullup = ENABLE;
> +	else
> +		eswin_sdhci_sdio->phy.enable_cmd_pullup = DISABLE;
> +
> +	if (of_property_read_bool(dev->of_node, "enable-data-pullup"))
> +		eswin_sdhci_sdio->phy.enable_data_pullup = ENABLE;
> +	else
> +		eswin_sdhci_sdio->phy.enable_data_pullup = DISABLE;
> +
> +	eswin_sdhci_dt_parse_clk_phases(dev, &eswin_sdhci_sdio->clk_data);
> +	ret = mmc_of_parse(host->mmc);
> +	if (ret) {
> +		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
> +		goto unreg_clk;
> +	}
> +
> +	ret = eswin_sdhci_sdio_add_host(eswin_sdhci_sdio);
> +	if (ret)
> +		goto unreg_clk;
> +
> +	pm_runtime_set_active(&pdev->dev);
> +	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
> +	pm_runtime_use_autosuspend(&pdev->dev);
> +	pm_suspend_ignore_children(&pdev->dev, 1);
> +	pm_runtime_enable(&pdev->dev);
> +
> +	return 0;
> +
> +unreg_clk:
> +	eswin_sdhci_sdio_unregister_sdclk(dev);
> +clk_disable_all:
> +	clk_disable_unprepare(clk_xin);
> +clk_dis_ahb:
> +	clk_disable_unprepare(eswin_sdhci_sdio->clk_ahb);
> +err_pltfm_free:
> +	sdhci_pltfm_free(pdev);
> +	return ret;
> +}


....

> +
> +static int eswin_sdhci_probe(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct clk *clk_xin;
> +	struct sdhci_host *host;
> +	struct sdhci_pltfm_host *pltfm_host;
> +	struct device *dev = &pdev->dev;
> +	struct eswin_sdhci_data *eswin_sdhci;
> +	const struct eswin_sdhci_of_data *data;
> +	unsigned int val = 0;
> +
> +	data = of_device_get_match_data(dev);
> +	host = sdhci_pltfm_init(pdev, data->pdata, sizeof(*eswin_sdhci));
> +	if (IS_ERR(host))
> +		return PTR_ERR(host);
> +
> +	pltfm_host = sdhci_priv(host);
> +	eswin_sdhci = sdhci_pltfm_priv(pltfm_host);
> +	eswin_sdhci->host = host;
> +	eswin_sdhci->clk_ops = data->clk_ops;
> +
> +	eswin_sdhci->clk_ahb = devm_clk_get(dev, "clk_ahb");

Undocumented ABI

Anyway, drop clk_ in property name.

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

drop clk_ in property name.

> +	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(eswin_sdhci->clk_ahb);

So just use devm_clk_get_enabled.

> +	if (ret) {
> +		dev_err(dev, "Unable to enable AHB clock.\n");
> +		goto err_pltfm_free;
> +	}
> +
> +	ret = clk_prepare_enable(clk_xin);
> +	if (ret) {
> +		dev_err(dev, "Unable to enable SD clock.\n");
> +		goto clk_dis_ahb;
> +	}
> +
> +	ret = eswin_sdhci_reset_init(dev, eswin_sdhci);
> +	if (ret < 0) {
> +		dev_err(dev, "failed to reset\n");
> +		goto clk_disable_all;
> +	}
> +
> +	eswin_sdhci->crg_regmap = syscon_regmap_lookup_by_phandle(

Use wrapper for getting the arguments.

> +		pdev->dev.of_node, "eswin,syscrg_csr");
> +	if (IS_ERR(eswin_sdhci->crg_regmap)) {
> +		dev_dbg(&pdev->dev, "No syscrg_csr phandle specified\n");
> +		goto clk_disable_all;
> +	}
> +
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 1, &eswin_sdhci->crg_core_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_core_clk (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 2, &eswin_sdhci->crg_aclk_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_aclk_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,syscrg_csr",
> +					 3, &eswin_sdhci->crg_cfg_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get crg_cfg_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +
> +	eswin_sdhci->hsp_regmap = syscon_regmap_lookup_by_phandle(
> +		dev->of_node, "eswin,hsp_sp_csr");
> +	if (IS_ERR(eswin_sdhci->hsp_regmap)) {
> +		dev_dbg(dev, "No hsp_sp_csr phandle specified\n");
> +		goto clk_disable_all;
> +	}
> +
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,hsp_sp_csr",
> +					 2, &eswin_sdhci->hsp_int_status);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get hsp_int_status (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +	ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,hsp_sp_csr",
> +					 3, &eswin_sdhci->hsp_pwr_ctrl);
> +	if (ret) {
> +		dev_err(&pdev->dev, "can't get hsp_pwr_ctrl (%d)\n", ret);
> +		goto clk_disable_all;
> +	}
> +
> +	regmap_write(eswin_sdhci->hsp_regmap, eswin_sdhci->hsp_int_status,
> +		     MSHC_INT_CLK_STABLE);
> +	regmap_write(eswin_sdhci->hsp_regmap, eswin_sdhci->hsp_pwr_ctrl,
> +		     MSHC_HOST_VAL_STABLE);
> +
> +	if (!of_property_read_u32(dev->of_node, "delay_code", &val))

NAK, undocumented ABI.

> +		eswin_sdhci->phy.delay_code = val;
> +
> +	if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val))

NAK

> +		eswin_sdhci->phy.drive_impedance =
> +			eswin_convert_drive_impedance_ohm(pdev, val);
> +
> +	if (of_property_read_bool(dev->of_node, "enable-cmd-pullup"))

NAK

> +		eswin_sdhci->phy.enable_cmd_pullup = ENABLE;
> +	else
> +		eswin_sdhci->phy.enable_cmd_pullup = DISABLE;
> +
> +	if (of_property_read_bool(dev->of_node, "enable-data-pullup"))

NAK


> +		eswin_sdhci->phy.enable_data_pullup = ENABLE;
> +	else
> +		eswin_sdhci->phy.enable_data_pullup = DISABLE;
> +
> +	if (of_property_read_bool(dev->of_node, "enable-strobe-pulldown"))
> +		eswin_sdhci->phy.enable_strobe_pulldown = ENABLE;
> +	else
> +		eswin_sdhci->phy.enable_strobe_pulldown = DISABLE;
> +
> +	sdhci_get_of_property(pdev);
> +
> +	pltfm_host->clk = clk_xin;
> +
> +	ret = eswin_sdhci_register_sdclk(eswin_sdhci, clk_xin, dev);
> +	if (ret)
> +		goto clk_disable_all;
> +
> +	eswin_sdhci_dt_parse_clk_phases(dev, &eswin_sdhci->clk_data);
> +
> +	ret = mmc_of_parse(host->mmc);
> +	if (ret) {
> +		ret = dev_err_probe(dev, ret, "parsing dt failed.\n");
> +		goto unreg_clk;
> +	}
> +
> +	if (of_device_is_compatible(dev->of_node, "eswin,sdhci-5.1")) {

NAK, there is no such compatible. If you tested your DTS, you would spot it.

This driver is in really poor shape.

> +		host->mmc_host_ops.hs400_enhanced_strobe =
> +			eswin_sdhci_hs400_enhanced_strobe;
> +		eswin_sdhci->has_cqe = true;
> +		host->mmc->caps2 |= MMC_CAP2_CQE;
> +
> +		if (!of_property_read_bool(dev->of_node, "disable-cqe-dcmd"))
> +			host->mmc->caps2 |= MMC_CAP2_CQE_DCMD;
> +	}
> +
> +	sdhci_enable_v4_mode(eswin_sdhci->host);
> +
> +	ret = eswin_sdhci_add_host(eswin_sdhci);
> +	if (ret)
> +		goto unreg_clk;
> +
> +	return 0;
> +
> +unreg_clk:
> +	eswin_sdhci_unregister_sdclk(dev);
> +clk_disable_all:
> +	clk_disable_unprepare(clk_xin);
> +clk_dis_ahb:
> +	clk_disable_unprepare(eswin_sdhci->clk_ahb);
> +err_pltfm_free:
> +	sdhci_pltfm_free(pdev);
> +	return ret;
> +}
> +
> +static void eswin_sdhci_remove(struct platform_device *pdev)
> +{
> +	int ret;
> +	struct sdhci_host *host = platform_get_drvdata(pdev);
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct eswin_sdhci_data *eswin_sdhci = sdhci_pltfm_priv(pltfm_host);
> +	struct clk *clk_ahb = eswin_sdhci->clk_ahb;
> +
> +	sdhci_pltfm_remove(pdev);
> +
> +	if (eswin_sdhci->txrx_rst) {
> +		ret = reset_control_assert(eswin_sdhci->txrx_rst);
> +		WARN_ON(ret != 0);

Drop. You can print some useful error msg, but you cannot have WARNs. It
not useful at all.


Best regards,
Krzysztof

  reply	other threads:[~2025-05-16 13:17 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-16  9:12 [PATCH v1 0/2] Add driver support for ESWIN eic7700 SoC sdhci controller dongxuyang
2025-05-16  9:16 ` [PATCH v1 1/2] dt-bindings: sdhci: eswin: Documentation for eic7700 SoC dongxuyang
2025-05-16 10:26   ` Rob Herring (Arm)
2025-05-16 13:12   ` Krzysztof Kozlowski
2025-05-16  9:17 ` [PATCH v1 2/2] sdhci: eswin: Add eic7700 sdhci driver dongxuyang
2025-05-16 13:17   ` Krzysztof Kozlowski [this message]
2025-05-17  1:57   ` kernel test robot
2025-05-22  7:48   ` Adrian Hunter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=15bbeaaf-6dcc-49ce-baff-03692fcb90a9@kernel.org \
    --to=krzk@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dongxuyang@eswincomputing.com \
    --cc=krzk+dt@kernel.org \
    --cc=linmin@eswincomputing.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=ningyu@eswincomputing.com \
    --cc=p.zabel@pengutronix.de \
    --cc=robh@kernel.org \
    --cc=shanchun1218@gmail.com \
    --cc=ulf.hansson@linaro.org \
    --cc=xuxiang@eswincomputing.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.