From: sashiko-bot@kernel.org
To: "Taniya Das" <taniya.das@oss.qualcomm.com>
Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org,
linux-gpio@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v2 03/12] clk: qcom: Add a driver for PDM GP_MN fractional clock divider
Date: Tue, 27 Oct 2026 11:31:20 +0000 [thread overview]
Message-ID: <sashiko-outbox-186448@kernel.org> (raw)
In-Reply-To: <20261026-b4-pdm_clk_gp_mnd_v2-v2-3-ff8e4bc8d567@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] clk: qcom: clk-gp-mnd: bogus n_val and duty cycle in gp_mnd_clk_recalc_rate()
- [Low] clk: qcom: clk-gp-mnd: 64-bit division in gp_mnd_clk_set_duty_cycle() on 32-bit
--
commit 6c57ad9a80b314f181dd85480b5578fd6c5deb24
Author: Taniya Das <taniya.das@oss.qualcomm.com>
clk: qcom: Add a driver for PDM GP_MN fractional clock divider
This commit adds a standalone platform driver for the Qualcomm PDM GP_MN
fractional clock divider, implementing rate and duty-cycle operations
over regmap with runtime PM clock management.
> diff --git a/drivers/clk/qcom/clk-gp-mnd.c b/drivers/clk/qcom/clk-gp-mnd.c
> new file mode 100644
> index 0000000000000..818726c02b615
> --- /dev/null
> +++ b/drivers/clk/qcom/clk-gp-mnd.c
> @@ -0,0 +1,333 @@
[ ... ]
> +static unsigned long gp_mnd_clk_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_gp_mnd *gp = to_clk_gp_mnd(hw);
> + unsigned int m_val, n_val;
> + int ret;
> +
> + ret = gp_mnd_clk_runtime_resume(gp);
> + if (ret)
> + return 0;
> +
> + ret = regmap_read(gp->regmap, GP_MND_MDIV_REG, &m_val);
> + if (ret)
> + goto out_runtime_put;
> +
> + m_val &= GP_MND_MAX_M;
> +
> + ret = regmap_read(gp->regmap, GP_MND_NDIV_REG, &n_val);
> + if (ret)
> + goto out_runtime_put;
> +
> + /* Reverse the 1's complement encoding: N = ~NDIV_REG + M */
> + n_val = (~n_val & GP_MND_MAX_N) + m_val;
> +
> +out_runtime_put:
> + gp_mnd_clk_runtime_put(gp);
> +
> + if (ret)
> + return 0;
> +
> + if (!n_val)
> + return 0;
> +
> + gp->m_val = m_val;
> + gp->n_val = n_val;
> +
> + return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * m_val, n_val);
> +}
> +
> +static int gp_mnd_clk_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
> +{
> + struct clk_gp_mnd *gp = to_clk_gp_mnd(hw);
> + unsigned int d_val;
> + int ret;
> +
> + if (!gp->n_val) {
> + duty->num = 1;
> + duty->den = 2;
> + return 0;
> + }
> +
> + ret = gp_mnd_clk_runtime_resume(gp);
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(gp->regmap, GP_MND_DUTY_REG, &d_val);
> +
> + gp_mnd_clk_runtime_put(gp);
> +
> + if (ret)
> + return ret;
> +
> + if (d_val >= gp->n_val)
> + return -EINVAL;
> +
> + /* DUTY stores the low-phase count; report the high-phase duty cycle. */
> + duty->num = gp->n_val - d_val;
> + duty->den = gp->n_val;
> +
> + return 0;
> +}
[Severity: Medium]
When GP_MND_MDIV_REG and GP_MND_NDIV_REG are at their power-on reset value of
0, gp_mnd_clk_recalc_rate() reads m_val = 0 and computes:
n_val = (~n_val & GP_MND_MAX_N) + m_val;
which evaluates to 8191. Because only !n_val is checked before caching,
gp_mnd_clk_recalc_rate() stores gp->m_val = 0 and gp->n_val = 8191 even though
the divider is unconfigured and the returned rate is 0.
When gp_mnd_clk_get_duty_cycle() is later called (for example via
clk_get_scaled_duty_cycle() or debugfs clk_summary), the !gp->n_val check for
the 50% default is bypassed because gp->n_val is 8191. Reading d_val = 0 from
GP_MND_DUTY_REG then reports duty->num = 8191 and duty->den = 8191 (100% duty
cycle) instead of 1/2.
In addition, during clk_gp_mnd_probe() -> devm_clk_hw_register() ->
__clk_core_init(), clk_core_update_duty_cycle_nolock() invokes
gp_mnd_clk_get_duty_cycle() before core->ops->recalc_rate() is called, so
gp->n_val is always 0 during initial registration even if the hardware
registers were already programmed prior to probe.
Should gp_mnd_clk_recalc_rate() also check for !m_val (or n_val <= 2 * m_val +
1) before caching gp->m_val and gp->n_val, and should gp_mnd_clk_get_duty_cycle()
handle reading the hardware state or validating M < D < (N - M) directly?
> +
> +static int gp_mnd_clk_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
> +{
> + struct clk_gp_mnd *gp = to_clk_gp_mnd(hw);
> + unsigned int d_val;
> + int ret;
> +
> + if (!gp->n_val || !gp->m_val || !duty->den || duty->num > duty->den)
> + return -EINVAL;
> +
> + /* D = (1 - duty) * N, giving the low-phase count */
> + d_val = DIV_ROUND_UP((u64)(duty->den - duty->num) * gp->n_val, duty->den);
[Severity: Low]
Since QCOM_CLK_GP_MND depends on ARM64 || COMPILE_TEST, this driver can be
built on 32-bit architectures.
In gp_mnd_clk_set_duty_cycle(), DIV_ROUND_UP() expands to plain C division on a
u64 dividend and a runtime unsigned int divisor (duty->den), which causes a
link failure (__udivdi3 / __aeabi_uldivmod undefined) on 32-bit COMPILE_TEST
builds.
Should this use DIV_ROUND_UP_ULL() instead?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261026-b4-pdm_clk_gp_mnd_v2-v2-0-ff8e4bc8d567@oss.qualcomm.com?part=3
next prev parent reply other threads:[~2026-10-27 11:31 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 11:29 [PATCH v2 00/12] clk: qcom: Add PDM GP_MN fractional clock divider driver and DT support Taniya Das
2026-10-26 11:29 ` [PATCH v2 01/12] dt-bindings: clock: qcom: Add bindings for PDM GP_MN clock divider Taniya Das
2026-10-27 11:31 ` sashiko-bot
2026-10-27 18:47 ` Krzysztof Kozlowski
2026-10-26 11:29 ` [PATCH v2 02/12] dt-bindings: clock: qcom: Add PDM XO4 divider clock IDs Taniya Das
2026-10-28 11:28 ` Krzysztof Kozlowski
2026-10-26 11:29 ` [PATCH v2 03/12] clk: qcom: Add a driver for PDM GP_MN fractional clock divider Taniya Das
2026-10-27 11:31 ` sashiko-bot [this message]
2026-10-26 11:29 ` [PATCH v2 04/12] clk: qcom: gcc: Add configurable PDM XO4 div clocks across targets Taniya Das
2026-10-26 15:04 ` Abel Vesa
2026-10-26 11:29 ` [PATCH v2 05/12] pinctrl: qcom: qcs8300: Add gp_mn mux function Taniya Das
2026-10-26 11:29 ` [PATCH v2 06/12] pinctrl: qcom: sa8775p: " Taniya Das
2026-10-26 11:29 ` [PATCH v2 07/12] pinctrl: qcom: sc7280: " Taniya Das
2026-10-26 11:29 ` [PATCH v2 08/12] pinctrl: qcom: qcs615: " Taniya Das
2026-10-28 15:32 ` Abel Vesa
2026-10-29 8:15 ` Konrad Dybcio
2026-10-26 11:29 ` [PATCH v2 09/12] arm64: dts: qcom: qcs8300: Add GP M/N clock controller Taniya Das
2026-10-27 11:31 ` sashiko-bot
2026-10-26 11:29 ` [PATCH v2 10/12] arm64: dts: qcom: sa8775p: " Taniya Das
2026-10-27 11:31 ` sashiko-bot
2026-10-26 11:29 ` [PATCH v2 11/12] arm64: dts: qcom: sc7280: " Taniya Das
2026-10-26 16:27 ` Abel Vesa
2026-10-27 11:31 ` sashiko-bot
2026-10-26 11:29 ` [PATCH v2 12/12] arm64: dts: qcom: qcs615: " Taniya Das
2026-10-26 16:27 ` Abel Vesa
2026-10-27 11:31 ` sashiko-bot
2026-10-28 9:44 ` [PATCH v2 00/12] clk: qcom: Add PDM GP_MN fractional clock divider driver and DT support Bartosz Golaszewski
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=sashiko-outbox-186448@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=linux-clk@vger.kernel.org \
--cc=linux-gpio@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=taniya.das@oss.qualcomm.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.