Skip to content
Snippets Groups Projects
Commit 71c49ee9 authored by Binbin Zhou's avatar Binbin Zhou Committed by Andi Shyti
Browse files

i2c: ls2x: Fix frequency division register access


According to the chip manual, the I2C register access type of
Loongson-2K2000/LS7A is "B", so we can only access registers in byte
form (readb()/writeb()).

Although Loongson-2K0500/Loongson-2K1000 do not have similar
constraints, register accesses in byte form also behave correctly.

Also, in hardware, the frequency division registers are defined as two
separate registers (high 8-bit and low 8-bit), so we just access them
directly as bytes.

Fixes: 015e61f0 ("i2c: ls2x: Add driver for Loongson-2K/LS7A I2C controller")
Co-developed-by: default avatarHongliang Wang <wanghongliang@loongson.cn>
Signed-off-by: default avatarHongliang Wang <wanghongliang@loongson.cn>
Signed-off-by: default avatarBinbin Zhou <zhoubinbin@loongson.cn>
Cc: stable@vger.kernel.org # v6.3+
Reviewed-by: default avatarAndy Shevchenko <andy@kernel.org>
Signed-off-by: default avatarAndi Shyti <andi.shyti@kernel.org>
Link: https://lore.kernel.org/r/20250220125612.1910990-1-zhoubinbin@loongson.cn
parent dd1998e2
No related branches found
No related tags found
No related merge requests found
......@@ -10,6 +10,7 @@
* Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn>
*/
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/completion.h>
#include <linux/device.h>
......@@ -26,7 +27,8 @@
#include <linux/units.h>
/* I2C Registers */
#define I2C_LS2X_PRER 0x0 /* Freq Division Register(16 bits) */
#define I2C_LS2X_PRER_LO 0x0 /* Freq Division Low Byte Register */
#define I2C_LS2X_PRER_HI 0x1 /* Freq Division High Byte Register */
#define I2C_LS2X_CTR 0x2 /* Control Register */
#define I2C_LS2X_TXR 0x3 /* Transport Data Register */
#define I2C_LS2X_RXR 0x3 /* Receive Data Register */
......@@ -93,6 +95,7 @@ static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id)
*/
static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
{
u16 val;
struct i2c_timings *t = &priv->i2c_t;
struct device *dev = priv->adapter.dev.parent;
u32 acpi_speed = i2c_acpi_find_bus_speed(dev);
......@@ -104,9 +107,14 @@ static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv)
else
t->bus_freq_hz = LS2X_I2C_FREQ_STD;
/* Calculate and set i2c frequency. */
writew(LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1,
priv->base + I2C_LS2X_PRER);
/*
* 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);
}
static void ls2x_i2c_init(struct ls2x_i2c_priv *priv)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment