* [PATCH v9 0/2] i2c: ls2x: Add clock- related properties and parsing
@ 2026-08-10 7:49 Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 1/2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed Hongliang Wang
0 siblings, 2 replies; 4+ messages in thread
From: Hongliang Wang @ 2026-08-10 7:49 UTC (permalink / raw)
To: Hongliang Wang, Binbin Zhou, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Wolfram Sang
Cc: linux-i2c, devicetree, loongarch
Hi all:
This patch set adds clock related properties and parsing in dts and acpi.
======
V9:
Patch (2/2):
- Rewrite the commit description
- Use 64-bit arithmetic to avoid integer overflow during the clock calculation
- Add checks to reject zero clock rates and ensure valid clock inputs
- Modify the comment for clocks and clock-div properties
- Add Tested-by tag from Xi Ruoyao, thanks
Link to V8:
https://lore.kernel.org/all/20260721122604.12717-1-wanghongliang@loongson.cn/
V8:
Patch (2/2):
Fix the potential issues from Sashiko AI review:
- Add error checking for the pointer returned by devm_clk_get_optional_enabled();
- Add zero-value checking for the match data to provide default div.
Link to V7:
https://lore.kernel.org/all/20260707035104.3092-1-wanghongliang@loongson.cn/
V7:
Patch (2/2):
Fix the potential issues from Sashiko AI review:
- Move the clock property parsing process to probe function to solve the issue
of calling `devm_clk_get_optional_enabled()` dynamically causes unbounded memory
leaks and unbalanced clock enable counts.
- Add non-zero checking to priv->div.
Link to V6:
https://lore.kernel.org/all/20260608024533.32419-1-wanghongliang@loongson.cn/
V6:
- Add Reviewed-by tag from Huacai, thanks.
Patch (1/2):
- Remove CC stable.
Link to V5:
https://lore.kernel.org/all/20260604015848.18643-1-wanghongliang@loongson.cn/
V5:
Patch (1/2):
- Adjust the position of #include <dt-bindings/clock/loongson,ls2k-clk.h>;
- Add CC stable;
- Fix Signed-off-by.
Patch (2/2):
- Replace 2K0500/2K1000/2K2000 with LS2K0500/2K1000/2K2000;
- Replace 7A1000/7A2000 with LS7A1000/7A2000;
- Replace if (clk && !IS_ERR(clk)) with if(!IS_ERR_OR_NULL(clk));
- Add document that clocks and clock-div are only ACPI properties in ACPI;
- Remove unsigned int cast in code (unsigned long)device_get_match_data(dev);
- Add CC stable;
- Fix Signed-off-by.
Link to V4:
https://lore.kernel.org/all/20260526031021.32662-1-wanghongliang@loongson.cn/
V4:
- Add Acked-by tag from Conor Dooley, thanks.
Patch (2/2):
- Adjust the position of #include <linux/clk.h>;
- Remove struct ls2x_i2c_chip_data and use macro to describe div;
- Use div instead of factor in ls2x_i2c_adjust_bus_speed;
- Reverse the "if & else" code logic in ls2x_i2c_adjust_bus_speed;
Link to V2:
The PATCH v3 is incomplete, v4 is the replacement of v3, so the previous patch link is v2.
[PATCH v2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties
https://lore.kernel.org/all/20260507081010.12810-1-wanghongliang@loongson.cn/
[PATCH v2] i2c: ls2x: Add clocks property parsing and adjust bus speed
https://lore.kernel.org/all/20260507081010.12810-2-wanghongliang@loongson.cn/
V2:
[PATCH v2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties
- Remove the custom properties clock-input and clock-div, use clock framework;
[PATCH v2] i2c: ls2x: Add clocks property parsing and adjust bus speed
- Use clock framework to obtain the i2c reference clock in dts.
Link to V1:
https://lore.kernel.org/all/20260325011852.19079-1-wanghongliang@loongson.cn/
Hongliang Wang (2):
dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties
i2c: ls2x: Add clocks property parsing and adjust bus speed
.../bindings/i2c/loongson,ls2x-i2c.yaml | 3 ++
drivers/i2c/busses/i2c-ls2x.c | 43 +++++++++++++++++--
2 files changed, 43 insertions(+), 3 deletions(-)
--
2.47.2
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v9 1/2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties
2026-08-10 7:49 [PATCH v9 0/2] i2c: ls2x: Add clock- related properties and parsing Hongliang Wang
@ 2026-08-10 7:49 ` Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed Hongliang Wang
1 sibling, 0 replies; 4+ messages in thread
From: Hongliang Wang @ 2026-08-10 7:49 UTC (permalink / raw)
To: Hongliang Wang, Binbin Zhou, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Wolfram Sang
Cc: linux-i2c, devicetree, loongarch, Huacai Chen, Conor Dooley
Add clocks and clock-frequency properties to examples.
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Hongliang Wang <wanghongliang@loongson.cn>
---
Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml | 3 +++
1 file changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
index ee09c6d9c5f0..0beb7f2515c8 100644
--- a/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
@@ -37,11 +37,14 @@ unevaluatedProperties: false
examples:
- |
+ #include <dt-bindings/clock/loongson,ls2k-clk.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0: i2c@1fe21000 {
compatible = "loongson,ls2k-i2c";
reg = <0x1fe21000 0x8>;
+ clock-frequency = <100000>;
+ clocks = <&clk LOONGSON2_APB_CLK>;
interrupt-parent = <&extioiic>;
interrupts = <22 IRQ_TYPE_LEVEL_LOW>;
#address-cells = <1>;
--
2.47.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed
2026-08-10 7:49 [PATCH v9 0/2] i2c: ls2x: Add clock- related properties and parsing Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 1/2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties Hongliang Wang
@ 2026-08-10 7:49 ` Hongliang Wang
2026-08-10 8:02 ` sashiko-bot
1 sibling, 1 reply; 4+ messages in thread
From: Hongliang Wang @ 2026-08-10 7:49 UTC (permalink / raw)
To: Hongliang Wang, Binbin Zhou, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Wolfram Sang
Cc: linux-i2c, devicetree, loongarch, Xi Ruoyao, Huacai Chen, stable
The original driver uses a fixed PCLK frequency(LS2X_I2C_PCLK_FREQ) and
fixed div(5) for I2C bus speed calculation. As PCLK frequency and div
vary on different SoCs and ACPI platforms, this leads to inaccurate I2C
bus speed calculation and poor adaptability across platforms.
Improve the accuracy of I2C bus speed calculation across different
platforms by parsing the real I2C bus reference clock (PCLK) and div.
Support both DTS and ACPI.
For DTS:
- Retrieve I2C bus reference clock via the common clock framework
- Fetch div from match data for LS2K/LS7A series
- Fallback to default values if clock lookup fails or the obtained
pclk or div is zero
For ACPI:
- Parse "clocks" property to get I2C bus reference clock
- Parse "clock-div" property to get div
- Fallback to the default values if property parsing fails or the
obtained pclk or div is zero
Calculate the I2C clock prescaler based on reference clock, div and
target bus frequency with the formula:
prescale = (pclk * 10) / (div * bus_freq_hz) - 1
Dynamically acquiring PCLK and div per platform ensures accurate I2C bus
speed calculation and reliable operation across different platforms.
Tested-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Cc: stable@vger.kernel.org
Signed-off-by: Hongliang Wang <wanghongliang@loongson.cn>
---
drivers/i2c/busses/i2c-ls2x.c | 43 ++++++++++++++++++++++++++++++++---
1 file changed, 40 insertions(+), 3 deletions(-)
diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
index b475dd27b7af..65451fc9145b 100644
--- a/drivers/i2c/busses/i2c-ls2x.c
+++ b/drivers/i2c/busses/i2c-ls2x.c
@@ -12,6 +12,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/iopoll.h>
@@ -63,11 +64,19 @@
/* The default bus frequency, which is an empirical value */
#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ)
+/* The div of i2c reference clock on LS2K0500/2K1000/2K2000 */
+#define LS2X_I2C_2K_CLOCK_DIV 40
+
+/* The div of i2c reference clock on LS7A1000/7A2000 */
+#define LS2X_I2C_7A_CLOCK_DIV 50
+
struct ls2x_i2c_priv {
struct i2c_adapter adapter;
void __iomem *base;
struct i2c_timings i2c_t;
struct completion cmd_complete;
+ unsigned int div;
+ unsigned int pclk;
};
/*
@@ -107,12 +116,13 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
+ val = ((u64)priv->pclk * 10) / ((u64)priv->div * t->bus_freq_hz) - 1;
+
/*
* According to the chip manual, we can only access the registers as bytes,
* otherwise the high bits will be truncated.
* So set the I2C frequency with a sequential writeb() instead of writew().
*/
- val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1;
writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_LO);
writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_HI);
}
@@ -287,6 +297,7 @@ static const struct i2c_algorithm ls2x_i2c_algo = {
static int ls2x_i2c_probe(struct platform_device *pdev)
{
int ret, irq;
+ struct clk *clk;
struct i2c_adapter *adap;
struct ls2x_i2c_priv *priv;
struct device *dev = &pdev->dev;
@@ -304,6 +315,32 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
+ if (dev_of_node(dev)) {
+ clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ if (clk) {
+ priv->pclk = clk_get_rate(clk);
+ if (!priv->pclk)
+ priv->pclk = LS2X_I2C_PCLK_FREQ;
+ } else {
+ priv->pclk = LS2X_I2C_PCLK_FREQ;
+ }
+
+ priv->div = (unsigned long)device_get_match_data(dev);
+ if (!priv->div)
+ priv->div = LS2X_I2C_2K_CLOCK_DIV;
+ } else {
+ /* clocks and clock-div properties are used only in ACPI path. */
+ ret = device_property_read_u32(dev, "clocks", &priv->pclk);
+ if (ret || !priv->pclk)
+ priv->pclk = LS2X_I2C_PCLK_FREQ;
+
+ ret = device_property_read_u32(dev, "clock-div", &priv->div);
+ if (ret || !priv->div)
+ priv->div = LS2X_I2C_7A_CLOCK_DIV;
+ }
+
/* Add the i2c adapter */
adap = &priv->adapter;
adap->retries = 5;
@@ -349,8 +386,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops,
ls2x_i2c_suspend, ls2x_i2c_resume, NULL);
static const struct of_device_id ls2x_i2c_id_table[] = {
- { .compatible = "loongson,ls2k-i2c" },
- { .compatible = "loongson,ls7a-i2c" },
+ { .compatible = "loongson,ls2k-i2c", .data = (void *)LS2X_I2C_2K_CLOCK_DIV, },
+ { .compatible = "loongson,ls7a-i2c", .data = (void *)LS2X_I2C_7A_CLOCK_DIV, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table);
--
2.47.2
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed
2026-08-10 7:49 ` [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed Hongliang Wang
@ 2026-08-10 8:02 ` sashiko-bot
0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-08-10 8:02 UTC (permalink / raw)
To: Hongliang Wang; +Cc: devicetree, conor+dt, robh
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [High] 64-bit integer division using the '/' operator causes a linker error on 32-bit architectures.
- [Medium] The ACPI fallback path reads the generic 'clocks' property as a single 32-bit integer frequency, violating standard property semantics.
Pre-existing issues:
- [High] Hardware interrupts are enabled before the IRQ handler is registered.
- [High] The driver lacks a remove function, failing to disable hardware interrupts during driver unbind.
--
--- Patch [2]: [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed ---
commit d881529f1ceaa7d91f234c648749c3641859d689
Author: Hongliang Wang <wanghongliang@loongson.cn>
i2c: ls2x: Add clocks property parsing and adjust bus speed
This commit improves I2C bus speed calculation across platforms by parsing
the real I2C bus reference clock (PCLK) and div from DTS or ACPI, instead
of using fixed values.
> diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
> index b475dd27b7af9..65451fc9145b7 100644
> --- a/drivers/i2c/busses/i2c-ls2x.c
> +++ b/drivers/i2c/busses/i2c-ls2x.c
> @@ -107,12 +116,13 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
> else
> t->bus_freq_hz = LS2X_I2C_FREQ_STD;
>
> + val = ((u64)priv->pclk * 10) / ((u64)priv->div * t->bus_freq_hz) - 1;
[Severity: High]
Will this 64-bit integer division using the direct '/' operator cause a
linker error on 32-bit architectures?
Since CONFIG_COMPILE_TEST=y is possible, compiling this driver on 32-bit
architectures emits a call to __udivdi3, which is intentionally omitted in
the kernel.
Could we use div64_u64() or do_div() from <linux/math64.h> here instead?
> +
> /*
> * According to the chip manual, we can only access the registers as bytes,
> * otherwise the high bits will be truncated.
[ ... ]
> @@ -304,6 +315,32 @@ static int ls2x_i2c_probe(struct platform_device *pdev)
> if (irq < 0)
> return irq;
>
> + if (dev_of_node(dev)) {
[ ... ]
> + } else {
> + /* clocks and clock-div properties are used only in ACPI path. */
> + ret = device_property_read_u32(dev, "clocks", &priv->pclk);
[Severity: Medium]
Does reading the ACPI "clocks" property as a single 32-bit integer frequency
violate standard property semantics?
The driver expects ACPI tables to provide the input clock frequency as an
integer under the "clocks" property.
However, "clocks" is standardly defined as an array of references (phandles)
to clock providers.
Should a standard property like "clock-frequency" be used instead to pass a
scalar integer?
> + if (ret || !priv->pclk)
> + priv->pclk = LS2X_I2C_PCLK_FREQ;
[ ... ]
[Severity: High]
This is a pre-existing issue, but does initializing the hardware in
ls2x_i2c_probe() enable interrupts before the IRQ handler is registered?
drivers/i2c/busses/i2c-ls2x.c:ls2x_i2c_probe() {
...
ls2x_i2c_init(priv);
ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c",
priv);
...
}
In ls2x_i2c_init(), the CTR_READY_MASK (which includes the interrupt enable
bit LS2X_CTR_IEN) is written to the control register before the handler is
registered by devm_request_irq().
If a hardware interrupt is asserted in this window, could it lead to an
unhandled interrupt storm and permanently disable the shared IRQ line?
[Severity: High]
This is a pre-existing issue, but is the driver missing a remove function
to disable hardware interrupts during driver unbind?
drivers/i2c/busses/i2c-ls2x.c:
static struct platform_driver ls2x_i2c_driver = {
.probe = ls2x_i2c_probe,
.driver = {
...
},
};
Because the driver relies on devres for cleanup and lacks a .remove
callback in ls2x_i2c_driver, devres will free the IRQ handler on unbind
while the hardware is never quiesced.
If an interrupt asserts after the handler is freed, would this cause an
unhandled interrupt?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810074927.25284-1-wanghongliang@loongson.cn?part=2
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-10 8:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 7:49 [PATCH v9 0/2] i2c: ls2x: Add clock- related properties and parsing Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 1/2] dt-bindings: i2c: ls2x-i2c: Add clocks and clock-frequency properties Hongliang Wang
2026-08-10 7:49 ` [PATCH v9 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed Hongliang Wang
2026-08-10 8:02 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox