From: Rustam Adilov Date: Sun, 29 Mar 2026 09:29:30 +0000 (+0500) Subject: realtek: i2c: rtl9300: backport rtl9607c i2c support and speed patches X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=refs%2Fpull%2F22663%2Fhead;p=thirdparty%2Fopenwrt.git realtek: i2c: rtl9300: backport rtl9607c i2c support and speed patches 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 Link: https://github.com/openwrt/openwrt/pull/22663 Signed-off-by: Hauke Mehrtens --- diff --git a/target/linux/realtek/patches-6.12/100-rtl9300-i2c-add-more-speeds.patch b/target/linux/realtek/patches-6.12/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch 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 8c1115aa238..a31b72e437f 100644 --- a/target/linux/realtek/patches-6.12/100-rtl9300-i2c-add-more-speeds.patch +++ b/target/linux/realtek/patches-6.12/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch @@ -1,10 +1,7 @@ -From linux-i2c Fri Feb 27 11:11:34 2026 -From: Jan Kantert -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 +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..502ca2217cd --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch @@ -0,0 +1,112 @@ +From 4c53b2eb4f18102c36d4bcaf8c604a1825701ffb Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..ba28e5a5fab --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch @@ -0,0 +1,66 @@ +From 98773df61f8416594ac993e8464df596755ee1b8 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..67dd19bccb6 --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch @@ -0,0 +1,56 @@ +From 55284a806b63a412846b9ecd3846f2639eaeaff4 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..ec6f6578d2c --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch @@ -0,0 +1,79 @@ +From 6afde011baaf722aa66c11696b6383f9ce85b653 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..9a1f2b3d390 --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch @@ -0,0 +1,73 @@ +From 1211ce1e11d23ec05d80a85b7187baa6abed3232 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Acked-by: Conor Dooley +Signed-off-by: Andi Shyti +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 index 00000000000..56bb8a8f582 --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch @@ -0,0 +1,70 @@ +From f60d27926c9e2d547200fb0d26f61eec9b8291a6 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 ++#include + #include + #include + #include +@@ -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 index 00000000000..f2fe9e7dfb3 --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch @@ -0,0 +1,147 @@ +From 991cd899ecd03a1c3ef7d177a0b99e824c6be581 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Signed-off-by: Andi Shyti +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 index 00000000000..13a6530a24e --- /dev/null +++ b/target/linux/realtek/patches-6.12/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch @@ -0,0 +1,154 @@ +From 40890b5fe72b1a0d4913883844854f6641a2f4b3 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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); diff --git a/target/linux/realtek/patches-6.18/100-rtl9300-i2c-add-more-speeds.patch b/target/linux/realtek/patches-6.18/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch 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 8c1115aa238..a31b72e437f 100644 --- a/target/linux/realtek/patches-6.18/100-rtl9300-i2c-add-more-speeds.patch +++ b/target/linux/realtek/patches-6.18/026-v7.1-i2c-rtl9300-add-support-for-more-bus-speeds.patch @@ -1,10 +1,7 @@ -From linux-i2c Fri Feb 27 11:11:34 2026 -From: Jan Kantert -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 +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..502ca2217cd --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-01-v7.1-i2c-rtl9300-split-data_reg-into-read-and-write-reg.patch @@ -0,0 +1,112 @@ +From 4c53b2eb4f18102c36d4bcaf8c604a1825701ffb Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..ba28e5a5fab --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-02-v7.1-i2c-rtl9300-introduce-max-length-property-to-driver-.patch @@ -0,0 +1,66 @@ +From 98773df61f8416594ac993e8464df596755ee1b8 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..67dd19bccb6 --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-03-v7.1-i2c-rtl9300-introduce-F_BUSY-to-the-reg_fields-struc.patch @@ -0,0 +1,56 @@ +From 55284a806b63a412846b9ecd3846f2639eaeaff4 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..ec6f6578d2c --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-04-v7.1-i2c-rtl9300-introduce-a-property-for-8-bit-width-reg.patch @@ -0,0 +1,79 @@ +From 6afde011baaf722aa66c11696b6383f9ce85b653 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 index 00000000000..9a1f2b3d390 --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-05-v7.1-dt-bindings-i2c-realtek-rtl9301-i2c-extend-for-clock.patch @@ -0,0 +1,73 @@ +From 1211ce1e11d23ec05d80a85b7187baa6abed3232 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Acked-by: Conor Dooley +Signed-off-by: Andi Shyti +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 index 00000000000..56bb8a8f582 --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-06-v7.1-i2c-rtl9300-introduce-clk-struct-for-upcoming-rtl960.patch @@ -0,0 +1,70 @@ +From f60d27926c9e2d547200fb0d26f61eec9b8291a6 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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 ++#include + #include + #include + #include +@@ -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 index 00000000000..f2fe9e7dfb3 --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-07-v7.1-i2c-rtl9300-introduce-new-function-properties-to-driv.patch @@ -0,0 +1,147 @@ +From 991cd899ecd03a1c3ef7d177a0b99e824c6be581 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Signed-off-by: Andi Shyti +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 index 00000000000..13a6530a24e --- /dev/null +++ b/target/linux/realtek/patches-6.18/027-08-v7.1-i2c-rtl9300-add-RTL9607C-i2c-controller-support.patch @@ -0,0 +1,154 @@ +From 40890b5fe72b1a0d4913883844854f6641a2f4b3 Mon Sep 17 00:00:00 2001 +From: Rustam Adilov +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 +Reviewed-by: Chris Packham +Signed-off-by: Andi Shyti +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);