devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver
@ 2025-08-09 22:07 Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 01/11] i2c: rtl9300: use regmap fields and API for registers Jonas Jelonek
                   ` (10 more replies)
  0 siblings, 11 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

This patch series reworks the current implementation of the driver for
I2C controller integrated into RTL9300 SoCs to have better overall code
simplify support extension, and adds support for the RTL9310 series.
Goal of this is to have RTL9310 support upstream in a proper
implementation to be able to drop downstream versions of this driver.

The first patch changes the driver to use more of the regmap API.
Instead of using macros, all registers are defined as reg_field and
operations on these registers are performed using regmap_field and the
corresponding API. This simplifies adding support for further chip
families and avoids potential redundant code by just providing
chip-specific functions for every chip family.

Further patches add some checks to fix issues based on incorrect passed
values, remove SMBus Quick support (not actually supported by hardware)
and reorder some operations to be at a proper location.

The last patch and penultimate patch add support for RTL9310 series to
the driver and adjust the dt-bindings accordingly.

Simple operations have been tested successfully on RTL9302B-based Zyxel
XGS1210-12 and RTL9313-based Netgear MS510TXM, with simple SFP EEPROM
read. Other operations need testing from people with devices available.

Compile-tested with Linux, run-tested as backport in OpenWrt on the
aforementioned devices.

I splitted the changes to my best knowledge, to simplify review. If
suggested, I might combine some of them for final merge.

--
Changelog

v5: - added more patches to fix further issues/do further cleanup
        - remove SMBus Quick support (not supported by hardware)
        - move setting SCL frequency to config_io
        - only set read message format (RD_MODE) once on probing
        - add check to avoid len = 0 being allowed as length
    - adjusted cover letter

v4: - fixed an incorrect check for number of channels which was already
      present in original code

v3: - narrowed vendor property per variant to be required only
      for RTL9310
    - narrowed usable child-node i2c addresses per variant
    - no changes to driver patches

v2: - Patch 1:
        - adjusted commit message
        - retained Tested-By and Reviewed-By from Chris Packham
    - Patch 2:
        - simplified check as suggested by Markus Stockhausen
        - fixed commit message
    - Patch 3 (all requested by Krzysztof):
        - use vendor property instead of generic
        - add front compatibles to make binding complete
        - fix commit message
    - reordered patches, dt-bindings patch now comes before its 'user'
    - properly add device-tree list and relevant maintainers to To/Cc

--

Jonas Jelonek (11):
  i2c: rtl9300: use regmap fields and API for registers
  i2c: rtl9300: fix channel number bound check
  dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos
  i2c: rtl9300: rename internal sda_pin to sda_num
  i2c: rtl9300: check if xfer length is valid
  i2c: rtl9300: remove SMBus Quick operation support
  i2c: rtl9300: move setting SCL frequency to config_io
  i2c: rtl9300: do not set read mode on every transfer
  i2c: rtl9300: separate xfer configuration and execution
  dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support
  i2c: rtl9300: add support for RTL9310 I2C controller

 .../bindings/i2c/realtek,rtl9301-i2c.yaml     |  45 +-
 drivers/i2c/busses/i2c-rtl9300.c              | 477 +++++++++++-------
 2 files changed, 321 insertions(+), 201 deletions(-)


base-commit: 7e161a991ea71e6ec526abc8f40c6852ebe3d946
prerequisite-patch-id: 603f6da5f9ccbf40aa1e8247144e2413f676ef24
prerequisite-patch-id: 4328bb2802794cbd46f4952a22cbc73e022d0c12
prerequisite-patch-id: 90d8673eb6c9444937ea335ae8a934414e0a9ecd
prerequisite-patch-id: de876ceafb623d95a41af42b3e3dae7538023e33
prerequisite-patch-id: ecc2a415352d9ed09975b06b97b750b5182f4147
-- 
2.48.1


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v5 01/11] i2c: rtl9300: use regmap fields and API for registers
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 02/11] i2c: rtl9300: fix channel number bound check Jonas Jelonek
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Adapt the RTL9300 I2C controller driver to use more of the regmap
API, especially make use of reg_field and regmap_field instead of macros
to represent registers. Most register operations are performed through
regmap_field_* API then.

Handle SCL selection using separate chip-specific functions since this
is already known to differ between the Realtek SoC families in such a
way that this cannot be properly handled using just a different
reg_field.

This makes it easier to add support for newer generations or to handle
differences between specific revisions within a series. Just by
defining a separate driver data structure with the corresponding
register field definitions and linking it to a new compatible.

Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
Tested-by: Chris Packham <chris.packham@alliedtelesis.co.nz> # On RTL9302c
Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 192 ++++++++++++++++++++-----------
 1 file changed, 124 insertions(+), 68 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 2ccc139ffbf6..e6eb6a32fde2 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -23,94 +23,114 @@ struct rtl9300_i2c_chan {
 	u8 sda_pin;
 };
 
+enum rtl9300_i2c_reg_scope {
+	REG_SCOPE_GLOBAL,
+	REG_SCOPE_MASTER,
+};
+
+struct rtl9300_i2c_reg_field {
+	struct reg_field field;
+	enum rtl9300_i2c_reg_scope scope;
+};
+
+enum rtl9300_i2c_reg_fields {
+	F_DATA_WIDTH = 0,
+	F_DEV_ADDR,
+	F_I2C_FAIL,
+	F_I2C_TRIG,
+	F_MEM_ADDR,
+	F_MEM_ADDR_WIDTH,
+	F_RD_MODE,
+	F_RWOP,
+	F_SCL_FREQ,
+	F_SCL_SEL,
+	F_SDA_OUT_SEL,
+	F_SDA_SEL,
+
+	/* keep last */
+	F_NUM_FIELDS
+};
+
+struct rtl9300_i2c_drv_data {
+	struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS];
+	int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl);
+	u32 data_reg;
+	u8 max_nchan;
+};
+
 #define RTL9300_I2C_MUX_NCHAN	8
 
 struct rtl9300_i2c {
 	struct regmap *regmap;
 	struct device *dev;
 	struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN];
+	struct regmap_field *fields[F_NUM_FIELDS];
 	u32 reg_base;
+	u32 data_reg;
 	u8 sda_pin;
 	struct mutex lock;
 };
 
 #define RTL9300_I2C_MST_CTRL1				0x0
-#define  RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS		8
-#define  RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK		GENMASK(31, 8)
-#define  RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS		4
-#define  RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK		GENMASK(6, 4)
-#define  RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL		BIT(3)
-#define  RTL9300_I2C_MST_CTRL1_RWOP			BIT(2)
-#define  RTL9300_I2C_MST_CTRL1_I2C_FAIL			BIT(1)
-#define  RTL9300_I2C_MST_CTRL1_I2C_TRIG			BIT(0)
 #define RTL9300_I2C_MST_CTRL2				0x4
-#define  RTL9300_I2C_MST_CTRL2_RD_MODE			BIT(15)
-#define  RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS		8
-#define  RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK		GENMASK(14, 8)
-#define  RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS		4
-#define  RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK		GENMASK(7, 4)
-#define  RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS	2
-#define  RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK	GENMASK(3, 2)
-#define  RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS		0
-#define  RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK		GENMASK(1, 0)
 #define RTL9300_I2C_MST_DATA_WORD0			0x8
 #define RTL9300_I2C_MST_DATA_WORD1			0xc
 #define RTL9300_I2C_MST_DATA_WORD2			0x10
 #define RTL9300_I2C_MST_DATA_WORD3			0x14
-
 #define RTL9300_I2C_MST_GLB_CTRL			0x384
 
 static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
 {
-	u32 val, mask;
 	int ret;
 
-	val = len << RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_OFS;
-	mask = RTL9300_I2C_MST_CTRL2_MEM_ADDR_WIDTH_MASK;
-
-	ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
+	ret = regmap_field_write(i2c->fields[F_MEM_ADDR_WIDTH], len);
 	if (ret)
 		return ret;
 
-	val = reg << RTL9300_I2C_MST_CTRL1_MEM_ADDR_OFS;
-	mask = RTL9300_I2C_MST_CTRL1_MEM_ADDR_MASK;
+	return regmap_field_write(i2c->fields[F_MEM_ADDR], reg);
+}
 
-	return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
+{
+	return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
 }
 
 static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
 {
+	struct rtl9300_i2c_drv_data *drv_data;
 	int ret;
-	u32 val, mask;
 
-	ret = regmap_update_bits(i2c->regmap, RTL9300_I2C_MST_GLB_CTRL, BIT(sda_pin), BIT(sda_pin));
+	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+
+	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_pin), BIT(sda_pin));
 	if (ret)
 		return ret;
 
-	val = (sda_pin << RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_OFS) |
-		RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
-	mask = RTL9300_I2C_MST_CTRL1_SDA_OUT_SEL_MASK | RTL9300_I2C_MST_CTRL1_GPIO_SCL_SEL;
+	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_pin);
+	if (ret)
+		return ret;
 
-	return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+	return drv_data->select_scl(i2c, 0);
 }
 
 static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
 				   u16 addr, u16 len)
 {
-	u32 val, mask;
-
-	val = chan->bus_freq << RTL9300_I2C_MST_CTRL2_SCL_FREQ_OFS;
-	mask = RTL9300_I2C_MST_CTRL2_SCL_FREQ_MASK;
+	int ret;
 
-	val |= addr << RTL9300_I2C_MST_CTRL2_DEV_ADDR_OFS;
-	mask |= RTL9300_I2C_MST_CTRL2_DEV_ADDR_MASK;
+	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
+	if (ret)
+		return ret;
 
-	val |= ((len - 1) & 0xf) << RTL9300_I2C_MST_CTRL2_DATA_WIDTH_OFS;
-	mask |= RTL9300_I2C_MST_CTRL2_DATA_WIDTH_MASK;
+	ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr);
+	if (ret)
+		return ret;
 
-	mask |= RTL9300_I2C_MST_CTRL2_RD_MODE;
+	ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf);
+	if (ret)
+		return ret;
 
-	return regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL2, mask, val);
+	return regmap_field_write(i2c->fields[F_RD_MODE], 0);
 }
 
 static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
@@ -121,8 +141,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
 	if (len > 16)
 		return -EIO;
 
-	ret = regmap_bulk_read(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
-			       vals, ARRAY_SIZE(vals));
+	ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
 	if (ret)
 		return ret;
 
@@ -149,52 +168,49 @@ static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
 		vals[reg] |= buf[i] << shift;
 	}
 
-	return regmap_bulk_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0,
-				vals, ARRAY_SIZE(vals));
+	return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
 }
 
 static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
 {
-	return regmap_write(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, data);
+	return regmap_write(i2c->regmap, i2c->data_reg, data);
 }
 
 static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
 				    int size, union i2c_smbus_data *data, int len)
 {
-	u32 val, mask;
+	u32 val;
 	int ret;
 
-	val = read_write == I2C_SMBUS_WRITE ? RTL9300_I2C_MST_CTRL1_RWOP : 0;
-	mask = RTL9300_I2C_MST_CTRL1_RWOP;
-
-	val |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
-	mask |= RTL9300_I2C_MST_CTRL1_I2C_TRIG;
+	ret = regmap_field_write(i2c->fields[F_RWOP], read_write == I2C_SMBUS_WRITE);
+	if (ret)
+		return ret;
 
-	ret = regmap_update_bits(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1, mask, val);
+	ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1);
 	if (ret)
 		return ret;
 
-	ret = regmap_read_poll_timeout(i2c->regmap, i2c->reg_base + RTL9300_I2C_MST_CTRL1,
-				       val, !(val & RTL9300_I2C_MST_CTRL1_I2C_TRIG), 100, 100000);
+	ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
 	if (ret)
 		return ret;
 
-	if (val & RTL9300_I2C_MST_CTRL1_I2C_FAIL)
+	ret = regmap_field_read(i2c->fields[F_I2C_FAIL], &val);
+	if (ret)
+		return ret;
+	if (val)
 		return -EIO;
 
 	if (read_write == I2C_SMBUS_READ) {
 		switch (size) {
 		case I2C_SMBUS_BYTE:
 		case I2C_SMBUS_BYTE_DATA:
-			ret = regmap_read(i2c->regmap,
-					  i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
+			ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
 			if (ret)
 				return ret;
 			data->byte = val & 0xff;
 			break;
 		case I2C_SMBUS_WORD_DATA:
-			ret = regmap_read(i2c->regmap,
-					  i2c->reg_base + RTL9300_I2C_MST_DATA_WORD0, &val);
+			ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
 			if (ret)
 				return ret;
 			data->word = val & 0xffff;
@@ -362,9 +378,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rtl9300_i2c *i2c;
+	struct fwnode_handle *child;
+	struct rtl9300_i2c_drv_data *drv_data;
+	struct reg_field fields[F_NUM_FIELDS];
 	u32 clock_freq, sda_pin;
 	int ret, i = 0;
-	struct fwnode_handle *child;
 
 	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
 	if (!i2c)
@@ -383,9 +401,22 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, i2c);
 
-	if (device_get_child_node_count(dev) >= RTL9300_I2C_MUX_NCHAN)
+	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+	if (device_get_child_node_count(dev) >= drv_data->max_nchan)
 		return dev_err_probe(dev, -EINVAL, "Too many channels\n");
 
+	i2c->data_reg = i2c->reg_base + drv_data->data_reg;
+	for (i = 0; i < F_NUM_FIELDS; i++) {
+		fields[i] = drv_data->field_desc[i].field;
+		if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER)
+			fields[i].reg += i2c->reg_base;
+	}
+	ret = devm_regmap_field_bulk_alloc(dev, i2c->regmap, i2c->fields,
+					   fields, F_NUM_FIELDS);
+	if (ret)
+		return ret;
+
+	i = 0;
 	device_for_each_child_node(dev, child) {
 		struct rtl9300_i2c_chan *chan = &i2c->chans[i];
 		struct i2c_adapter *adap = &chan->adap;
@@ -402,7 +433,6 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 		case I2C_MAX_STANDARD_MODE_FREQ:
 			chan->bus_freq = RTL9300_I2C_STD_FREQ;
 			break;
-
 		case I2C_MAX_FAST_MODE_FREQ:
 			chan->bus_freq = RTL9300_I2C_FAST_FREQ;
 			break;
@@ -434,11 +464,37 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 	return 0;
 }
 
+#define GLB_REG_FIELD(reg, msb, lsb)    \
+	{ .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_GLOBAL }
+#define MST_REG_FIELD(reg, msb, lsb)    \
+	{ .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_MASTER }
+
+static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = {
+	.field_desc = {
+		[F_MEM_ADDR]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 8, 31),
+		[F_SDA_OUT_SEL]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 4, 6),
+		[F_SCL_SEL]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 3, 3),
+		[F_RWOP]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 2, 2),
+		[F_I2C_FAIL]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 1, 1),
+		[F_I2C_TRIG]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+		[F_RD_MODE]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 15, 15),
+		[F_DEV_ADDR]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 8, 14),
+		[F_DATA_WIDTH]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 4, 7),
+		[F_MEM_ADDR_WIDTH]	= MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3),
+		[F_SCL_FREQ]		= MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1),
+		[F_SDA_SEL]		= GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7),
+	},
+	.select_scl = rtl9300_i2c_select_scl,
+	.data_reg = RTL9300_I2C_MST_DATA_WORD0,
+	.max_nchan = RTL9300_I2C_MUX_NCHAN,
+};
+
+
 static const struct of_device_id i2c_rtl9300_dt_ids[] = {
-	{ .compatible = "realtek,rtl9301-i2c" },
-	{ .compatible = "realtek,rtl9302b-i2c" },
-	{ .compatible = "realtek,rtl9302c-i2c" },
-	{ .compatible = "realtek,rtl9303-i2c" },
+	{ .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+	{ .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+	{ .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+	{ .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 02/11] i2c: rtl9300: fix channel number bound check
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 01/11] i2c: rtl9300: use regmap fields and API for registers Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos Jonas Jelonek
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Fix the current check for number of channels (child nodes in the device
tree). Before, this was:

if (device_get_child_node_count(dev) >= drv_data->max_nchan)

drv_data->max_nchan gives the maximum number of channels so checking
with '>=' isn't correct because it doesn't allow the last channel
number. Thus, fix it to:

if (device_get_child_node_count(dev) > drv_data->max_nchan)

Issue occured on a TP-Link TL-ST1008F v2.0 device (8 SFP+ ports) and fix
is tested there.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index e6eb6a32fde2..68acbb6cc5a4 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -402,7 +402,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, i2c);
 
 	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
-	if (device_get_child_node_count(dev) >= drv_data->max_nchan)
+	if (device_get_child_node_count(dev) > drv_data->max_nchan)
 		return dev_err_probe(dev, -EINVAL, "Too many channels\n");
 
 	i2c->data_reg = i2c->reg_base + drv_data->data_reg;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 01/11] i2c: rtl9300: use regmap fields and API for registers Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 02/11] i2c: rtl9300: fix channel number bound check Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-18 15:10   ` Rob Herring (Arm)
  2025-08-09 22:07 ` [PATCH v5 04/11] i2c: rtl9300: rename internal sda_pin to sda_num Jonas Jelonek
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Fix wording of binding description to use plural because there is not
only a single RTL9300 SoC. RTL9300 describes a whole family of Realtek
SoCs.

Add missing word 'of' in description of reg property.

Change 'SDA pin' to 'SDA line number' because the property must contain
the SDA (channel) number ranging from 0-7 instead of a real pin number.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 .../devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml        | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
index 69ac5db8b914..274e2ab8b612 100644
--- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
@@ -10,7 +10,7 @@ maintainers:
   - Chris Packham <chris.packham@alliedtelesis.co.nz>
 
 description:
-  The RTL9300 SoC has two I2C controllers. Each of these has an SCL line (which
+  RTL9300 SoCs have two I2C controllers. Each of these has an SCL line (which
   if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be
   assigned to either I2C controller.
 
@@ -27,7 +27,7 @@ properties:
 
   reg:
     items:
-      - description: Register offset and size this I2C controller.
+      - description: Register offset and size of this I2C controller.
 
   "#address-cells":
     const: 1
@@ -42,7 +42,7 @@ patternProperties:
 
     properties:
       reg:
-        description: The SDA pin associated with the I2C bus.
+        description: The SDA line number associated with the I2C bus.
         maxItems: 1
 
     required:
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 04/11] i2c: rtl9300: rename internal sda_pin to sda_num
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (2 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid Jonas Jelonek
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Rename the internally used 'sda_pin' to 'sda_num' to make it clear that
this is NOT the actual pin number of the GPIO pin but rather the logical
SDA channel number. Although the alternate function SDA_Y is sometimes
given with the GPIO number, this is not always the case. Thus, avoid any
confusion or misconfiguration by giving the variable the correct name.

This follows the description change in the devicetree bindings.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 68acbb6cc5a4..fb1ea2961cfb 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -20,7 +20,7 @@ struct rtl9300_i2c_chan {
 	struct i2c_adapter adap;
 	struct rtl9300_i2c *i2c;
 	enum rtl9300_bus_freq bus_freq;
-	u8 sda_pin;
+	u8 sda_num;
 };
 
 enum rtl9300_i2c_reg_scope {
@@ -67,7 +67,7 @@ struct rtl9300_i2c {
 	struct regmap_field *fields[F_NUM_FIELDS];
 	u32 reg_base;
 	u32 data_reg;
-	u8 sda_pin;
+	u8 sda_num;
 	struct mutex lock;
 };
 
@@ -102,11 +102,11 @@ static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
 
 	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
 
-	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_pin), BIT(sda_pin));
+	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_num), BIT(sda_num));
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_pin);
+	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_num);
 	if (ret)
 		return ret;
 
@@ -240,11 +240,11 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
 	int len = 0, ret;
 
 	mutex_lock(&i2c->lock);
-	if (chan->sda_pin != i2c->sda_pin) {
+	if (chan->sda_num != i2c->sda_num) {
 		ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
 		if (ret)
 			goto out_unlock;
-		i2c->sda_pin = chan->sda_pin;
+		i2c->sda_num = chan->sda_num;
 	}
 
 	switch (size) {
@@ -381,7 +381,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 	struct fwnode_handle *child;
 	struct rtl9300_i2c_drv_data *drv_data;
 	struct reg_field fields[F_NUM_FIELDS];
-	u32 clock_freq, sda_pin;
+	u32 clock_freq, sda_num;
 	int ret, i = 0;
 
 	i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL);
@@ -421,7 +421,7 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 		struct rtl9300_i2c_chan *chan = &i2c->chans[i];
 		struct i2c_adapter *adap = &chan->adap;
 
-		ret = fwnode_property_read_u32(child, "reg", &sda_pin);
+		ret = fwnode_property_read_u32(child, "reg", &sda_num);
 		if (ret)
 			return ret;
 
@@ -438,11 +438,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 			break;
 		default:
 			dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
-				 sda_pin, clock_freq);
+				 sda_num, clock_freq);
 			break;
 		}
 
-		chan->sda_pin = sda_pin;
+		chan->sda_num = sda_num;
 		chan->i2c = i2c;
 		adap = &i2c->chans[i].adap;
 		adap->owner = THIS_MODULE;
@@ -452,14 +452,14 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 		adap->dev.parent = dev;
 		i2c_set_adapdata(adap, chan);
 		adap->dev.of_node = to_of_node(child);
-		snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_pin);
+		snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num);
 		i++;
 
 		ret = devm_i2c_add_adapter(dev, adap);
 		if (ret)
 			return ret;
 	}
-	i2c->sda_pin = 0xff;
+	i2c->sda_num = 0xff;
 
 	return 0;
 }
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (3 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 04/11] i2c: rtl9300: rename internal sda_pin to sda_num Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-10  5:51   ` Wolfram Sang
  2025-08-09 22:07 ` [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support Jonas Jelonek
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer'
to make sure a length < 1 or > 16 isn't accepted. While there shouldn't
be a length > 16 because this is specified in the i2c_adapter_quirks, a
length of 0 may be passed. This is problematic, because the code adopts
this value with

(len - 1) & 0xf

because the corresponding register documentation states that the value
in the register is always used + 1 ([1]). Obvious reason for this is to
fit allow xfer length of 16 to be specified in this 4-bit wide register
field.

Another consequence of this is also, that an xfer length of 0 cannot be
set. Thus, an explicit check should avoid this. Before, this actually
led to writing 0xf into the register, probably causing unintended
behaviour.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index fb1ea2961cfb..35b05fb59f88 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -118,6 +118,9 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
 {
 	int ret;
 
+	if (len < 1 || len > 16)
+		return -EINVAL;
+
 	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
 	if (ret)
 		return ret;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (4 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-10  7:13   ` Sven Eckelmann
  2025-08-09 22:07 ` [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io Jonas Jelonek
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Remove the SMBus Quick operation from this driver because it is not
natively supported by the hardware and is wrongly implemented in the
driver.

The I2C controllers in Realtek RTL9300 and RTL9310 are SMBus-compliant
but there doesn't seem to be native support for the SMBus Quick
operation. It is not explicitly mentioned in the documentation but
looking at the registers which configure an SMBus transaction, one can
see that the data length cannot be set to 0. This suggests that the
hardware doesn't allow any SMBus message without data bytes (except for
those it does on it's own, see SMBus Block Read).

The current implementation of SMBus Quick operation passes a length of
0 (which is actually invalid). Before the fix of a bug in a previous
commit, this led to a read operation of 16 bytes from any register (the
one of a former transaction or any other value.

Although there are currently no reports of actual issues this caused.
However, as an example, i2cdetect by default uses Quick Write operation
to probe the bus and this may already write anything to some register
of a device, causing unintended behaviour. This could be the cause of a
recent brick of one of my DAC cables where there was a checksum mismatch
of the EEPROM after having run 'i2cdetect -l' before.

Because SMBus Quick operation is obviously not supported on these
controllers (because a length of 0 cannot be set, even when no register
address is set), remove that instead of claiming there is support. There
also shouldn't be any kind of emulated 'Quick' which just does another
kind of operation in the background. Otherwise, specific issues may
occur in case of a 'Quick' Write which writes unknown data to an unknown
register.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 16 +++-------------
 1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 35b05fb59f88..ead5aa6e60f8 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -251,15 +251,6 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
 	}
 
 	switch (size) {
-	case I2C_SMBUS_QUICK:
-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
-		if (ret)
-			goto out_unlock;
-		ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
-		if (ret)
-			goto out_unlock;
-		break;
-
 	case I2C_SMBUS_BYTE:
 		if (read_write == I2C_SMBUS_WRITE) {
 			ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
@@ -360,10 +351,9 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
 
 static u32 rtl9300_i2c_func(struct i2c_adapter *a)
 {
-	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
-	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
-	       I2C_FUNC_SMBUS_READ_I2C_BLOCK | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
-	       I2C_FUNC_SMBUS_BLOCK_DATA;
+	return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+	       I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_READ_I2C_BLOCK |
+	       I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA;
 }
 
 static const struct i2c_algorithm rtl9300_i2c_algo = {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (5 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-10  8:49   ` Markus Elfring
  2025-08-09 22:07 ` [PATCH v5 08/11] i2c: rtl9300: do not set read mode on every transfer Jonas Jelonek
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Move the register operation to set the SCL frequency to the
rtl9300_i2c_config_io function instead of the rtl9300_i2c_config_xfer
function. This rather belongs there next to selecting the current SDA
output line.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index ead5aa6e60f8..8e8e98108750 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -95,18 +95,23 @@ static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
 	return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
 }
 
-static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, u8 sda_pin)
+static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
 {
 	struct rtl9300_i2c_drv_data *drv_data;
 	int ret;
 
 	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
 
-	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(sda_num), BIT(sda_num));
+	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
+				       BIT(chan->sda_num));
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], sda_num);
+	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
 	if (ret)
 		return ret;
 
@@ -121,10 +126,6 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
 	if (len < 1 || len > 16)
 		return -EINVAL;
 
-	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
-	if (ret)
-		return ret;
-
 	ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr);
 	if (ret)
 		return ret;
@@ -244,7 +245,7 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
 
 	mutex_lock(&i2c->lock);
 	if (chan->sda_num != i2c->sda_num) {
-		ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
+		ret = rtl9300_i2c_config_io(i2c, chan);
 		if (ret)
 			goto out_unlock;
 		i2c->sda_num = chan->sda_num;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 08/11] i2c: rtl9300: do not set read mode on every transfer
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (6 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 09/11] i2c: rtl9300: separate xfer configuration and execution Jonas Jelonek
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Move the operation to set the read mode from config_xfer to probe.

The I2C controller of RTL9300 and RTL9310 support a legacy message mode
for READs with 'Read Address Data' instead of the standard format 'Write
Address ; Read Data'. There is no way to pass that via smbus_xfer, thus
there is no point in supported this in the driver and moreover no point
in setting this on every transaction. Setting this once in the probe
call is sufficient.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 8e8e98108750..4d3fcb5efc36 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -130,11 +130,7 @@ static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf);
-	if (ret)
-		return ret;
-
-	return regmap_field_write(i2c->fields[F_RD_MODE], 0);
+	return regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf);
 }
 
 static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
@@ -455,6 +451,11 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 	}
 	i2c->sda_num = 0xff;
 
+	/* only use standard read format */
+	ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 09/11] i2c: rtl9300: separate xfer configuration and execution
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (7 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 08/11] i2c: rtl9300: do not set read mode on every transfer Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support Jonas Jelonek
  2025-08-09 22:07 ` [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller Jonas Jelonek
  10 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

So far, the rtl9300_i2c_smbus_xfer code is quite a mess with function
calls distributed over the whole function setting different values in
different cases. Calls to rtl9300_i2c_config_xfer and
rtl9300_i2c_reg_addr_set are used in every case-block with varying
values whose meaning is not instantly obvious. In some cases, there are
additional calls within these case-blocks doing more things.

This is in general a bad design and especially really bad for
readability and maintainability because it distributes changes or
issues to multiple locations due to the same function being called with
different hardcoded values in different places.

To have a good structure, setting different parameters based on the
desired operation should not be interleaved with applying these
parameters to the hardware registers. Or in different words, the
parameter site should be mixed with the call site.

Thus, separate configuration and execution of an SMBus xfer within
rtl9300_i2c_smbus_xfer to improve readability and maintainability. Add a
new 'struct rtl9300_i2c_xfer' to carry the required parameters for an
xfer which are configured based on the input parameters within a single
switch-case block, without having any function calls within this block.

The function calls to actually apply these values to the hardware
registers then appear below in a single place and just operate on the
passed instance of 'struct rtl9300_i2c_xfer'. These are
'rtl9300_i2c_prepare_xfer' which combines applying all parameters of the
xfer to the corresponding register, and 'rtl9300_i2c_do_xfer' which
actually executes the xfer and does post-processing if needed.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 234 +++++++++++++++----------------
 1 file changed, 114 insertions(+), 120 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 4d3fcb5efc36..73eb35052077 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -8,6 +8,7 @@
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/unaligned.h>
 
 enum rtl9300_bus_freq {
 	RTL9300_I2C_STD_FREQ,
@@ -71,6 +72,22 @@ struct rtl9300_i2c {
 	struct mutex lock;
 };
 
+enum rtl9300_i2c_xfer_type {
+	RTL9300_I2C_XFER_BYTE,
+	RTL9300_I2C_XFER_WORD,
+	RTL9300_I2C_XFER_BLOCK,
+};
+
+struct rtl9300_i2c_xfer {
+	enum rtl9300_i2c_xfer_type type;
+	u16 dev_addr;
+	u8 reg_addr;
+	u8 reg_addr_len;
+	u8 *data;
+	u8 data_len;
+	bool write;
+};
+
 #define RTL9300_I2C_MST_CTRL1				0x0
 #define RTL9300_I2C_MST_CTRL2				0x4
 #define RTL9300_I2C_MST_DATA_WORD0			0x8
@@ -95,45 +112,37 @@ static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
 	return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
 }
 
-static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
+static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
 {
 	struct rtl9300_i2c_drv_data *drv_data;
 	int ret;
 
-	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+	if (i2c->sda_num == chan->sda_num)
+		return 0;
 
-	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
-				       BIT(chan->sda_num));
+	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
+	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
+	ret = drv_data->select_scl(i2c, 0);
 	if (ret)
 		return ret;
 
-	ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
+	ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
+				       BIT(chan->sda_num));
 	if (ret)
 		return ret;
 
