Hi Guenter, On Sun, 1 Feb 2015 15:48:01 -0800, Guenter Roeck wrote: > SMBUs access functions assume that 16 bit values are formatted as
Correct spelling is SMBus (lowercase U.) Also I think "16 bit" is better spelled "16-bit" (more occurrences below.) > little endian numbers. The direct i2c access functions in regmap, > however, assume that 16 bit values are formatted as big endian numbers. > As a result, the current code returns different values if an i2c chip's > 16 bit registers are accessed through i2c access functions vs. SMBus > access functions. > > Use regmap_smbus_read_word_swapped and regmap_smbus_write_word_swapped > for 16 bit SMBus accesses unless a chip is registered with val_format_endian > set to REGMAP_ENDIAN_LITTLE. In the latter case, keep using > regmap_smbus_write_word_data and regmap_smbus_read_word_data. > > Cc: Jean Delvare <jdelv...@suse.de> > Signed-off-by: Guenter Roeck <li...@roeck-us.net> > --- > Might be a candidate for -stable, though as far as I can see there is > currently > no driver in the upstream kernel using regmap for 16-bit i2c accesses. > > drivers/base/regmap/regmap-i2c.c | 41 > +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 40 insertions(+), 1 deletion(-) > > diff --git a/drivers/base/regmap/regmap-i2c.c > b/drivers/base/regmap/regmap-i2c.c > index 053150a..865f4f8 100644 > --- a/drivers/base/regmap/regmap-i2c.c > +++ b/drivers/base/regmap/regmap-i2c.c > @@ -87,6 +87,42 @@ static struct regmap_bus regmap_smbus_word = { > .reg_read = regmap_smbus_word_reg_read, > }; > > +static int regmap_smbus_word_read_swapped(void *context, unsigned int reg, > + unsigned int *val) > +{ > + struct device *dev = context; > + struct i2c_client *i2c = to_i2c_client(dev); > + int ret; > + > + if (reg > 0xff) > + return -EINVAL; > + > + ret = i2c_smbus_read_word_swapped(i2c, reg); > + if (ret < 0) > + return ret; > + > + *val = ret; > + > + return 0; > +} > + > +static int regmap_smbus_word_write_swapped(void *context, unsigned int reg, > + unsigned int val) > +{ > + struct device *dev = context; > + struct i2c_client *i2c = to_i2c_client(dev); > + > + if (val > 0xffff || reg > 0xff) > + return -EINVAL; > + > + return i2c_smbus_write_word_swapped(i2c, reg, val); > +} > + > +static struct regmap_bus regmap_smbus_word_swapped = { > + .reg_write = regmap_smbus_word_write_swapped, > + .reg_read = regmap_smbus_word_read_swapped, > +}; > + > static int regmap_i2c_write(void *context, const void *data, size_t count) > { > struct device *dev = context; > @@ -180,7 +216,10 @@ static const struct regmap_bus > *regmap_get_i2c_bus(struct i2c_client *i2c, > else if (config->val_bits == 16 && config->reg_bits == 8 && > i2c_check_functionality(i2c->adapter, > I2C_FUNC_SMBUS_WORD_DATA)) > - return ®map_smbus_word; > + if (config->val_format_endian == REGMAP_ENDIAN_LITTLE) > + return ®map_smbus_word; > + else > + return ®map_smbus_word_swapped; Indentation looks wrong. > else if (config->val_bits == 8 && config->reg_bits == 8 && > i2c_check_functionality(i2c->adapter, > I2C_FUNC_SMBUS_BYTE_DATA)) The code itself looks sane, although I am not a regmap expert. Reviewed-by: Jean Delvare <jdelv...@suse.de> -- Jean Delvare SUSE L3 Support -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/