regmap: Fixes for v7.1

There's couple of patches here that came in since my pull request:
 
  - What is effectively a quirk for shoehorning support for a wider range
    of I2C regmaps on weirdly restricted SMBus controllers.
  - One minor fix for a memory leak on in error handling in the dummy
    driver used by the KUnit tests.
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmnrgSsACgkQJNaLcl1U
 h9AfoAf/TYndFyEmvFiaG41OECKDlhRdtX43WS2ulFZDXjeAhRJlLecBVwHN8o5c
 RLMLvDs07nBr0arYCQl/MOvKZEUorT2Ka0eCI3RL95K0AitzF/taNcXTwEtnuAOT
 lBRBOSHsbR1+X2WJWhv56M0oK01//Hm9KG1CywiG1WzAXt708UWkVGMoB+T5AGw0
 RU12YIJCVcoX6CfHlwgFm8tZxk8GeaEKVy6tPwQ23SYt/trlqJpBqDCcTYAlVGzW
 hzqwgq1+/zFs4AH1zdk55Me0g82yC/linfgT5tfouKq3CIdEDUruYdPk/1vbJBdx
 mMrRovslNx+IEG61v8fnub0U6eM4iw==
 =1GRM
 -----END PGP SIGNATURE-----

Merge tag 'regmap-fix-v7.1-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap

Pull regmap fixes from Mark Brown:
 "There's couple of patches here that came in since my pull request:

   - What is effectively a quirk for shoehorning support for a wider
     range of I2C regmaps on weirdly restricted SMBus controllers

   - One minor fix for a memory leak on in error handling in the dummy
     driver used by the KUnit tests"

* tag 'regmap-fix-v7.1-merge-window' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap:
  regmap: ram: fix memory leaks in __regmap_init_ram() on error
  regmap-i2c: add SMBus byte/word reg16 bus for adapters lacking I2C_FUNC_I2C
This commit is contained in:
Linus Torvalds 2026-04-24 12:11:26 -07:00
commit 6e2d43100c
2 changed files with 56 additions and 1 deletions

View File

@ -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 = &regmap_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 = &regmap_smbus_byte_word_reg16;
else if (config->val_bits == 16 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_WORD_DATA))

View File

@ -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, &regmap_ram, data, config,
lock_key, lock_name);
if (IS_ERR(map)) {
kfree(data->read);
kfree(data->written);
}
return map;
}