-	return drv_data->select_scl(i2c, 0);
-}
-
-static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
-				   u16 addr, u16 len)
-{
-	int ret;
-
-	if (len < 1 || len > 16)
-		return -EINVAL;
-
-	ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr);
+	ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
 	if (ret)
 		return ret;
 
-	return regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf);
+	i2c->sda_num = chan->sda_num;
+	return 0;
 }
 
-static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
+static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
 {
 	u32 vals[4] = {};
 	int i, ret;
@@ -153,7 +162,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
 	return 0;
 }
 
-static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
+static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
 {
 	u32 vals[4] = {};
 	int i;
@@ -176,16 +185,51 @@ static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
 	return regmap_write(i2c->regmap, i2c->data_reg, data);
 }
 
-static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
-				    int size, union i2c_smbus_data *data, int len)
+static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
 {
-	u32 val;
 	int ret;
 
-	ret = regmap_field_write(i2c->fields[F_RWOP], read_write == I2C_SMBUS_WRITE);
+	if (xfer->data_len < 1 || xfer->data_len > 16)
+		return -EINVAL;
+
+	ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
+	if (ret)
+		return ret;
+
+	ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf);
 	if (ret)
 		return ret;
 
+	if (xfer->write) {
+		switch (xfer->type) {
+		case RTL9300_I2C_XFER_BYTE:
+			ret = rtl9300_i2c_writel(i2c, *xfer->data);
+			break;
+		case RTL9300_I2C_XFER_WORD:
+			ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data));
+			break;
+		default:
+			ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+{
+	u32 val;
+	int ret;
+
 	ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1);
 	if (ret)
 		return ret;
@@ -200,28 +244,24 @@ static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
 	if (val)
 		return -EIO;
 
-	if (read_write == I2C_SMBUS_READ) {
-		switch (size) {
-		case I2C_SMBUS_BYTE:
-		case I2C_SMBUS_BYTE_DATA:
+	if (!xfer->write) {
+		switch (xfer->type) {
+		case RTL9300_I2C_XFER_BYTE:
 			ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
 			if (ret)
 				return ret;
-			data->byte = val & 0xff;
+
+			*xfer->data = val & 0xff;
 			break;
-		case I2C_SMBUS_WORD_DATA:
+		case RTL9300_I2C_XFER_WORD:
 			ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
 			if (ret)
 				return ret;
-			data->word = val & 0xffff;
-			break;
-		case I2C_SMBUS_I2C_BLOCK_DATA:
-			ret = rtl9300_i2c_read(i2c, &data->block[1], len);
-			if (ret)
-				return ret;
+
+			put_unaligned(val & 0xffff, (u16*)xfer->data);
 			break;
 		default:
-			ret = rtl9300_i2c_read(i2c, &data->block[0], len);
+			ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len);
 			if (ret)
 				return ret;
 			break;
@@ -237,108 +277,62 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
 {
 	struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
 	struct rtl9300_i2c *i2c = chan->i2c;
-	int len = 0, ret;
+	struct rtl9300_i2c_xfer xfer = {0};
+	int ret;
+
+	if (addr > 0x7f)
+		return -EINVAL;
 
 	mutex_lock(&i2c->lock);
-	if (chan->sda_num != i2c->sda_num) {
-		ret = rtl9300_i2c_config_io(i2c, chan);
-		if (ret)
-			goto out_unlock;
-		i2c->sda_num = chan->sda_num;
-	}
+
+	ret = rtl9300_i2c_config_chan(i2c, chan);
+	if (ret)
+		goto out_unlock;
+
+	xfer.dev_addr = addr & 0x7f;
+	xfer.write = (read_write == I2C_SMBUS_WRITE);
+	xfer.reg_addr = command;
+	xfer.reg_addr_len = 1;
 
 	switch (size) {
 	case I2C_SMBUS_BYTE:
-		if (read_write == I2C_SMBUS_WRITE) {
-			ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
-			if (ret)
-				goto out_unlock;
-			ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
-			if (ret)
-				goto out_unlock;
-		} else {
-			ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
-			if (ret)
-				goto out_unlock;
-			ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
-			if (ret)
-				goto out_unlock;
-		}
+		xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command;
+		xfer.data_len = 1;
+		xfer.reg_addr = 0;
+		xfer.reg_addr_len = 0;
+		xfer.type = RTL9300_I2C_XFER_BYTE;
 		break;
-
 	case I2C_SMBUS_BYTE_DATA:
-		ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
-		if (ret)
-			goto out_unlock;
-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
-		if (ret)
-			goto out_unlock;
-		if (read_write == I2C_SMBUS_WRITE) {
-			ret = rtl9300_i2c_writel(i2c, data->byte);
-			if (ret)
-				goto out_unlock;
-		}
+		xfer.data = &data->byte;
+		xfer.data_len = 1;
+		xfer.type = RTL9300_I2C_XFER_BYTE;
 		break;
-
 	case I2C_SMBUS_WORD_DATA:
-		ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
-		if (ret)
-			goto out_unlock;
-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2);
-		if (ret)
-			goto out_unlock;
-		if (read_write == I2C_SMBUS_WRITE) {
-			ret = rtl9300_i2c_writel(i2c, data->word);
-			if (ret)
-				goto out_unlock;
-		}
+		xfer.data = (u8 *)&data->word;
+		xfer.data_len = 2;
+		xfer.type = RTL9300_I2C_XFER_WORD;
 		break;
-
 	case I2C_SMBUS_BLOCK_DATA:
-		ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
-		if (ret)
-			goto out_unlock;
-		if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
-			ret = -EINVAL;
-			goto out_unlock;
-		}
-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1);
-		if (ret)
-			goto out_unlock;
-		if (read_write == I2C_SMBUS_WRITE) {
-			ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1);
-			if (ret)
-				goto out_unlock;
-		}
-		len = data->block[0] + 1;
+		xfer.data = &data->block[0];
+		xfer.data_len = data->block[0] + 1;
+		xfer.type = RTL9300_I2C_XFER_BLOCK;
 		break;
-
 	case I2C_SMBUS_I2C_BLOCK_DATA:
-		ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
-		if (ret)
-			goto out_unlock;
-		if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
-			ret = -EINVAL;
-			goto out_unlock;
-		}
-		ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]);
-		if (ret)
-			goto out_unlock;
-		if (read_write == I2C_SMBUS_WRITE) {
-			ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]);
-			if (ret)
-				goto out_unlock;
-		}
-		len = data->block[0];
+		xfer.data = &data->block[1];
+		xfer.data_len = data->block[0];
+		xfer.type = RTL9300_I2C_XFER_BLOCK;
 		break;
