]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: i2c: rtl9300: backport rtl9607c i2c support and speed patches 22663/head
authorRustam Adilov <adilov@tutamail.com>
Sun, 29 Mar 2026 09:29:30 +0000 (14:29 +0500)
committerHauke Mehrtens <hauke@hauke-m.de>
Fri, 3 Apr 2026 16:43:11 +0000 (18:43 +0200)
The [1] patch and [2] patch series has been accepted by upstream linux so
backport them to OpenWrt.

Patch from [1] adds 50 kHz and 2.5 MHz bus speeds.
Patch series from [2] adds support for RTL9607C i2c controller.

[1] - https://lore.kernel.org/linux-i2c/20260227111134.2163701-1-jan-kernel@kantert.net/
[2] - https://lore.kernel.org/linux-i2c/20260401180648.337834-1-adilov@disroot.org/

Signed-off-by: Rustam Adilov <adilov@tutamail.com>
Link: https://github.com/openwrt/openwrt/pull/22663
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
18 files changed:
target/linux/realtek/patches-6.12/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch [moved from target/linux/realtek/patches-6.12/100-rtl9300-i2c-add-more-speeds.patch with 77% similarity]
target/linux/realtek/patches-6.12/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch [new file with mode: 0644]
target/linux/realtek/patches-6.12/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch [moved from target/linux/realtek/patches-6.18/100-rtl9300-i2c-add-more-speeds.patch with 77% similarity]
target/linux/realtek/patches-6.18/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch [new file with mode: 0644]
target/linux/realtek/patches-6.18/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch [new file with mode: 0644]

similarity index 77%
rename from target/linux/realtek/patches-6.12/100-rtl9300-i2c-add-more-speeds.patch
rename to target/linux/realtek/patches-6.12/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch
index 8c1115aa2385057179af392618aeeefdba5dad9d..a31b72e437f0e026adbdd186ff744f279d0816de 100644 (file)
@@ -1,10 +1,7 @@
-From linux-i2c  Fri Feb 27 11:11:34 2026
-From: Jan Kantert <jan-kernel () kantert ! net>
-Date: Fri, 27 Feb 2026 11:11:34 +0000
-To: linux-i2c
-Subject: [PATCH] i2c: rtl9300: add support for 50 kHz and 2.5 MHz bus speeds
-Message-Id: <20260227111134.2163701-1-jan-kernel () kantert ! net>
-X-MARC-Message: https://marc.info/?l=linux-i2c&m=177219358420283
+From 879766b58ea5cba79ff5fe46f062ed8e05e715aa Mon Sep 17 00:00:00 2001
+From: Jan Kantert <jan-kernel@kantert.net>
+Date: Fri, 27 Feb 2026 12:11:34 +0100
+Subject: i2c: rtl9300: add support for 50 kHz and 2.5 MHz bus speeds
 
 Some SFP modules on certain switches (for example the ONTi ONT-S508CL-8S and
 XikeStor SKS8300-8X) exhibit unreliable I2C communication at the currently
@@ -12,6 +9,9 @@ supported speeds. Add support for 50 kHz and 2.5 MHz I2C bus modes on the
 RTL9300 to improve compatibility with these devices.
 
 Signed-off-by: Jan Kantert <jan-kernel@kantert.net>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260227111134.2163701-1-jan-kernel@kantert.net
 ---
  drivers/i2c/busses/i2c-rtl9300.c | 16 ++++++++++++++--
  1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/target/linux/realtek/patches-6.12/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch b/target/linux/realtek/patches-6.12/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch
new file mode 100644 (file)
index 0000000..502ca22
--- /dev/null
@@ -0,0 +1,112 @@
+From 4c53b2eb4f18102c36d4bcaf8c604a1825701ffb Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:41 +0500
+Subject: i2c: rtl9300: split data_reg into read and write reg
+
+In RTL9607C i2c controller, there are 2 separate registers for reads
+and writes as opposed the combined 1 on rtl9300 and rtl9310.
+
+In preparation for RTL9607C support, split it up into rd_reg and wd_reg
+properties and change the i2c read and write functions accordingly.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-2-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -61,7 +61,8 @@ enum rtl9300_i2c_reg_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;
++      u32 rd_reg;
++      u32 wd_reg;
+       u8 max_nchan;
+ };
+@@ -74,7 +75,8 @@ struct rtl9300_i2c {
+       struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
+       struct regmap_field *fields[F_NUM_FIELDS];
+       u32 reg_base;
+-      u32 data_reg;
++      u32 rd_reg;
++      u32 wd_reg;
+       u8 scl_num;
+       u8 sda_num;
+       struct mutex lock;
+@@ -171,7 +173,7 @@ static int rtl9300_i2c_read(struct rtl93
+       if (len > 16)
+               return -EIO;
+-      ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
++      ret = regmap_bulk_read(i2c->regmap, i2c->rd_reg, vals, ARRAY_SIZE(vals));
+       if (ret)
+               return ret;
+@@ -198,12 +200,12 @@ static int rtl9300_i2c_write(struct rtl9
+               vals[reg] |= buf[i] << shift;
+       }
+-      return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
++      return regmap_bulk_write(i2c->regmap, i2c->wd_reg, vals, ARRAY_SIZE(vals));
+ }
+ static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
+ {
+-      return regmap_write(i2c->regmap, i2c->data_reg, data);
++      return regmap_write(i2c->regmap, i2c->wd_reg, data);
+ }
+ static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+@@ -268,14 +270,14 @@ static int rtl9300_i2c_do_xfer(struct rt
+       if (!xfer->write) {
+               switch (xfer->type) {
+               case RTL9300_I2C_XFER_BYTE:
+-                      ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
++                      ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
+                       if (ret)
+                               return ret;
+                       *xfer->data = val & 0xff;
+                       break;
+               case RTL9300_I2C_XFER_WORD:
+-                      ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
++                      ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
+                       if (ret)
+                               return ret;
+@@ -408,7 +410,8 @@ static int rtl9300_i2c_probe(struct plat
+       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;
++      i2c->rd_reg = i2c->reg_base + drv_data->rd_reg;
++      i2c->wd_reg = i2c->reg_base + drv_data->wd_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)
+@@ -499,7 +502,8 @@ static const struct rtl9300_i2c_drv_data
+               [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,
++      .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
++      .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+ };
+@@ -519,7 +523,8 @@ static const struct rtl9300_i2c_drv_data
+               [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,
++      .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
++      .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
+ };
diff --git a/target/linux/realtek/patches-6.12/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch b/target/linux/realtek/patches-6.12/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch
new file mode 100644 (file)
index 0000000..ba28e5a
--- /dev/null
@@ -0,0 +1,66 @@
+From 98773df61f8416594ac993e8464df596755ee1b8 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:42 +0500
+Subject: i2c: rtl9300: introduce max length property to driver data
+
+In RTL9607C i2c controller, theoretical maximum the data length
+can be is 4 bytes as opposed to 16 bytes on rtl9300 and rtl9310.
+
+Introduce a new property to the driver data struct for that.
+Adjust if statement in prepare_xfer function to follow that new
+property instead of the hardcoded value.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-3-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -64,11 +64,14 @@ struct rtl9300_i2c_drv_data {
+       u32 rd_reg;
+       u32 wd_reg;
+       u8 max_nchan;
++      u8 max_data_len;
+ };
+ #define RTL9300_I2C_MUX_NCHAN 8
+ #define RTL9310_I2C_MUX_NCHAN 12
++#define RTL9300_I2C_MAX_DATA_LEN      16
++
+ struct rtl9300_i2c {
+       struct regmap *regmap;
+       struct device *dev;
+@@ -210,9 +213,11 @@ static int rtl9300_i2c_writel(struct rtl
+ static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+ {
++      const struct rtl9300_i2c_drv_data *drv_data;
+       int ret;
+-      if (xfer->data_len < 1 || xfer->data_len > 16)
++      drv_data = device_get_match_data(i2c->dev);
++      if (xfer->data_len < 1 || xfer->data_len > drv_data->max_data_len)
+               return -EINVAL;
+       ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
+@@ -505,6 +510,7 @@ static const struct rtl9300_i2c_drv_data
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
++      .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
+ };
+ static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+@@ -526,6 +532,7 @@ static const struct rtl9300_i2c_drv_data
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
++      .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
+ };
+ static const struct of_device_id i2c_rtl9300_dt_ids[] = {
diff --git a/target/linux/realtek/patches-6.12/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch b/target/linux/realtek/patches-6.12/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch
new file mode 100644 (file)
index 0000000..67dd19b
--- /dev/null
@@ -0,0 +1,56 @@
+From 55284a806b63a412846b9ecd3846f2639eaeaff4 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:43 +0500
+Subject: i2c: rtl9300: introduce F_BUSY to the reg_fields struct
+
+In RTL9607C i2c controller the busy check operation is done on the
+separate bit of the command register as opposed to self clearing
+command trigger bit on the rtl9300 and rtl9310 i2c controllers.
+
+Introduce a new F_BUSY field to the reg_fields struct for that
+and change the regmap read poll function to use F_BUSY
+instead of I2C_TRIG.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-4-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -53,6 +53,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SCL_SEL,
+       F_SDA_OUT_SEL,
+       F_SDA_SEL,
++      F_BUSY,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -262,7 +263,7 @@ static int rtl9300_i2c_do_xfer(struct rt
+       if (ret)
+               return ret;
+-      ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
++      ret = regmap_field_read_poll_timeout(i2c->fields[F_BUSY], val, !val, 100, 100000);
+       if (ret)
+               return ret;
+@@ -505,6 +506,7 @@ static const struct rtl9300_i2c_drv_data
+               [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),
++              [F_BUSY]                = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+       },
+       .select_scl = rtl9300_i2c_select_scl,
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+@@ -527,6 +529,7 @@ static const struct rtl9300_i2c_drv_data
+               [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),
++              [F_BUSY]                = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+       },
+       .select_scl = rtl9310_i2c_select_scl,
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
diff --git a/target/linux/realtek/patches-6.12/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch b/target/linux/realtek/patches-6.12/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch
new file mode 100644 (file)
index 0000000..ec6f657
--- /dev/null
@@ -0,0 +1,79 @@
+From 6afde011baaf722aa66c11696b6383f9ce85b653 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:44 +0500
+Subject: i2c: rtl9300: introduce a property for 8 bit width reg address
+
+In RTL9607C i2c controller, in order to indicate that the width of
+memory address is 8 bits, 0 is written to MEM_ADDR_WIDTH field as
+opposed to 1 for RTL9300 and RTL9310.
+
+Introduce a new property to a driver data to indicate what value
+need to written to MEM_ADDR_WIDTH field for this case.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-5-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -66,6 +66,7 @@ struct rtl9300_i2c_drv_data {
+       u32 wd_reg;
+       u8 max_nchan;
+       u8 max_data_len;
++      u8 reg_addr_8bit_len;
+ };
+ #define RTL9300_I2C_MUX_NCHAN 8
+@@ -111,6 +112,7 @@ struct rtl9300_i2c_xfer {
+ #define RTL9300_I2C_MST_DATA_WORD2                    0x10
+ #define RTL9300_I2C_MST_DATA_WORD3                    0x14
+ #define RTL9300_I2C_MST_GLB_CTRL                      0x384
++#define RTL9300_REG_ADDR_8BIT_LEN                     1
+ #define RTL9310_I2C_MST_IF_CTRL                               0x1004
+ #define RTL9310_I2C_MST_IF_SEL                                0x1008
+@@ -305,6 +307,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+                                 union i2c_smbus_data *data)
+ {
+       struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
++      const struct rtl9300_i2c_drv_data *drv_data;
+       struct rtl9300_i2c *i2c = chan->i2c;
+       struct rtl9300_i2c_xfer xfer = {0};
+       int ret;
+@@ -314,6 +317,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       guard(rtl9300_i2c)(i2c);
++      drv_data = device_get_match_data(i2c->dev);
+       ret = rtl9300_i2c_config_chan(i2c, chan);
+       if (ret)
+               return ret;
+@@ -321,7 +325,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       xfer.dev_addr = addr & 0x7f;
+       xfer.write = (read_write == I2C_SMBUS_WRITE);
+       xfer.reg_addr = command;
+-      xfer.reg_addr_len = 1;
++      xfer.reg_addr_len = drv_data->reg_addr_8bit_len;
+       switch (size) {
+       case I2C_SMBUS_BYTE:
+@@ -513,6 +517,7 @@ static const struct rtl9300_i2c_drv_data
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+       .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
+ static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+@@ -536,6 +541,7 @@ static const struct rtl9300_i2c_drv_data
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
+       .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
+ static const struct of_device_id i2c_rtl9300_dt_ids[] = {
diff --git a/target/linux/realtek/patches-6.12/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch b/target/linux/realtek/patches-6.12/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch
new file mode 100644 (file)
index 0000000..9a1f2b3
--- /dev/null
@@ -0,0 +1,73 @@
+From 1211ce1e11d23ec05d80a85b7187baa6abed3232 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:45 +0500
+Subject: dt-bindings: i2c: realtek,rtl9301-i2c: extend for clocks and RTL9607C
+ support
+
+Add the "realtek,rtl9607-i2c" compatible for i2c controller on the
+RTL9607C SoC series.
+
+Add a clocks property to the properties to describe the i2c reference
+clock and make it available for all the compatibles. This i2c reference
+clock is assumed to be coming from switchcore region via Lexra bus as
+the other SoC peripherals.
+
+According to the info available about the existing devices, they also
+have the i2c master controller clocks.
+
+RTL9607C requires the "realtek,scl" and "clocks" to be specified
+and so handle it under separate if check for "realtek,rtl9607-i2c".
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-6-adilov@disroot.org
+---
+ .../devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml      | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
++++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
+@@ -15,6 +15,8 @@ description:
+   assigned to either I2C controller.
+   RTL9310 SoCs have equal capabilities but support 12 common SDA lines which
+   can be assigned to either I2C controller.
++  RTL9607C SoCs have equal capabilities but each controller only supports 1
++  SCL/SDA line.
+ properties:
+   compatible:
+@@ -34,6 +36,7 @@ properties:
+       - enum:
+           - realtek,rtl9301-i2c
+           - realtek,rtl9310-i2c
++          - realtek,rtl9607-i2c
+   reg:
+     items:
+@@ -51,6 +54,9 @@ properties:
+       The SCL line number of this I2C controller.
+     enum: [ 0, 1 ]
++  clocks:
++    maxItems: 1
++
+ patternProperties:
+   '^i2c@[0-9ab]$':
+     $ref: /schemas/i2c/i2c-controller.yaml
+@@ -82,6 +88,15 @@ allOf:
+     then:
+       patternProperties:
+         '^i2c@[89ab]$': false
++  - if:
++      properties:
++        compatible:
++          contains:
++            const: realtek,rtl9607-i2c
++    then:
++      required:
++        - realtek,scl
++        - clocks
+ required:
+   - compatible
diff --git a/target/linux/realtek/patches-6.12/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch b/target/linux/realtek/patches-6.12/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch
new file mode 100644 (file)
index 0000000..56bb8a8
--- /dev/null
@@ -0,0 +1,70 @@
+From f60d27926c9e2d547200fb0d26f61eec9b8291a6 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:46 +0500
+Subject: i2c: rtl9300: introduce clk struct for upcoming rtl9607 support
+
+In RTL9607C i2c controller, there is 10 bit CLK_DIV field for
+setting the clock of i2c interface which depends on the rate
+of i2c clk (which seems be fixed to 62.5MHz according to Realtek SDK).
+
+Introduce the clk struct and the respective F_CLK_DIV and clk_div
+which are going to be used in the upcoming patch for rtl9607c i2c
+controller support addition.
+
+devm_clk_get_optional_enabled() function was used for cleaner code
+as it automatically returns NULL if the clk is not present, which is
+going to be the case for RTL9300 and RTL9310 i2c controllers.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-7-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ #include <linux/bits.h>
++#include <linux/clk.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-mux.h>
+ #include <linux/mod_devicetable.h>
+@@ -28,6 +29,7 @@ struct rtl9300_i2c_chan {
+       struct rtl9300_i2c *i2c;
+       enum rtl9300_bus_freq bus_freq;
+       u8 sda_num;
++      u32 clk_div;
+ };
+ enum rtl9300_i2c_reg_scope {
+@@ -54,6 +56,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SDA_OUT_SEL,
+       F_SDA_SEL,
+       F_BUSY,
++      F_CLK_DIV,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -85,6 +88,7 @@ struct rtl9300_i2c {
+       u8 scl_num;
+       u8 sda_num;
+       struct mutex lock;
++      struct clk *clk;
+ };
+ DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock))
+@@ -432,6 +436,10 @@ static int rtl9300_i2c_probe(struct plat
+       if (ret)
+               return ret;
++      i2c->clk = devm_clk_get_optional_enabled(dev, NULL);
++      if (IS_ERR(i2c->clk))
++              return dev_err_probe(dev, PTR_ERR(i2c->clk), "Failed to enable i2c clock\n");
++
+       i = 0;
+       for_each_child_of_node_scoped(dev->of_node, child) {
+               struct rtl9300_i2c_chan *chan = &i2c->chans[i];
diff --git a/target/linux/realtek/patches-6.12/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch b/target/linux/realtek/patches-6.12/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch
new file mode 100644 (file)
index 0000000..f2fe9e7
--- /dev/null
@@ -0,0 +1,147 @@
+From 991cd899ecd03a1c3ef7d177a0b99e824c6be581 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:47 +0500
+Subject: i2c: rtl9300: introduce new function properties to driver data
+
+Due to the very nature of differences between RTL9607C i2c controller
+and RTL9300 / RTL9310 that are incompatible with each other in some areas
+of this driver, for example in clock configuration, channel configuration
+and initialization at the end of the probe, introduce new function
+properties to the driver data struct to handle those differences.
+
+With these new properties, create configuration functions for RTL9300 and
+RTL9310 and assign them to their respective driver data structs.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-8-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 66 ++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 22 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -65,6 +65,9 @@ enum rtl9300_i2c_reg_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);
++      int (*config_chan)(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan);
++      void (*config_clock)(u32 clock_freq, struct rtl9300_i2c_chan *chan);
++      int (*misc_init)(struct rtl9300_i2c *i2c);
+       u32 rd_reg;
+       u32 wd_reg;
+       u8 max_nchan;
+@@ -175,6 +178,30 @@ static int rtl9300_i2c_config_chan(struc
+       return 0;
+ }
++static void rtl9300_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
++{
++      struct rtl9300_i2c *i2c = chan->i2c;
++
++      switch (clock_freq) {
++      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;
++      case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
++              chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
++              break;
++      case RTL9300_I2C_MAX_SLOW_FREQ:
++              chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
++              break;
++      default:
++              dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
++                       chan->sda_num, clock_freq);
++              break;
++      }
++}
++
+ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
+ {
+       u32 vals[4] = {};
+@@ -322,7 +349,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       guard(rtl9300_i2c)(i2c);
+       drv_data = device_get_match_data(i2c->dev);
+-      ret = rtl9300_i2c_config_chan(i2c, chan);
++      ret = drv_data->config_chan(i2c, chan);
+       if (ret)
+               return ret;
+@@ -389,6 +416,12 @@ static struct i2c_adapter_quirks rtl9300
+       .max_write_len  = 16,
+ };
++static int rtl9300_i2c_init(struct rtl9300_i2c *i2c)
++{
++      /* only use standard read format */
++      return regmap_field_write(i2c->fields[F_RD_MODE], 0);
++}
++
+ static int rtl9300_i2c_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+@@ -453,27 +486,11 @@ static int rtl9300_i2c_probe(struct plat
+               if (ret)
+                       clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
+-              switch (clock_freq) {
+-              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;
+-              case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
+-                      chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
+-                      break;
+-              case RTL9300_I2C_MAX_SLOW_FREQ:
+-                      chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
+-                      break;
+-              default:
+-                      dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
+-                               sda_num, clock_freq);
+-                      break;
+-              }
+-
+               chan->sda_num = sda_num;
+               chan->i2c = i2c;
++
++              drv_data->config_clock(clock_freq, chan);
++
+               adap = &i2c->chans[i].adap;
+               adap->owner = THIS_MODULE;
+               adap->algo = &rtl9300_i2c_algo;
+@@ -491,8 +508,7 @@ static int rtl9300_i2c_probe(struct plat
+       }
+       i2c->sda_num = 0xff;
+-      /* only use standard read format */
+-      ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
++      ret = drv_data->misc_init(i2c);
+       if (ret)
+               return ret;
+@@ -521,6 +537,9 @@ static const struct rtl9300_i2c_drv_data
+               [F_BUSY]                = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+       },
+       .select_scl = rtl9300_i2c_select_scl,
++      .config_chan = rtl9300_i2c_config_chan,
++      .config_clock = rtl9300_i2c_config_clock,
++      .misc_init = rtl9300_i2c_init,
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+@@ -545,6 +564,9 @@ static const struct rtl9300_i2c_drv_data
+               [F_BUSY]                = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+       },
+       .select_scl = rtl9310_i2c_select_scl,
++      .config_chan = rtl9300_i2c_config_chan,
++      .config_clock = rtl9300_i2c_config_clock,
++      .misc_init = rtl9300_i2c_init,
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
diff --git a/target/linux/realtek/patches-6.12/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch b/target/linux/realtek/patches-6.12/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch
new file mode 100644 (file)
index 0000000..13a6530
--- /dev/null
@@ -0,0 +1,154 @@
+From 40890b5fe72b1a0d4913883844854f6641a2f4b3 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:48 +0500
+Subject: i2c: rtl9300: add RTL9607C i2c controller support
+
+Add support for the internal I2C controllers of RTL9607C series based
+SoCs. Add register definitions, chip-specific functions and macros too.
+
+Make use of the clk introduced from the previous patch to get the clk_div
+value and use it during the rtl9607c channel configuration.
+
+Introduce a new EXT_SCK_5MS field to the reg fields struct which is going
+to be initialized by rtl9607c init function at the end of the probe.
+
+This patch depends on all the previous patches in this patch series.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-9-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 70 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -57,6 +57,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SDA_SEL,
+       F_BUSY,
+       F_CLK_DIV,
++      F_EXT_SCK_5MS,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -77,8 +78,10 @@ struct rtl9300_i2c_drv_data {
+ #define RTL9300_I2C_MUX_NCHAN 8
+ #define RTL9310_I2C_MUX_NCHAN 12
++#define RTL9607_I2C_MUX_NCHAN 1
+ #define RTL9300_I2C_MAX_DATA_LEN      16
++#define RTL9607_I2C_MAX_DATA_LEN      4
+ struct rtl9300_i2c {
+       struct regmap *regmap;
+@@ -127,6 +130,14 @@ struct rtl9300_i2c_xfer {
+ #define RTL9310_I2C_MST_MEMADDR_CTRL                  0x4
+ #define RTL9310_I2C_MST_DATA_CTRL                     0x8
++#define RTL9607_I2C_CONFIG                            0x22f50
++#define RTL9607_IO_MODE_EN                            0x23014
++#define RTL9607_I2C_IND_WD                            0x0
++#define RTL9607_I2C_IND_ADR                           0x8
++#define RTL9607_I2C_IND_CMD                           0x10
++#define RTL9607_I2C_IND_RD                            0x18
++#define RTL9607_REG_ADDR_8BIT_LEN                     0
++
+ static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
+ {
+       int ret;
+@@ -178,6 +189,27 @@ static int rtl9300_i2c_config_chan(struc
+       return 0;
+ }
++static int rtl9607_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
++{
++      const struct rtl9300_i2c_drv_data *drv_data;
++      int ret;
++
++      if (i2c->sda_num == chan->sda_num)
++              return 0;
++
++      ret = regmap_field_write(i2c->fields[F_CLK_DIV], chan->clk_div);
++      if (ret)
++              return ret;
++
++      drv_data = device_get_match_data(i2c->dev);
++      ret = drv_data->select_scl(i2c, i2c->scl_num);
++      if (ret)
++              return ret;
++
++      i2c->sda_num = chan->sda_num;
++      return 0;
++}
++
+ static void rtl9300_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
+ {
+       struct rtl9300_i2c *i2c = chan->i2c;
+@@ -202,6 +234,13 @@ static void rtl9300_i2c_config_clock(u32
+       }
+ }
++static void rtl9607_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
++{
++      struct rtl9300_i2c *i2c = chan->i2c;
++
++      chan->clk_div = clk_get_rate(i2c->clk) / clock_freq - 1;
++}
++
+ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
+ {
+       u32 vals[4] = {};
+@@ -422,6 +461,11 @@ static int rtl9300_i2c_init(struct rtl93
+       return regmap_field_write(i2c->fields[F_RD_MODE], 0);
+ }
++static int rtl9607_i2c_init(struct rtl9300_i2c *i2c)
++{
++      return regmap_field_write(i2c->fields[F_EXT_SCK_5MS], 1);
++}
++
+ static int rtl9300_i2c_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+@@ -574,6 +618,31 @@ static const struct rtl9300_i2c_drv_data
+       .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
++static const struct rtl9300_i2c_drv_data rtl9607_i2c_drv_data = {
++      .field_desc = {
++              [F_SCL_SEL]             = GLB_REG_FIELD(RTL9607_IO_MODE_EN, 13, 14),
++              [F_EXT_SCK_5MS]         = MST_REG_FIELD(RTL9607_I2C_CONFIG, 26, 26),
++              [F_DEV_ADDR]            = MST_REG_FIELD(RTL9607_I2C_CONFIG, 14, 20),
++              [F_MEM_ADDR_WIDTH]      = MST_REG_FIELD(RTL9607_I2C_CONFIG, 12, 13),
++              [F_DATA_WIDTH]          = MST_REG_FIELD(RTL9607_I2C_CONFIG, 10, 11),
++              [F_CLK_DIV]             = MST_REG_FIELD(RTL9607_I2C_CONFIG, 0, 9),
++              [F_I2C_FAIL]            = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 3, 3),
++              [F_BUSY]                = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 2, 2),
++              [F_RWOP]                = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 1, 1),
++              [F_I2C_TRIG]            = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 0, 0),
++              [F_MEM_ADDR]            = MST_REG_FIELD(RTL9607_I2C_IND_ADR, 0, 31),
++      },
++      .select_scl = rtl9310_i2c_select_scl,
++      .config_chan = rtl9607_i2c_config_chan,
++      .config_clock = rtl9607_i2c_config_clock,
++      .misc_init = rtl9607_i2c_init,
++      .rd_reg = RTL9607_I2C_IND_RD,
++      .wd_reg = RTL9607_I2C_IND_WD,
++      .max_nchan = RTL9607_I2C_MUX_NCHAN,
++      .max_data_len = RTL9607_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9607_REG_ADDR_8BIT_LEN,
++};
++
+ 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 },
+@@ -583,6 +652,7 @@ static const struct of_device_id i2c_rtl
+       { .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 },
++      { .compatible = "realtek,rtl9607-i2c", .data = (void *) &rtl9607_i2c_drv_data },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);
similarity index 77%
rename from target/linux/realtek/patches-6.18/100-rtl9300-i2c-add-more-speeds.patch
rename to target/linux/realtek/patches-6.18/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch
index 8c1115aa2385057179af392618aeeefdba5dad9d..a31b72e437f0e026adbdd186ff744f279d0816de 100644 (file)
@@ -1,10 +1,7 @@
-From linux-i2c  Fri Feb 27 11:11:34 2026
-From: Jan Kantert <jan-kernel () kantert ! net>
-Date: Fri, 27 Feb 2026 11:11:34 +0000
-To: linux-i2c
-Subject: [PATCH] i2c: rtl9300: add support for 50 kHz and 2.5 MHz bus speeds
-Message-Id: <20260227111134.2163701-1-jan-kernel () kantert ! net>
-X-MARC-Message: https://marc.info/?l=linux-i2c&m=177219358420283
+From 879766b58ea5cba79ff5fe46f062ed8e05e715aa Mon Sep 17 00:00:00 2001
+From: Jan Kantert <jan-kernel@kantert.net>
+Date: Fri, 27 Feb 2026 12:11:34 +0100
+Subject: i2c: rtl9300: add support for 50 kHz and 2.5 MHz bus speeds
 
 Some SFP modules on certain switches (for example the ONTi ONT-S508CL-8S and
 XikeStor SKS8300-8X) exhibit unreliable I2C communication at the currently
@@ -12,6 +9,9 @@ supported speeds. Add support for 50 kHz and 2.5 MHz I2C bus modes on the
 RTL9300 to improve compatibility with these devices.
 
 Signed-off-by: Jan Kantert <jan-kernel@kantert.net>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260227111134.2163701-1-jan-kernel@kantert.net
 ---
  drivers/i2c/busses/i2c-rtl9300.c | 16 ++++++++++++++--
  1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/target/linux/realtek/patches-6.18/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch b/target/linux/realtek/patches-6.18/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch
new file mode 100644 (file)
index 0000000..502ca22
--- /dev/null
@@ -0,0 +1,112 @@
+From 4c53b2eb4f18102c36d4bcaf8c604a1825701ffb Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:41 +0500
+Subject: i2c: rtl9300: split data_reg into read and write reg
+
+In RTL9607C i2c controller, there are 2 separate registers for reads
+and writes as opposed the combined 1 on rtl9300 and rtl9310.
+
+In preparation for RTL9607C support, split it up into rd_reg and wd_reg
+properties and change the i2c read and write functions accordingly.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-2-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -61,7 +61,8 @@ enum rtl9300_i2c_reg_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;
++      u32 rd_reg;
++      u32 wd_reg;
+       u8 max_nchan;
+ };
+@@ -74,7 +75,8 @@ struct rtl9300_i2c {
+       struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN];
+       struct regmap_field *fields[F_NUM_FIELDS];
+       u32 reg_base;
+-      u32 data_reg;
++      u32 rd_reg;
++      u32 wd_reg;
+       u8 scl_num;
+       u8 sda_num;
+       struct mutex lock;
+@@ -171,7 +173,7 @@ static int rtl9300_i2c_read(struct rtl93
+       if (len > 16)
+               return -EIO;
+-      ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
++      ret = regmap_bulk_read(i2c->regmap, i2c->rd_reg, vals, ARRAY_SIZE(vals));
+       if (ret)
+               return ret;
+@@ -198,12 +200,12 @@ static int rtl9300_i2c_write(struct rtl9
+               vals[reg] |= buf[i] << shift;
+       }
+-      return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals));
++      return regmap_bulk_write(i2c->regmap, i2c->wd_reg, vals, ARRAY_SIZE(vals));
+ }
+ static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
+ {
+-      return regmap_write(i2c->regmap, i2c->data_reg, data);
++      return regmap_write(i2c->regmap, i2c->wd_reg, data);
+ }
+ static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+@@ -268,14 +270,14 @@ static int rtl9300_i2c_do_xfer(struct rt
+       if (!xfer->write) {
+               switch (xfer->type) {
+               case RTL9300_I2C_XFER_BYTE:
+-                      ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
++                      ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
+                       if (ret)
+                               return ret;
+                       *xfer->data = val & 0xff;
+                       break;
+               case RTL9300_I2C_XFER_WORD:
+-                      ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
++                      ret = regmap_read(i2c->regmap, i2c->rd_reg, &val);
+                       if (ret)
+                               return ret;
+@@ -408,7 +410,8 @@ static int rtl9300_i2c_probe(struct plat
+       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;
++      i2c->rd_reg = i2c->reg_base + drv_data->rd_reg;
++      i2c->wd_reg = i2c->reg_base + drv_data->wd_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)
+@@ -499,7 +502,8 @@ static const struct rtl9300_i2c_drv_data
+               [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,
++      .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
++      .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+ };
+@@ -519,7 +523,8 @@ static const struct rtl9300_i2c_drv_data
+               [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,
++      .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
++      .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
+ };
diff --git a/target/linux/realtek/patches-6.18/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch b/target/linux/realtek/patches-6.18/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch
new file mode 100644 (file)
index 0000000..ba28e5a
--- /dev/null
@@ -0,0 +1,66 @@
+From 98773df61f8416594ac993e8464df596755ee1b8 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:42 +0500
+Subject: i2c: rtl9300: introduce max length property to driver data
+
+In RTL9607C i2c controller, theoretical maximum the data length
+can be is 4 bytes as opposed to 16 bytes on rtl9300 and rtl9310.
+
+Introduce a new property to the driver data struct for that.
+Adjust if statement in prepare_xfer function to follow that new
+property instead of the hardcoded value.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-3-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -64,11 +64,14 @@ struct rtl9300_i2c_drv_data {
+       u32 rd_reg;
+       u32 wd_reg;
+       u8 max_nchan;
++      u8 max_data_len;
+ };
+ #define RTL9300_I2C_MUX_NCHAN 8
+ #define RTL9310_I2C_MUX_NCHAN 12
++#define RTL9300_I2C_MAX_DATA_LEN      16
++
+ struct rtl9300_i2c {
+       struct regmap *regmap;
+       struct device *dev;
+@@ -210,9 +213,11 @@ static int rtl9300_i2c_writel(struct rtl
+ static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
+ {
++      const struct rtl9300_i2c_drv_data *drv_data;
+       int ret;
+-      if (xfer->data_len < 1 || xfer->data_len > 16)
++      drv_data = device_get_match_data(i2c->dev);
++      if (xfer->data_len < 1 || xfer->data_len > drv_data->max_data_len)
+               return -EINVAL;
+       ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
+@@ -505,6 +510,7 @@ static const struct rtl9300_i2c_drv_data
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
++      .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
+ };
+ static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+@@ -526,6 +532,7 @@ static const struct rtl9300_i2c_drv_data
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
++      .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
+ };
+ static const struct of_device_id i2c_rtl9300_dt_ids[] = {
diff --git a/target/linux/realtek/patches-6.18/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch b/target/linux/realtek/patches-6.18/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch
new file mode 100644 (file)
index 0000000..67dd19b
--- /dev/null
@@ -0,0 +1,56 @@
+From 55284a806b63a412846b9ecd3846f2639eaeaff4 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:43 +0500
+Subject: i2c: rtl9300: introduce F_BUSY to the reg_fields struct
+
+In RTL9607C i2c controller the busy check operation is done on the
+separate bit of the command register as opposed to self clearing
+command trigger bit on the rtl9300 and rtl9310 i2c controllers.
+
+Introduce a new F_BUSY field to the reg_fields struct for that
+and change the regmap read poll function to use F_BUSY
+instead of I2C_TRIG.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-4-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -53,6 +53,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SCL_SEL,
+       F_SDA_OUT_SEL,
+       F_SDA_SEL,
++      F_BUSY,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -262,7 +263,7 @@ static int rtl9300_i2c_do_xfer(struct rt
+       if (ret)
+               return ret;
+-      ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000);
++      ret = regmap_field_read_poll_timeout(i2c->fields[F_BUSY], val, !val, 100, 100000);
+       if (ret)
+               return ret;
+@@ -505,6 +506,7 @@ static const struct rtl9300_i2c_drv_data
+               [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),
++              [F_BUSY]                = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+       },
+       .select_scl = rtl9300_i2c_select_scl,
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+@@ -527,6 +529,7 @@ static const struct rtl9300_i2c_drv_data
+               [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),
++              [F_BUSY]                = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+       },
+       .select_scl = rtl9310_i2c_select_scl,
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
diff --git a/target/linux/realtek/patches-6.18/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch b/target/linux/realtek/patches-6.18/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch
new file mode 100644 (file)
index 0000000..ec6f657
--- /dev/null
@@ -0,0 +1,79 @@
+From 6afde011baaf722aa66c11696b6383f9ce85b653 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:44 +0500
+Subject: i2c: rtl9300: introduce a property for 8 bit width reg address
+
+In RTL9607C i2c controller, in order to indicate that the width of
+memory address is 8 bits, 0 is written to MEM_ADDR_WIDTH field as
+opposed to 1 for RTL9300 and RTL9310.
+
+Introduce a new property to a driver data to indicate what value
+need to written to MEM_ADDR_WIDTH field for this case.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-5-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 8 +++++++-
+ 1 file changed, 7 insertions(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -66,6 +66,7 @@ struct rtl9300_i2c_drv_data {
+       u32 wd_reg;
+       u8 max_nchan;
+       u8 max_data_len;
++      u8 reg_addr_8bit_len;
+ };
+ #define RTL9300_I2C_MUX_NCHAN 8
+@@ -111,6 +112,7 @@ struct rtl9300_i2c_xfer {
+ #define RTL9300_I2C_MST_DATA_WORD2                    0x10
+ #define RTL9300_I2C_MST_DATA_WORD3                    0x14
+ #define RTL9300_I2C_MST_GLB_CTRL                      0x384
++#define RTL9300_REG_ADDR_8BIT_LEN                     1
+ #define RTL9310_I2C_MST_IF_CTRL                               0x1004
+ #define RTL9310_I2C_MST_IF_SEL                                0x1008
+@@ -305,6 +307,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+                                 union i2c_smbus_data *data)
+ {
+       struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
++      const struct rtl9300_i2c_drv_data *drv_data;
+       struct rtl9300_i2c *i2c = chan->i2c;
+       struct rtl9300_i2c_xfer xfer = {0};
+       int ret;
+@@ -314,6 +317,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       guard(rtl9300_i2c)(i2c);
++      drv_data = device_get_match_data(i2c->dev);
+       ret = rtl9300_i2c_config_chan(i2c, chan);
+       if (ret)
+               return ret;
+@@ -321,7 +325,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       xfer.dev_addr = addr & 0x7f;
+       xfer.write = (read_write == I2C_SMBUS_WRITE);
+       xfer.reg_addr = command;
+-      xfer.reg_addr_len = 1;
++      xfer.reg_addr_len = drv_data->reg_addr_8bit_len;
+       switch (size) {
+       case I2C_SMBUS_BYTE:
+@@ -513,6 +517,7 @@ static const struct rtl9300_i2c_drv_data
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+       .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
+ static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = {
+@@ -536,6 +541,7 @@ static const struct rtl9300_i2c_drv_data
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
+       .max_data_len = RTL9300_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
+ static const struct of_device_id i2c_rtl9300_dt_ids[] = {
diff --git a/target/linux/realtek/patches-6.18/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch b/target/linux/realtek/patches-6.18/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch
new file mode 100644 (file)
index 0000000..9a1f2b3
--- /dev/null
@@ -0,0 +1,73 @@
+From 1211ce1e11d23ec05d80a85b7187baa6abed3232 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:45 +0500
+Subject: dt-bindings: i2c: realtek,rtl9301-i2c: extend for clocks and RTL9607C
+ support
+
+Add the "realtek,rtl9607-i2c" compatible for i2c controller on the
+RTL9607C SoC series.
+
+Add a clocks property to the properties to describe the i2c reference
+clock and make it available for all the compatibles. This i2c reference
+clock is assumed to be coming from switchcore region via Lexra bus as
+the other SoC peripherals.
+
+According to the info available about the existing devices, they also
+have the i2c master controller clocks.
+
+RTL9607C requires the "realtek,scl" and "clocks" to be specified
+and so handle it under separate if check for "realtek,rtl9607-i2c".
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-6-adilov@disroot.org
+---
+ .../devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml      | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+--- a/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
++++ b/Documentation/devicetree/bindings/i2c/realtek,rtl9301-i2c.yaml
+@@ -15,6 +15,8 @@ description:
+   assigned to either I2C controller.
+   RTL9310 SoCs have equal capabilities but support 12 common SDA lines which
+   can be assigned to either I2C controller.
++  RTL9607C SoCs have equal capabilities but each controller only supports 1
++  SCL/SDA line.
+ properties:
+   compatible:
+@@ -34,6 +36,7 @@ properties:
+       - enum:
+           - realtek,rtl9301-i2c
+           - realtek,rtl9310-i2c
++          - realtek,rtl9607-i2c
+   reg:
+     items:
+@@ -51,6 +54,9 @@ properties:
+       The SCL line number of this I2C controller.
+     enum: [ 0, 1 ]
++  clocks:
++    maxItems: 1
++
+ patternProperties:
+   '^i2c@[0-9ab]$':
+     $ref: /schemas/i2c/i2c-controller.yaml
+@@ -82,6 +88,15 @@ allOf:
+     then:
+       patternProperties:
+         '^i2c@[89ab]$': false
++  - if:
++      properties:
++        compatible:
++          contains:
++            const: realtek,rtl9607-i2c
++    then:
++      required:
++        - realtek,scl
++        - clocks
+ required:
+   - compatible
diff --git a/target/linux/realtek/patches-6.18/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch b/target/linux/realtek/patches-6.18/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch
new file mode 100644 (file)
index 0000000..56bb8a8
--- /dev/null
@@ -0,0 +1,70 @@
+From f60d27926c9e2d547200fb0d26f61eec9b8291a6 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:46 +0500
+Subject: i2c: rtl9300: introduce clk struct for upcoming rtl9607 support
+
+In RTL9607C i2c controller, there is 10 bit CLK_DIV field for
+setting the clock of i2c interface which depends on the rate
+of i2c clk (which seems be fixed to 62.5MHz according to Realtek SDK).
+
+Introduce the clk struct and the respective F_CLK_DIV and clk_div
+which are going to be used in the upcoming patch for rtl9607c i2c
+controller support addition.
+
+devm_clk_get_optional_enabled() function was used for cleaner code
+as it automatically returns NULL if the clk is not present, which is
+going to be the case for RTL9300 and RTL9310 i2c controllers.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-7-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -1,6 +1,7 @@
+ // SPDX-License-Identifier: GPL-2.0-only
+ #include <linux/bits.h>
++#include <linux/clk.h>
+ #include <linux/i2c.h>
+ #include <linux/i2c-mux.h>
+ #include <linux/mod_devicetable.h>
+@@ -28,6 +29,7 @@ struct rtl9300_i2c_chan {
+       struct rtl9300_i2c *i2c;
+       enum rtl9300_bus_freq bus_freq;
+       u8 sda_num;
++      u32 clk_div;
+ };
+ enum rtl9300_i2c_reg_scope {
+@@ -54,6 +56,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SDA_OUT_SEL,
+       F_SDA_SEL,
+       F_BUSY,
++      F_CLK_DIV,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -85,6 +88,7 @@ struct rtl9300_i2c {
+       u8 scl_num;
+       u8 sda_num;
+       struct mutex lock;
++      struct clk *clk;
+ };
+ DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock))
+@@ -432,6 +436,10 @@ static int rtl9300_i2c_probe(struct plat
+       if (ret)
+               return ret;
++      i2c->clk = devm_clk_get_optional_enabled(dev, NULL);
++      if (IS_ERR(i2c->clk))
++              return dev_err_probe(dev, PTR_ERR(i2c->clk), "Failed to enable i2c clock\n");
++
+       i = 0;
+       for_each_child_of_node_scoped(dev->of_node, child) {
+               struct rtl9300_i2c_chan *chan = &i2c->chans[i];
diff --git a/target/linux/realtek/patches-6.18/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch b/target/linux/realtek/patches-6.18/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch
new file mode 100644 (file)
index 0000000..f2fe9e7
--- /dev/null
@@ -0,0 +1,147 @@
+From 991cd899ecd03a1c3ef7d177a0b99e824c6be581 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:47 +0500
+Subject: i2c: rtl9300: introduce new function properties to driver data
+
+Due to the very nature of differences between RTL9607C i2c controller
+and RTL9300 / RTL9310 that are incompatible with each other in some areas
+of this driver, for example in clock configuration, channel configuration
+and initialization at the end of the probe, introduce new function
+properties to the driver data struct to handle those differences.
+
+With these new properties, create configuration functions for RTL9300 and
+RTL9310 and assign them to their respective driver data structs.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-8-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 66 ++++++++++++++++++++++++++--------------
+ 1 file changed, 44 insertions(+), 22 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -65,6 +65,9 @@ enum rtl9300_i2c_reg_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);
++      int (*config_chan)(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan);
++      void (*config_clock)(u32 clock_freq, struct rtl9300_i2c_chan *chan);
++      int (*misc_init)(struct rtl9300_i2c *i2c);
+       u32 rd_reg;
+       u32 wd_reg;
+       u8 max_nchan;
+@@ -175,6 +178,30 @@ static int rtl9300_i2c_config_chan(struc
+       return 0;
+ }
++static void rtl9300_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
++{
++      struct rtl9300_i2c *i2c = chan->i2c;
++
++      switch (clock_freq) {
++      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;
++      case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
++              chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
++              break;
++      case RTL9300_I2C_MAX_SLOW_FREQ:
++              chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
++              break;
++      default:
++              dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
++                       chan->sda_num, clock_freq);
++              break;
++      }
++}
++
+ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
+ {
+       u32 vals[4] = {};
+@@ -322,7 +349,7 @@ static int rtl9300_i2c_smbus_xfer(struct
+       guard(rtl9300_i2c)(i2c);
+       drv_data = device_get_match_data(i2c->dev);
+-      ret = rtl9300_i2c_config_chan(i2c, chan);
++      ret = drv_data->config_chan(i2c, chan);
+       if (ret)
+               return ret;
+@@ -389,6 +416,12 @@ static struct i2c_adapter_quirks rtl9300
+       .max_write_len  = 16,
+ };
++static int rtl9300_i2c_init(struct rtl9300_i2c *i2c)
++{
++      /* only use standard read format */
++      return regmap_field_write(i2c->fields[F_RD_MODE], 0);
++}
++
+ static int rtl9300_i2c_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+@@ -453,27 +486,11 @@ static int rtl9300_i2c_probe(struct plat
+               if (ret)
+                       clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
+-              switch (clock_freq) {
+-              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;
+-              case RTL9300_I2C_MAX_SUPER_FAST_FREQ:
+-                      chan->bus_freq = RTL9300_I2C_SUPER_FAST_FREQ;
+-                      break;
+-              case RTL9300_I2C_MAX_SLOW_FREQ:
+-                      chan->bus_freq = RTL9300_I2C_SLOW_FREQ;
+-                      break;
+-              default:
+-                      dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n",
+-                               sda_num, clock_freq);
+-                      break;
+-              }
+-
+               chan->sda_num = sda_num;
+               chan->i2c = i2c;
++
++              drv_data->config_clock(clock_freq, chan);
++
+               adap = &i2c->chans[i].adap;
+               adap->owner = THIS_MODULE;
+               adap->algo = &rtl9300_i2c_algo;
+@@ -491,8 +508,7 @@ static int rtl9300_i2c_probe(struct plat
+       }
+       i2c->sda_num = 0xff;
+-      /* only use standard read format */
+-      ret = regmap_field_write(i2c->fields[F_RD_MODE], 0);
++      ret = drv_data->misc_init(i2c);
+       if (ret)
+               return ret;
+@@ -521,6 +537,9 @@ static const struct rtl9300_i2c_drv_data
+               [F_BUSY]                = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0),
+       },
+       .select_scl = rtl9300_i2c_select_scl,
++      .config_chan = rtl9300_i2c_config_chan,
++      .config_clock = rtl9300_i2c_config_clock,
++      .misc_init = rtl9300_i2c_init,
+       .rd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .wd_reg = RTL9300_I2C_MST_DATA_WORD0,
+       .max_nchan = RTL9300_I2C_MUX_NCHAN,
+@@ -545,6 +564,9 @@ static const struct rtl9300_i2c_drv_data
+               [F_BUSY]                = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0),
+       },
+       .select_scl = rtl9310_i2c_select_scl,
++      .config_chan = rtl9300_i2c_config_chan,
++      .config_clock = rtl9300_i2c_config_clock,
++      .misc_init = rtl9300_i2c_init,
+       .rd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .wd_reg = RTL9310_I2C_MST_DATA_CTRL,
+       .max_nchan = RTL9310_I2C_MUX_NCHAN,
diff --git a/target/linux/realtek/patches-6.18/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch b/target/linux/realtek/patches-6.18/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch
new file mode 100644 (file)
index 0000000..13a6530
--- /dev/null
@@ -0,0 +1,154 @@
+From 40890b5fe72b1a0d4913883844854f6641a2f4b3 Mon Sep 17 00:00:00 2001
+From: Rustam Adilov <adilov@disroot.org>
+Date: Wed, 1 Apr 2026 23:06:48 +0500
+Subject: i2c: rtl9300: add RTL9607C i2c controller support
+
+Add support for the internal I2C controllers of RTL9607C series based
+SoCs. Add register definitions, chip-specific functions and macros too.
+
+Make use of the clk introduced from the previous patch to get the clk_div
+value and use it during the rtl9607c channel configuration.
+
+Introduce a new EXT_SCK_5MS field to the reg fields struct which is going
+to be initialized by rtl9607c init function at the end of the probe.
+
+This patch depends on all the previous patches in this patch series.
+
+Signed-off-by: Rustam Adilov <adilov@disroot.org>
+Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz>
+Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
+Link: https://lore.kernel.org/r/20260401180648.337834-9-adilov@disroot.org
+---
+ drivers/i2c/busses/i2c-rtl9300.c | 70 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 70 insertions(+)
+
+--- a/drivers/i2c/busses/i2c-rtl9300.c
++++ b/drivers/i2c/busses/i2c-rtl9300.c
+@@ -57,6 +57,7 @@ enum rtl9300_i2c_reg_fields {
+       F_SDA_SEL,
+       F_BUSY,
+       F_CLK_DIV,
++      F_EXT_SCK_5MS,
+       /* keep last */
+       F_NUM_FIELDS
+@@ -77,8 +78,10 @@ struct rtl9300_i2c_drv_data {
+ #define RTL9300_I2C_MUX_NCHAN 8
+ #define RTL9310_I2C_MUX_NCHAN 12
++#define RTL9607_I2C_MUX_NCHAN 1
+ #define RTL9300_I2C_MAX_DATA_LEN      16
++#define RTL9607_I2C_MAX_DATA_LEN      4
+ struct rtl9300_i2c {
+       struct regmap *regmap;
+@@ -127,6 +130,14 @@ struct rtl9300_i2c_xfer {
+ #define RTL9310_I2C_MST_MEMADDR_CTRL                  0x4
+ #define RTL9310_I2C_MST_DATA_CTRL                     0x8
++#define RTL9607_I2C_CONFIG                            0x22f50
++#define RTL9607_IO_MODE_EN                            0x23014
++#define RTL9607_I2C_IND_WD                            0x0
++#define RTL9607_I2C_IND_ADR                           0x8
++#define RTL9607_I2C_IND_CMD                           0x10
++#define RTL9607_I2C_IND_RD                            0x18
++#define RTL9607_REG_ADDR_8BIT_LEN                     0
++
+ static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
+ {
+       int ret;
+@@ -178,6 +189,27 @@ static int rtl9300_i2c_config_chan(struc
+       return 0;
+ }
++static int rtl9607_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
++{
++      const struct rtl9300_i2c_drv_data *drv_data;
++      int ret;
++
++      if (i2c->sda_num == chan->sda_num)
++              return 0;
++
++      ret = regmap_field_write(i2c->fields[F_CLK_DIV], chan->clk_div);
++      if (ret)
++              return ret;
++
++      drv_data = device_get_match_data(i2c->dev);
++      ret = drv_data->select_scl(i2c, i2c->scl_num);
++      if (ret)
++              return ret;
++
++      i2c->sda_num = chan->sda_num;
++      return 0;
++}
++
+ static void rtl9300_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
+ {
+       struct rtl9300_i2c *i2c = chan->i2c;
+@@ -202,6 +234,13 @@ static void rtl9300_i2c_config_clock(u32
+       }
+ }
++static void rtl9607_i2c_config_clock(u32 clock_freq, struct rtl9300_i2c_chan *chan)
++{
++      struct rtl9300_i2c *i2c = chan->i2c;
++
++      chan->clk_div = clk_get_rate(i2c->clk) / clock_freq - 1;
++}
++
+ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
+ {
+       u32 vals[4] = {};
+@@ -422,6 +461,11 @@ static int rtl9300_i2c_init(struct rtl93
+       return regmap_field_write(i2c->fields[F_RD_MODE], 0);
+ }
++static int rtl9607_i2c_init(struct rtl9300_i2c *i2c)
++{
++      return regmap_field_write(i2c->fields[F_EXT_SCK_5MS], 1);
++}
++
+ static int rtl9300_i2c_probe(struct platform_device *pdev)
+ {
+       struct device *dev = &pdev->dev;
+@@ -574,6 +618,31 @@ static const struct rtl9300_i2c_drv_data
+       .reg_addr_8bit_len = RTL9300_REG_ADDR_8BIT_LEN,
+ };
++static const struct rtl9300_i2c_drv_data rtl9607_i2c_drv_data = {
++      .field_desc = {
++              [F_SCL_SEL]             = GLB_REG_FIELD(RTL9607_IO_MODE_EN, 13, 14),
++              [F_EXT_SCK_5MS]         = MST_REG_FIELD(RTL9607_I2C_CONFIG, 26, 26),
++              [F_DEV_ADDR]            = MST_REG_FIELD(RTL9607_I2C_CONFIG, 14, 20),
++              [F_MEM_ADDR_WIDTH]      = MST_REG_FIELD(RTL9607_I2C_CONFIG, 12, 13),
++              [F_DATA_WIDTH]          = MST_REG_FIELD(RTL9607_I2C_CONFIG, 10, 11),
++              [F_CLK_DIV]             = MST_REG_FIELD(RTL9607_I2C_CONFIG, 0, 9),
++              [F_I2C_FAIL]            = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 3, 3),
++              [F_BUSY]                = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 2, 2),
++              [F_RWOP]                = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 1, 1),
++              [F_I2C_TRIG]            = MST_REG_FIELD(RTL9607_I2C_IND_CMD, 0, 0),
++              [F_MEM_ADDR]            = MST_REG_FIELD(RTL9607_I2C_IND_ADR, 0, 31),
++      },
++      .select_scl = rtl9310_i2c_select_scl,
++      .config_chan = rtl9607_i2c_config_chan,
++      .config_clock = rtl9607_i2c_config_clock,
++      .misc_init = rtl9607_i2c_init,
++      .rd_reg = RTL9607_I2C_IND_RD,
++      .wd_reg = RTL9607_I2C_IND_WD,
++      .max_nchan = RTL9607_I2C_MUX_NCHAN,
++      .max_data_len = RTL9607_I2C_MAX_DATA_LEN,
++      .reg_addr_8bit_len = RTL9607_REG_ADDR_8BIT_LEN,
++};
++
+ 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 },
+@@ -583,6 +652,7 @@ static const struct of_device_id i2c_rtl
+       { .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 },
++      { .compatible = "realtek,rtl9607-i2c", .data = (void *) &rtl9607_i2c_drv_data },
+       {}
+ };
+ MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids);