Re: [PATCH v8 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed

Hongliang Wang <[email protected]> Sat, 1 Aug 2026 17:12:29 +0800
Newsgroups dev.linux.lists.loongarch,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-i2c,org.kernel.vger.stable
Message-ID <[email protected]>
Hi Ruoyao,

On 2026/7/29 下午4:09, Xi Ruoyao wrote:
> On Tue, 2026-07-21 at 20:26 +0800, Hongliang Wang wrote:
>> The i2c-ls2x driver supports dts and acpi parameter passing.
>>
>> In dts, uses clock framework, by parsing clocks property to
>> get i2c bus reference clock, and define the div of reference
>> clock by device data.
>>
>> In acpi, by passing clocks property to describe i2c bus reference
>> clock and clock-div property to describe the div of reference clock.
>>
>> Based on i2c bus reference clock(clock_a), i2c bus speed(clock_s)
>> and div, calculate the prcescale of i2c divider register. The
>> calculation formula is
>>
>> prcescale = (clock_a*10)/(div*clock_s)-1
>>
>> Reviewed-by: Huacai Chen<[email protected]>
>> Cc:[email protected]
>> Signed-off-by: Hongliang Wang<[email protected]>
> This resolves the jittery touchpad input on the EAECIS NL60R laptop.
>
> Tested-by: Xi Ruoyao<[email protected]>
Thank you for testing!
>> ---
>>   drivers/i2c/busses/i2c-ls2x.c | 40 ++++++++++++++++++++++++++++++++---
>>   1 file changed, 37 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c
>> index b475dd27b7af..25f8301ae14f 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 = (priv->pclk * 10) / (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,29 @@ 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);
>> +		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 are only ACPI properties. */
>> +		ret = device_property_read_u32(dev, "clocks", &priv->pclk);
>> +		if (ret)
>> +			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 +383,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);
Best regards,
Hongliang Wang