From bad4bd28abf4d7cb2adcb39cc0de789729d2cd69 Mon Sep 17 00:00:00 2001 From: Nishanth Sampath Kumar Date: Tue, 7 Apr 2026 16:39:27 -0700 Subject: [PATCH 1/2] 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 Link: https://patch.msgid.link/20260407233927.498932-1-nissampa@cisco.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-i2c.c | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index c9b39a02278e..31e30dfced19 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -303,6 +303,50 @@ static const struct regmap_bus regmap_i2c_smbus_i2c_block_reg16 = { .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 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, 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)) From 7e555fcae40ab2ba91fd5cd54a5a83096414957f Mon Sep 17 00:00:00 2001 From: Yuho Choi Date: Thu, 16 Apr 2026 19:56:30 -0400 Subject: [PATCH 2/2] regmap: ram: fix memory leaks in __regmap_init_ram() on error Two allocations in __regmap_init_ram() are not cleaned up on failure. If the kzalloc_objs() for data->written fails, data->read is returned with no way for the caller to free it. If __regmap_init() fails, neither data->read nor data->written is freed because its error paths do not call bus->free_context() (which is regmap_ram_free_context() here). Only regmap_exit() does, and that is never reached on an init failure. Free the allocated arrays before returning any error. Fixes: f6352424e37e ("regmap: Add RAM backed register map") Signed-off-by: Yuho Choi Link: https://patch.msgid.link/20260416235630.78408-1-dbgh9129@gmail.com Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-ram.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap-ram.c b/drivers/base/regmap/regmap-ram.c index 0272d53fead1..c7356b0d8c83 100644 --- a/drivers/base/regmap/regmap-ram.c +++ b/drivers/base/regmap/regmap-ram.c @@ -71,11 +71,17 @@ struct regmap *__regmap_init_ram(struct device *dev, return ERR_PTR(-ENOMEM); data->written = kzalloc_objs(bool, config->max_register + 1); - if (!data->written) + if (!data->written) { + kfree(data->read); return ERR_PTR(-ENOMEM); + } map = __regmap_init(dev, ®map_ram, data, config, lock_key, lock_name); + if (IS_ERR(map)) { + kfree(data->read); + kfree(data->written); + } return map; }