Re: [PATCH v8 2/2] i2c: ls2x: Add clocks property parsing and adjust bus speed
Xi Ruoyao <[email protected]> Wed, 29 Jul 2026 16:09:31 +0800
| Newsgroups | org.kernel.vger.linux-i2c,dev.linux.lists.loongarch,org.kernel.vger.linux-devicetree,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
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]> > --- > 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); -- Xi Ruoyao <[email protected]>