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 | dev.linux.lists.loongarch,org.kernel.vger.linux-devicetree,org.kernel.vger.linux-i2c,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. >=20 > 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. >=20 > In acpi, by passing clocks property to describe i2c bus reference > clock and clock-div property to describe the div of reference clock. >=20 > 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 >=20 > prcescale =3D (clock_a*10)/(div*clock_s)-1 >=20 > 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]> > --- > =C2=A0drivers/i2c/busses/i2c-ls2x.c | 40 ++++++++++++++++++++++++++++++++= --- > =C2=A01 file changed, 37 insertions(+), 3 deletions(-) >=20 > 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 @@ > =C2=A0 > =C2=A0#include <linux/bitfield.h> > =C2=A0#include <linux/bits.h> > +#include <linux/clk.h> > =C2=A0#include <linux/completion.h> > =C2=A0#include <linux/device.h> > =C2=A0#include <linux/iopoll.h> > @@ -63,11 +64,19 @@ > =C2=A0/* The default bus frequency, which is an empirical value */ > =C2=A0#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ) > =C2=A0 > +/* 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 > + > =C2=A0struct ls2x_i2c_priv { > =C2=A0 struct i2c_adapter adapter; > =C2=A0 void __iomem *base; > =C2=A0 struct i2c_timings i2c_t; > =C2=A0 struct completion cmd_complete; > + unsigned int div; > + unsigned int pclk; > =C2=A0}; > =C2=A0 > =C2=A0/* > @@ -107,12 +116,13 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i= 2c_priv *priv) > =C2=A0 else > =C2=A0 t->bus_freq_hz =3D LS2X_I2C_FREQ_STD; > =C2=A0 > + val =3D (priv->pclk * 10) / (priv->div * t->bus_freq_hz) - 1; > + > =C2=A0 /* > =C2=A0 * According to the chip manual, we can only access the registers = as bytes, > =C2=A0 * otherwise the high bits will be truncated. > =C2=A0 * So set the I2C frequency with a sequential writeb() instead of = writew(). > =C2=A0 */ > - val =3D LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1; > =C2=A0 writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_L= O); > =C2=A0 writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_= HI); > =C2=A0} > @@ -287,6 +297,7 @@ static const struct i2c_algorithm ls2x_i2c_algo =3D { > =C2=A0static int ls2x_i2c_probe(struct platform_device *pdev) > =C2=A0{ > =C2=A0 int ret, irq; > + struct clk *clk; > =C2=A0 struct i2c_adapter *adap; > =C2=A0 struct ls2x_i2c_priv *priv; > =C2=A0 struct device *dev =3D &pdev->dev; > @@ -304,6 +315,29 @@ static int ls2x_i2c_probe(struct platform_device *pd= ev) > =C2=A0 if (irq < 0) > =C2=A0 return irq; > =C2=A0 > + if (dev_of_node(dev)) { > + clk =3D devm_clk_get_optional_enabled(dev, NULL); > + if (IS_ERR(clk)) > + return PTR_ERR(clk); > + if (clk) > + priv->pclk =3D clk_get_rate(clk); > + else > + priv->pclk =3D LS2X_I2C_PCLK_FREQ; > + > + priv->div =3D (unsigned long)device_get_match_data(dev); > + if (!priv->div) > + priv->div =3D LS2X_I2C_2K_CLOCK_DIV; > + } else { > + /* clocks and clock-div are only ACPI properties. */ > + ret =3D device_property_read_u32(dev, "clocks", &priv->pclk); > + if (ret) > + priv->pclk =3D LS2X_I2C_PCLK_FREQ; > + > + ret =3D device_property_read_u32(dev, "clock-div", &priv->div); > + if (ret || !priv->div) > + priv->div =3D LS2X_I2C_7A_CLOCK_DIV; > + } > + > =C2=A0 /* Add the i2c adapter */ > =C2=A0 adap =3D &priv->adapter; > =C2=A0 adap->retries =3D 5; > @@ -349,8 +383,8 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops, > =C2=A0 ls2x_i2c_suspend, ls2x_i2c_resume, NULL); > =C2=A0 > =C2=A0static const struct of_device_id ls2x_i2c_id_table[] =3D { > - { .compatible =3D "loongson,ls2k-i2c" }, > - { .compatible =3D "loongson,ls7a-i2c" }, > + { .compatible =3D "loongson,ls2k-i2c", .data =3D (void *)LS2X_I2C_2K_CL= OCK_DIV, }, > + { .compatible =3D "loongson,ls7a-i2c", .data =3D (void *)LS2X_I2C_7A_CL= OCK_DIV, }, > =C2=A0 { /* sentinel */ } > =C2=A0}; > =C2=A0MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table); --=20 Xi Ruoyao <[email protected]>