diff --git a/patches-sonic/cisco-regmap-i2c-smbus-byte-word-reg16.patch b/patches-sonic/cisco-regmap-i2c-smbus-byte-word-reg16.patch new file mode 100755 index 000000000..8f0beee99 --- /dev/null +++ b/patches-sonic/cisco-regmap-i2c-smbus-byte-word-reg16.patch @@ -0,0 +1,112 @@ +From: Nishanth Sampath Kumar +Date: Mon, 07 Apr 2026 12:00:00 -0700 +Subject: [PATCH v2] regmap-i2c: add SMBus byte/word reg16 bus for adapters + lacking I2C_FUNC_I2C + +AMD PIIX4 SMBus adapters, present on AMD SP5/EPYC-based platforms +(including Cisco 8000 series routers), support SMBUS_BYTE_DATA and +SMBUS_WORD_DATA but lack I2C_FUNC_I2C and I2C_FUNC_SMBUS_I2C_BLOCK. + +When at24 (or any driver) requests a regmap with reg_bits=16 and +val_bits=8 on such an adapter, regmap_get_i2c_bus() finds no matching +bus and returns -ENOTSUPP. The existing regmap_i2c_smbus_i2c_block_reg16 +bus type already implements 16-bit addressed reads using only +write_byte_data() + read_byte() primitives, but its selection is gated +on I2C_FUNC_SMBUS_I2C_BLOCK which these adapters lack. + +Add a new regmap_smbus_byte_word_reg16 bus that: + + READ: reuses regmap_i2c_smbus_i2c_read_reg16() -- sets the 16-bit + address via write_byte_data(addr_lo, addr_hi), then reads + bytes sequentially via read_byte() (EEPROM auto-increments). + Requires only SMBUS_BYTE_DATA. + + WRITE: uses write_word_data(addr_hi, (data << 8) | addr_lo) to + encode one data byte per SMBus WORD transaction. + Requires only SMBUS_WORD_DATA. Single-byte writes only. + +The new bus is selected in regmap_get_i2c_bus() when reg_bits=16, +val_bits=8, and the adapter has SMBUS_BYTE_DATA | SMBUS_WORD_DATA but +not I2C_FUNC_I2C or SMBUS_I2C_BLOCK. The branch is placed after the +existing I2C_BLOCK_reg16 check so adapters with full block support +continue to use the faster path. + +This fixes at24 EEPROM probe failures on PIIX4: + at24 3-0055: probe with driver at24 failed with error -524 + +No driver changes are required -- at24 already passes reg_bits=16 to +devm_regmap_init_i2c(), which now succeeds. + +Signed-off-by: Nishanth Sampath Kumar +--- +v1 -> v2: Moved fix from at24 driver into regmap-i2c core per review + feedback from Bartosz Golaszewski and Mark Brown. + + drivers/base/regmap/regmap-i2c.c | 49 ++++++++++++++++++++++++++++++++ + 1 file changed, 49 insertions(+) + +--- a/drivers/base/regmap/regmap-i2c.c ++++ b/drivers/base/regmap/regmap-i2c.c +@@ -303,6 +303,50 @@ + .max_raw_write = I2C_SMBUS_BLOCK_MAX - 2, + }; + ++/* ++ * SMBus byte/word reg16 support for adapters that have SMBUS_BYTE_DATA ++ * and SMBUS_WORD_DATA but lack I2C_FUNC_I2C and I2C_FUNC_SMBUS_I2C_BLOCK, ++ * such as the AMD PIIX4. ++ * ++ * READ: set 16-bit EEPROM address via write_byte_data(addr_lo, addr_hi), ++ * then sequentially read bytes via read_byte() (EEPROM auto- ++ * increments the address pointer). Same as the I2C-block reg16 ++ * read path above. ++ * ++ * WRITE: encode the low address byte and data into a word transaction: ++ * write_word_data(addr_hi, (data_byte << 8) | addr_lo). ++ * Only single-byte writes are supported (one value per transaction). ++ */ ++static int regmap_smbus_word_write_reg16(void *context, const void *data, ++ size_t count) ++{ ++ struct device *dev = context; ++ struct i2c_client *i2c = to_i2c_client(dev); ++ u8 addr_hi, addr_lo, val; ++ ++ /* ++ * data layout: [addr_hi, addr_lo, val0, val1, ...]. ++ * Only single-byte value writes are supported; multi-byte would ++ * require raw I2C (or repeated word writes with incrementing address). ++ */ ++ if (count != 3) ++ return -EINVAL; ++ ++ addr_hi = ((u8 *)data)[0]; ++ addr_lo = ((u8 *)data)[1]; ++ val = ((u8 *)data)[2]; ++ ++ return i2c_smbus_write_word_data(i2c, addr_hi, ++ cpu_to_le16(((u16)val << 8) | addr_lo)); ++} ++ ++static const struct regmap_bus regmap_smbus_byte_word_reg16 = { ++ .write = regmap_smbus_word_write_reg16, ++ .read = regmap_i2c_smbus_i2c_read_reg16, ++ .max_raw_read = I2C_SMBUS_BLOCK_MAX - 2, ++ .max_raw_write = 1, ++}; ++ + static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, + const struct regmap_config *config) + { +@@ -321,6 +365,11 @@ + i2c_check_functionality(i2c->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) + bus = ®map_i2c_smbus_i2c_block_reg16; ++ else if (config->val_bits == 8 && config->reg_bits == 16 && ++ i2c_check_functionality(i2c->adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | ++ I2C_FUNC_SMBUS_WORD_DATA)) ++ bus = ®map_smbus_byte_word_reg16; + else if (config->val_bits == 16 && config->reg_bits == 8 && + i2c_check_functionality(i2c->adapter, + I2C_FUNC_SMBUS_WORD_DATA))