-
 	default:
 		dev_err(&adap->dev, "Unsupported transaction %d\n", size);
 		ret = -EOPNOTSUPP;
 		goto out_unlock;
 	}
 
-	ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len);
+	ret = rtl9300_i2c_prepare_xfer(i2c, &xfer);
+	if (ret)
+		goto out_unlock;
+
+	ret = rtl9300_i2c_do_xfer(i2c, &xfer);
 
 out_unlock:
 	mutex_unlock(&i2c->lock);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (8 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 09/11] i2c: rtl9300: separate xfer configuration and execution Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-18 15:13   ` Rob Herring (Arm)
  2025-08-09 22:07 ` [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller Jonas Jelonek
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Adjust the regex for child-node address to account for the fact that
RTL9310 supports 12 instead of only 8 SDA lines. Also, narrow this per
variant.

Add a vendor-specific property to explicitly specify the
Realtek-internal ID of the defined I2C controller/master. This is
required, in particular for RTL9310, to describe the correct I2C
master. Require this property for RTL9310.

Add compatibles for known SoC variants RTL9311, RTL9312 and RTL9313.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 .../bindings/i2c/realtek,rtl9301-i2c.yaml     | 39 ++++++++++++++++++-
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
index 274e2ab8b612..17ce39c19ab1 100644
--- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
+++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
@@ -13,6 +13,8 @@ description:
   RTL9300 SoCs have two I2C controllers. Each of these has an SCL line (which
   if not-used for SCL can be a GPIO). There are 8 common SDA lines that can be
   assigned to either I2C controller.
+  RTL9310 SoCs have equal capabilities but support 12 common SDA lines which
+  can be assigned to either I2C controller.
 
 properties:
   compatible:
@@ -23,7 +25,15 @@ properties:
               - realtek,rtl9302c-i2c
               - realtek,rtl9303-i2c
           - const: realtek,rtl9301-i2c
-      - const: realtek,rtl9301-i2c
+      - items:
+          - enum:
+              - realtek,rtl9311-i2c
+              - realtek,rtl9312-i2c
+              - realtek,rtl9313-i2c
+          - const: realtek,rtl9310-i2c
+      - enum:
+          - realtek,rtl9301-i2c
+          - realtek,rtl9310-i2c
 
   reg:
     items:
@@ -35,8 +45,14 @@ properties:
   "#size-cells":
     const: 0
 
+  realtek,scl:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    description:
+      The SCL line number of this I2C controller.
+    enum: [ 0, 1 ]
+
 patternProperties:
-  '^i2c@[0-7]$':
+  '^i2c@[0-9ab]$':
     $ref: /schemas/i2c/i2c-controller.yaml
     unevaluatedProperties: false
 
@@ -48,6 +64,25 @@ patternProperties:
     required:
       - reg
 
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: realtek,rtl9310-i2c
+    then:
+      required:
+        - realtek,scl
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: realtek,rtl9301-i2c
+    then:
+      patternProperties:
+        '^i2c@[89ab]$': false
+
 required:
   - compatible
   - reg
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller
  2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
                   ` (9 preceding siblings ...)
  2025-08-09 22:07 ` [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support Jonas Jelonek
@ 2025-08-09 22:07 ` Jonas Jelonek
  2025-08-10 10:39   ` Sven Eckelmann
  10 siblings, 1 reply; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-09 22:07 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel, Jonas Jelonek

Add support for the internal I2C controllers of RTL9310 series based
SoCs to the driver for RTL9300. Add register definitions, chip-specific
functions and compatible strings for known RTL9310-based SoCs RTL9311,
RTL9312 and RTL9313.

Make use of a new device tree property 'realtek,scl' which needs to be
specified in case both or only the second master is used. This is
required due how the register layout changed in contrast to RTL9300,
which has SCL selection in a global register instead of a
master-specific one.

Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
---
 drivers/i2c/busses/i2c-rtl9300.c | 44 ++++++++++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c
index 73eb35052077..2261a08e07a6 100644
--- a/drivers/i2c/busses/i2c-rtl9300.c
+++ b/drivers/i2c/busses/i2c-rtl9300.c
@@ -60,14 +60,16 @@ struct rtl9300_i2c_drv_data {
 };
 
 #define RTL9300_I2C_MUX_NCHAN	8
+#define RTL9310_I2C_MUX_NCHAN	12
 
 struct rtl9300_i2c {
 	struct regmap *regmap;
 	struct device *dev;
-	struct rtl9300_i2c_chan chans[RTL9300_I2C_MUX_NCHAN];
+	struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
 	struct regmap_field *fields[F_NUM_FIELDS];
 	u32 reg_base;
 	u32 data_reg;
+	u8 scl_num;
 	u8 sda_num;
 	struct mutex lock;
 };
@@ -96,6 +98,12 @@ struct rtl9300_i2c_xfer {
 #define RTL9300_I2C_MST_DATA_WORD3			0x14
 #define RTL9300_I2C_MST_GLB_CTRL			0x384
 
+#define RTL9310_I2C_MST_IF_CTRL				0x1004
+#define	RTL9310_I2C_MST_IF_SEL				0x1008
+#define	RTL9310_I2C_MST_CTRL				0x0
+#define	RTL9310_I2C_MST_MEMADDR_CTRL			0x4
+#define RTL9310_I2C_MST_DATA_CTRL			0x8
+
 static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
 {
 	int ret;
@@ -112,6 +120,11 @@ static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
 	return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
 }
 
+static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
+{
+	return regmap_field_update_bits(i2c->fields[F_SCL_SEL], BIT(scl), BIT(scl));
+}
+
 static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
 {
 	struct rtl9300_i2c_drv_data *drv_data;
@@ -125,7 +138,7 @@ static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_c
 		return ret;
 
 	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
-	ret = drv_data->select_scl(i2c, 0);
+	ret = drv_data->select_scl(i2c, i2c->scl_num);
 	if (ret)
 		return ret;
 
@@ -383,6 +396,10 @@ static int rtl9300_i2c_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = device_property_read_u8(dev, "realtek,scl", &i2c->scl_num);
+	if (ret || i2c->scl_num != 1)
+		i2c->scl_num = 0;
+
 	platform_set_drvdata(pdev, i2c);
 
 	drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
@@ -478,12 +495,35 @@ static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = {
 	.max_nchan = RTL9300_I2C_MUX_NCHAN,
 };
 
+static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+	.field_desc = {
+		[F_SCL_SEL]		= GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 12, 13),
+		[F_SDA_SEL]		= GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 0, 11),
+		[F_SCL_FREQ]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 30, 31),
+		[F_DEV_ADDR]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 11, 17),
+		[F_SDA_OUT_SEL]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 18, 21),
+		[F_MEM_ADDR_WIDTH]	= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 9, 10),
+		[F_DATA_WIDTH]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 5, 8),
+		[F_RD_MODE]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 4, 4),
+		[F_RWOP]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 2, 2),
+		[F_I2C_FAIL]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1),
+		[F_I2C_TRIG]		= MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+		[F_MEM_ADDR]		= MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23),
+	},
+	.select_scl = rtl9310_i2c_select_scl,
+	.data_reg = RTL9310_I2C_MST_DATA_CTRL,
+	.max_nchan = RTL9310_I2C_MUX_NCHAN,
+};
 
 static const struct of_device_id i2c_rtl9300_dt_ids[] = {
 	{ .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data },
 	{ .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data },
 	{ .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data },
 	{ .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data },
+	{ .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+	{ .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+	{ .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data },
+	{ .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data },
 	{}
 };
 MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid
  2025-08-09 22:07 ` [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid Jonas Jelonek
@ 2025-08-10  5:51   ` Wolfram Sang
  2025-08-10  7:01     ` Sven Eckelmann
  0 siblings, 1 reply; 23+ messages in thread
From: Wolfram Sang @ 2025-08-10  5:51 UTC (permalink / raw)
  To: Jonas Jelonek
  Cc: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Sven Eckelmann, Harshal Gohel

[-- Attachment #1: Type: text/plain, Size: 412 bytes --]

On Sat, Aug 09, 2025 at 10:07:06PM +0000, Jonas Jelonek wrote:
> Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer'
> to make sure a length < 1 or > 16 isn't accepted. While there shouldn't
> be a length > 16 because this is specified in the i2c_adapter_quirks, a
> length of 0 may be passed.

There is another quirk for this: I2C_AQ_NO_ZERO_LEN

With that, you shouldn't need the code here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid
  2025-08-10  5:51   ` Wolfram Sang
@ 2025-08-10  7:01     ` Sven Eckelmann
  2025-08-10  9:22       ` Jonas Jelonek
  0 siblings, 1 reply; 23+ messages in thread
From: Sven Eckelmann @ 2025-08-10  7:01 UTC (permalink / raw)
  To: Jonas Jelonek, Wolfram Sang
  Cc: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Harshal Gohel

[-- Attachment #1: Type: text/plain, Size: 1487 bytes --]

On Sunday, 10 August 2025 07:51:12 CEST Wolfram Sang wrote:
> On Sat, Aug 09, 2025 at 10:07:06PM +0000, Jonas Jelonek wrote:
> > Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer'
> > to make sure a length < 1 or > 16 isn't accepted. While there shouldn't
> > be a length > 16 because this is specified in the i2c_adapter_quirks, a
> > length of 0 may be passed.
> 
> There is another quirk for this: I2C_AQ_NO_ZERO_LEN
> 
> With that, you shouldn't need the code here.

I am a little bit lost here. Let us assume that i2c_smbus_write_byte_data() is 
called - for example by an in-kernel driver. We would then have following call 
chain:

* i2c_smbus_write_byte_data
* i2c_smbus_xfer
* __i2c_smbus_xfer
* adapter->algo->smbus_xfer (aka rtl9300_i2c_smbus_xfer)

But the quirk is only checked in i2c_check_for_quirks - and then on 
`struct i2c_msg` and not `union i2c_smbus_data`. And this is only called by 
__i2c_transfer (which is called by i2c_transfer, i2c_smbus_xfer_emulated, 
...). But on first glance, it didn't look like it will be called when using 
i2c_smbus_write_byte_data - unless __i2c_smbus_xfer fails and must fall back 
to i2c_smbus_xfer_emulated. I most likely missed something when doing a quick 
check of the source code. Maybe you can point it out.

And I might have to point out that I am currently not next to the actual HW to 
check if my statement that adapter->algo->smbus_xfer == rtl9300_i2c_smbus_xfer 
is really true.

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support
  2025-08-09 22:07 ` [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support Jonas Jelonek
@ 2025-08-10  7:13   ` Sven Eckelmann
  2025-08-10  9:31     ` Jonas Jelonek
  0 siblings, 1 reply; 23+ messages in thread
From: Sven Eckelmann @ 2025-08-10  7:13 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	Jonas Jelonek
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Harshal Gohel, Jonas Jelonek

[-- Attachment #1: Type: text/plain, Size: 1128 bytes --]

On Sunday, 10 August 2025 00:07:07 CEST Jonas Jelonek wrote:
[...]
> The current implementation of SMBus Quick operation passes a length of
> 0 (which is actually invalid). Before the fix of a bug in a previous
> commit, this led to a read operation of 16 bytes from any register (the
> one of a former transaction or any other value.
> 
> Although there are currently no reports of actual issues this caused.
> However, as an example, i2cdetect by default uses Quick Write operation
> to probe the bus and this may already write anything to some register
> of a device, causing unintended behaviour. This could be the cause of a
> recent brick of one of my DAC cables where there was a checksum mismatch
> of the EEPROM after having run 'i2cdetect -l' before.
[...]

Nice find. I've actually observed odd behavior after/during probing and 
attributed it only to the other problems (especially the low timeout + missing 
check) we found and never did a deep dive to figure out what happened on the 
bus during the probe. Possible that this could be related.

Reviewed-by: Sven Eckelmann <sven@narfation.org>

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io
  2025-08-09 22:07 ` [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io Jonas Jelonek
@ 2025-08-10  8:49   ` Markus Elfring
  2025-08-10  8:54     ` Sven Eckelmann
  2025-08-10  9:10     ` Jonas Jelonek
  0 siblings, 2 replies; 23+ messages in thread
From: Markus Elfring @ 2025-08-10  8:49 UTC (permalink / raw)
  To: Jonas Jelonek, linux-i2c, devicetree, Andi Shyti, Chris Packham,
	Krzysztof Kozlowski, Rob Herring
  Cc: LKML, Conor Dooley, Harshal Gohel, Markus Stockhausen,
	Sven Eckelmann

…
> +++ b/drivers/i2c/busses/i2c-rtl9300.c
> +static int mshv_vtl_sint_ioctl_set_eventfd(struct mshv_vtl_set_eventfd __user *arg)
> +{
> @@ -244,7 +245,7 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
>  
>  	mutex_lock(&i2c->lock);
>  	if (chan->sda_num != i2c->sda_num) {
> -		ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
> +		ret = rtl9300_i2c_config_io(i2c, chan);
>  		if (ret)
>  			goto out_unlock;
…

Under which circumstances would you become interested to apply a statement
like “guard(mutex)(&i2c->lock);”?
https://elixir.bootlin.com/linux/v6.16/source/include/linux/mutex.h#L225

Regards,
Markus

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io
  2025-08-10  8:49   ` Markus Elfring
@ 2025-08-10  8:54     ` Sven Eckelmann
  2025-08-10  9:10     ` Jonas Jelonek
  1 sibling, 0 replies; 23+ messages in thread
From: Sven Eckelmann @ 2025-08-10  8:54 UTC (permalink / raw)
  To: Jonas Jelonek, linux-i2c, devicetree, Andi Shyti, Chris Packham,
	Krzysztof Kozlowski, Rob Herring, Markus Elfring
  Cc: LKML, Conor Dooley, Harshal Gohel, Markus Stockhausen

[-- Attachment #1: Type: text/plain, Size: 864 bytes --]

On Sunday, 10 August 2025 10:49:02 CEST Markus Elfring wrote:
> …
> > +++ b/drivers/i2c/busses/i2c-rtl9300.c
> …
> > +static int mshv_vtl_sint_ioctl_set_eventfd(struct mshv_vtl_set_eventfd __user *arg)
> > +{
> …
> > @@ -244,7 +245,7 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
> >  
> >  	mutex_lock(&i2c->lock);
> >  	if (chan->sda_num != i2c->sda_num) {
> > -		ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
> > +		ret = rtl9300_i2c_config_io(i2c, chan);
> >  		if (ret)
> >  			goto out_unlock;
> …
> 
> Under which circumstances would you become interested to apply a statement
> like “guard(mutex)(&i2c->lock);”?
> https://elixir.bootlin.com/linux/v6.16/source/include/linux/mutex.h#L225

https://lwn.net/Articles/934679/ ("From cleanup functions to classes")

Kind regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io
  2025-08-10  8:49   ` Markus Elfring
  2025-08-10  8:54     ` Sven Eckelmann
@ 2025-08-10  9:10     ` Jonas Jelonek
  1 sibling, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-10  9:10 UTC (permalink / raw)
  To: Markus Elfring, linux-i2c, devicetree, Andi Shyti, Chris Packham,
	Krzysztof Kozlowski, Rob Herring
  Cc: LKML, Conor Dooley, Harshal Gohel, Markus Stockhausen,
	Sven Eckelmann


On 10.08.2025 10:49, Markus Elfring wrote:
> …
>> +++ b/drivers/i2c/busses/i2c-rtl9300.c
> …
>> +static int mshv_vtl_sint_ioctl_set_eventfd(struct mshv_vtl_set_eventfd __user *arg)
>> +{
> …
>> @@ -244,7 +245,7 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
>>  
>>  	mutex_lock(&i2c->lock);
>>  	if (chan->sda_num != i2c->sda_num) {
>> -		ret = rtl9300_i2c_config_io(i2c, chan->sda_pin);
>> +		ret = rtl9300_i2c_config_io(i2c, chan);
>>  		if (ret)
>>  			goto out_unlock;
> …
>
> Under which circumstances would you become interested to apply a statement
> like “guard(mutex)(&i2c->lock);”?
> https://elixir.bootlin.com/linux/v6.16/source/include/linux/mutex.h#L225

Didn't know about that before but no objections against it. Can integrate that
in the next version.

The link Sven posted was quite helpful on that, thanks! This looks quite similar
to how it is in Rust, that you just lock/guard it and it is dropped at the end of
the current scope. I like that :)

> Regards,
> Markus

Best regards,
Jonas

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid
  2025-08-10  7:01     ` Sven Eckelmann
@ 2025-08-10  9:22       ` Jonas Jelonek
  0 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-10  9:22 UTC (permalink / raw)
  To: Sven Eckelmann, Wolfram Sang
  Cc: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Harshal Gohel


On 10.08.2025 09:01, Sven Eckelmann wrote:
> On Sunday, 10 August 2025 07:51:12 CEST Wolfram Sang wrote:
>> On Sat, Aug 09, 2025 at 10:07:06PM +0000, Jonas Jelonek wrote:
>>> Add an explicit check for the xfer length to 'rtl9300_i2c_config_xfer'
>>> to make sure a length < 1 or > 16 isn't accepted. While there shouldn't
>>> be a length > 16 because this is specified in the i2c_adapter_quirks, a
>>> length of 0 may be passed.
>> There is another quirk for this: I2C_AQ_NO_ZERO_LEN
>>
>> With that, you shouldn't need the code here.
> I am a little bit lost here. Let us assume that i2c_smbus_write_byte_data() is 
> called - for example by an in-kernel driver. We would then have following call 
> chain:
>
> * i2c_smbus_write_byte_data
> * i2c_smbus_xfer
> * __i2c_smbus_xfer
> * adapter->algo->smbus_xfer (aka rtl9300_i2c_smbus_xfer)
>
> But the quirk is only checked in i2c_check_for_quirks - and then on 
> `struct i2c_msg` and not `union i2c_smbus_data`. And this is only called by 
> __i2c_transfer (which is called by i2c_transfer, i2c_smbus_xfer_emulated, 
> ...). But on first glance, it didn't look like it will be called when using 
> i2c_smbus_write_byte_data - unless __i2c_smbus_xfer fails and must fall back 
> to i2c_smbus_xfer_emulated. I most likely missed something when doing a quick 
> check of the source code. Maybe you can point it out.

Thanks Sven.
I came to the same conclusion for now. The mentioned quirk doesn't seem to
prevent this for smbus_xfer. However, it doesn't harm to add it. This probably
applies to the existing quirks too, that they are not checked for.

So I think this check is necessary. It also ensures that [1] is kept in its purpose
more or less. To prevent any invalid length passed from everywhere. The
implementation of Quick in this driver is also problematic because it passes a
length of 0 internally. Thus, the next patch actually removes that completely.

> And I might have to point out that I am currently not next to the actual HW to 
> check if my statement that adapter->algo->smbus_xfer == rtl9300_i2c_smbus_xfer 
> is really true.

It's true, yes. See [2].

> Kind regards,
> 	Sven

Best regards,
Jonas

[1] https://lore.kernel.org/linux-i2c/20250809-i2c-rtl9300-multi-byte-v4-1-d71dd5eb6121@narfation.org/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support
  2025-08-10  7:13   ` Sven Eckelmann
@ 2025-08-10  9:31     ` Jonas Jelonek
  0 siblings, 0 replies; 23+ messages in thread
From: Jonas Jelonek @ 2025-08-10  9:31 UTC (permalink / raw)
  To: Sven Eckelmann, Chris Packham, Andi Shyti, Rob Herring,
	Krzysztof Kozlowski
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Harshal Gohel



On 10.08.2025 09:13, Sven Eckelmann wrote:
> On Sunday, 10 August 2025 00:07:07 CEST Jonas Jelonek wrote:
> [...]
>> The current implementation of SMBus Quick operation passes a length of
>> 0 (which is actually invalid). Before the fix of a bug in a previous
>> commit, this led to a read operation of 16 bytes from any register (the
>> one of a former transaction or any other value.
>>
>> Although there are currently no reports of actual issues this caused.
>> However, as an example, i2cdetect by default uses Quick Write operation
>> to probe the bus and this may already write anything to some register
>> of a device, causing unintended behaviour. This could be the cause of a
>> recent brick of one of my DAC cables where there was a checksum mismatch
>> of the EEPROM after having run 'i2cdetect -l' before.
> [...]
>
> Nice find. I've actually observed odd behavior after/during probing and 
> attributed it only to the other problems (especially the low timeout + missing 
> check) we found and never did a deep dive to figure out what happened on the 
> bus during the probe. Possible that this could be related.

Haven't actually described my issue in detail in the commit message (may add
this in the next version) but it perfectly makes sense. Quick operation in the
driver passed a length of 0 to config_xfer. Internally, this leads to a value of
0xf in the DATA_WIDTH register meaning 16 bytes to be read/written because
of:

(len - 1) & 0xf

The register value obviously was assumed to be 0 by the hardware and data
was completely zeroed too. Then it did a 16-byte write of that. Unfortunately,
the EEPROM of my DAC isn't write-protected so it was written to the EEPROM
causing checksum error on next boot (was able to fix that though).

> Reviewed-by: Sven Eckelmann <sven@narfation.org>

Thanks!

> Kind regards,
> 	Sven

Best,
Jonas

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller
  2025-08-09 22:07 ` [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller Jonas Jelonek
@ 2025-08-10 10:39   ` Sven Eckelmann
  0 siblings, 0 replies; 23+ messages in thread
From: Sven Eckelmann @ 2025-08-10 10:39 UTC (permalink / raw)
  To: Chris Packham, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
	Jonas Jelonek
  Cc: linux-i2c, Conor Dooley, devicetree, linux-kernel,
	Markus Stockhausen, Harshal Gohel, Jonas Jelonek

[-- Attachment #1: Type: text/plain, Size: 855 bytes --]

On Sunday, 10 August 2025 00:07:12 CEST Jonas Jelonek wrote:
> Add support for the internal I2C controllers of RTL9310 series based
> SoCs to the driver for RTL9300. Add register definitions, chip-specific
> functions and compatible strings for known RTL9310-based SoCs RTL9311,
> RTL9312 and RTL9313.
> 
> Make use of a new device tree property 'realtek,scl' which needs to be
> specified in case both or only the second master is used. This is
> required due how the register layout changed in contrast to RTL9300,
> which has SCL selection in a global register instead of a
> master-specific one.
> 
> Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>

Tested-by: Sven Eckelmann <sven@narfation.org>

Tested the patchset on an RTL9312 device with both SFP modules and an POE MCU 
which requires I2C Block transfers (but not SMBus).

Regards,
	Sven

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos
  2025-08-09 22:07 ` [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos Jonas Jelonek
@ 2025-08-18 15:10   ` Rob Herring (Arm)
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring (Arm) @ 2025-08-18 15:10 UTC (permalink / raw)
  To: Jonas Jelonek
  Cc: Andi Shyti, linux-kernel, Chris Packham, Markus Stockhausen,
	Conor Dooley, Krzysztof Kozlowski, Sven Eckelmann, Harshal Gohel,
	linux-i2c, devicetree


On Sat, 09 Aug 2025 22:07:04 +0000, Jonas Jelonek wrote:
> Fix wording of binding description to use plural because there is not
> only a single RTL9300 SoC. RTL9300 describes a whole family of Realtek
> SoCs.
> 
> Add missing word 'of' in description of reg property.
> 
> Change 'SDA pin' to 'SDA line number' because the property must contain
> the SDA (channel) number ranging from 0-7 instead of a real pin number.
> 
> Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
> ---
>  .../devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml        | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support
  2025-08-09 22:07 ` [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support Jonas Jelonek
@ 2025-08-18 15:13   ` Rob Herring (Arm)
  0 siblings, 0 replies; 23+ messages in thread
From: Rob Herring (Arm) @ 2025-08-18 15:13 UTC (permalink / raw)
  To: Jonas Jelonek
  Cc: Krzysztof Kozlowski, Chris Packham, devicetree, Harshal Gohel,
	Markus Stockhausen, linux-i2c, linux-kernel, Conor Dooley,
	Andi Shyti, Sven Eckelmann


On Sat, 09 Aug 2025 22:07:11 +0000, Jonas Jelonek wrote:
> Adjust the regex for child-node address to account for the fact that
> RTL9310 supports 12 instead of only 8 SDA lines. Also, narrow this per
> variant.
> 
> Add a vendor-specific property to explicitly specify the
> Realtek-internal ID of the defined I2C controller/master. This is
> required, in particular for RTL9310, to describe the correct I2C
> master. Require this property for RTL9310.
> 
> Add compatibles for known SoC variants RTL9311, RTL9312 and RTL9313.
> 
> Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com>
> ---
>  .../bindings/i2c/realtek,rtl9301-i2c.yaml     | 39 ++++++++++++++++++-
>  1 file changed, 37 insertions(+), 2 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2025-08-18 15:13 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-09 22:07 [PATCH v5 00/11] i2c: rework and extend RTL9300 I2C driver Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 01/11] i2c: rtl9300: use regmap fields and API for registers Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 02/11] i2c: rtl9300: fix channel number bound check Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 03/11] dt-bindings: i2c: realtek,rtl9301-i2c: fix wording and typos Jonas Jelonek
2025-08-18 15:10   ` Rob Herring (Arm)
2025-08-09 22:07 ` [PATCH v5 04/11] i2c: rtl9300: rename internal sda_pin to sda_num Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 05/11] i2c: rtl9300: check if xfer length is valid Jonas Jelonek
2025-08-10  5:51   ` Wolfram Sang
2025-08-10  7:01     ` Sven Eckelmann
2025-08-10  9:22       ` Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 06/11] i2c: rtl9300: remove SMBus Quick operation support Jonas Jelonek
2025-08-10  7:13   ` Sven Eckelmann
2025-08-10  9:31     ` Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 07/11] i2c: rtl9300: move setting SCL frequency to config_io Jonas Jelonek
2025-08-10  8:49   ` Markus Elfring
2025-08-10  8:54     ` Sven Eckelmann
2025-08-10  9:10     ` Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 08/11] i2c: rtl9300: do not set read mode on every transfer Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 09/11] i2c: rtl9300: separate xfer configuration and execution Jonas Jelonek
2025-08-09 22:07 ` [PATCH v5 10/11] dt-bindings: i2c: realtek,rtl9301-i2c: extend for RTL9310 support Jonas Jelonek
2025-08-18 15:13   ` Rob Herring (Arm)
2025-08-09 22:07 ` [PATCH v5 11/11] i2c: rtl9300: add support for RTL9310 I2C controller Jonas Jelonek
2025-08-10 10:39   ` Sven Eckelmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).