Use regmap for register accesses to be able to utilize its caching functionality. This also lets us hide register access differences in regmap code. Signed-off-by: Guenter Roeck <linux@xxxxxxxxxxxx> --- drivers/hwmon/Kconfig | 1 + drivers/hwmon/tmp401.c | 225 +++++++++++++++++++++++++++-------------- 2 files changed, 150 insertions(+), 76 deletions(-) diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 64bd3dfba2c4..e0e6e5889591 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1939,6 +1939,7 @@ config SENSORS_TMP108 config SENSORS_TMP401 tristate "Texas Instruments TMP401 and compatibles" depends on I2C + select REGMAP help If you say yes here you get support for Texas Instruments TMP401, TMP411, TMP431, TMP432, and TMP435 temperature sensor chips. diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index f595d8555370..0b1f31b02344 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/regmap.h> #include <linux/slab.h> /* Addresses to scan */ @@ -114,6 +115,7 @@ MODULE_DEVICE_TABLE(i2c, tmp401_id); struct tmp401_data { struct i2c_client *client; + struct regmap *regmap; struct mutex update_lock; enum chips kind; @@ -128,32 +130,30 @@ struct tmp401_data { struct hwmon_chip_info chip; }; -static int tmp401_register_to_temp(u16 reg, bool extended) -{ - int temp = reg; - - if (extended) - temp -= 64 * 256; +/* regmap */ - return DIV_ROUND_CLOSEST(temp * 125, 32); -} - -static u16 tmp401_temp_to_register(long temp, bool extended, int zbits) +static bool tmp401_regmap_is_volatile(struct device *dev, unsigned int reg) { - if (extended) { - temp = clamp_val(temp, -64000, 191000); - temp += 64000; - } else { - temp = clamp_val(temp, 0, 127000); + switch (reg) { + case 0: /* local temp msb */ + case 1: /* remote temp msb */ + case 2: /* status */ + case 0x10: /* remote temp lsb */ + case 0x15: /* local temp lsb */ + case 0x1b: /* status (tmp432) */ + case 0x23 ... 0x24: /* remote temp 2 msb / lsb */ + case 0x30 ... 0x37: /* lowest/highest temp; status (tmp432) */ + return true; + default: + return false; } - - return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; } -static int tmp401_reg_read(struct tmp401_data *data, unsigned int reg) +static int tmp401_reg_read(void *context, unsigned int reg, unsigned int *val) { + struct tmp401_data *data = context; struct i2c_client *client = data->client; - int val, regval; + int regval; switch (reg) { case 0: /* local temp msb */ @@ -172,55 +172,71 @@ static int tmp401_reg_read(struct tmp401_data *data, unsigned int reg) /* work around register overlap between TMP411 and TMP432 */ if (reg == 0xf6) reg = 0x36; - return i2c_smbus_read_word_swapped(client, reg); + regval = i2c_smbus_read_word_swapped(client, reg); + if (regval < 0) + return regval; + *val = regval; + break; case 0x19: /* critical limits, 8-bit registers */ case 0x1a: case 0x20: regval = i2c_smbus_read_byte_data(client, reg); if (regval < 0) return regval; - return regval << 8; + *val = regval << 8; + break; case 0x1b: case 0x35 ... 0x37: - if (data->kind == tmp432) - return i2c_smbus_read_byte_data(client, reg); + if (data->kind == tmp432) { + regval = i2c_smbus_read_byte_data(client, reg); + if (regval < 0) + return regval; + *val = regval; + break; + } /* simulate TMP432 status registers */ regval = i2c_smbus_read_byte_data(client, TMP401_STATUS); if (regval < 0) return regval; - val = 0; + *val = 0; switch (reg) { case 0x1b: /* open / fault */ if (regval & TMP401_STATUS_REMOTE_OPEN) - val |= BIT(1); + *val |= BIT(1); break; case 0x35: /* high limit */ if (regval & TMP401_STATUS_LOCAL_HIGH) - val |= BIT(0); + *val |= BIT(0); if (regval & TMP401_STATUS_REMOTE_HIGH) - val |= BIT(1); + *val |= BIT(1); break; case 0x36: /* low limit */ if (regval & TMP401_STATUS_LOCAL_LOW) - val |= BIT(0); + *val |= BIT(0); if (regval & TMP401_STATUS_REMOTE_LOW) - val |= BIT(1); + *val |= BIT(1); break; case 0x37: /* therm / crit limit */ if (regval & TMP401_STATUS_LOCAL_CRIT) - val |= BIT(0); + *val |= BIT(0); if (regval & TMP401_STATUS_REMOTE_CRIT) - val |= BIT(1); + *val |= BIT(1); break; } - return val; + break; default: - return i2c_smbus_read_byte_data(client, reg); + regval = i2c_smbus_read_byte_data(client, reg); + if (regval < 0) + return regval; + *val = regval; + break; } + return 0; } -static int tmp401_reg_write(struct tmp401_data *data, unsigned int reg, unsigned int val) +static int tmp401_reg_write(void *context, unsigned int reg, unsigned int val) { + struct tmp401_data *data = context; struct i2c_client *client = data->client; switch (reg) { @@ -240,6 +256,41 @@ static int tmp401_reg_write(struct tmp401_data *data, unsigned int reg, unsigned } } +static const struct regmap_config tmp401_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = tmp401_regmap_is_volatile, + .reg_read = tmp401_reg_read, + .reg_write = tmp401_reg_write, +}; + +/* temperature conversion */ + +static int tmp401_register_to_temp(u16 reg, bool extended) +{ + int temp = reg; + + if (extended) + temp -= 64 * 256; + + return DIV_ROUND_CLOSEST(temp * 125, 32); +} + +static u16 tmp401_temp_to_register(long temp, bool extended, int zbits) +{ + if (extended) { + temp = clamp_val(temp, -64000, 191000); + temp += 64000; + } else { + temp = clamp_val(temp, 0, 127000); + } + + return DIV_ROUND_CLOSEST(temp * (1 << (8 - zbits)), 1000) << zbits; +} + +/* hwmon API functions */ + static const u8 tmp401_temp_reg_index[] = { [hwmon_temp_input] = 0, [hwmon_temp_min] = 1, @@ -259,7 +310,9 @@ static const u8 tmp401_status_reg_index[] = { static int tmp401_temp_read(struct device *dev, u32 attr, int channel, long *val) { struct tmp401_data *data = dev_get_drvdata(dev); - int reg, regval; + struct regmap *regmap = data->regmap; + unsigned int regval; + int reg, ret; switch (attr) { case hwmon_temp_input: @@ -269,36 +322,35 @@ static int tmp401_temp_read(struct device *dev, u32 attr, int channel, long *val case hwmon_temp_lowest: case hwmon_temp_highest: reg = TMP401_TEMP_MSB_READ[tmp401_temp_reg_index[attr]][channel]; - regval = tmp401_reg_read(data, reg); - if (regval < 0) - return regval; + ret = regmap_read(regmap, reg, ®val); + if (ret < 0) + return ret; *val = tmp401_register_to_temp(regval, data->extended_range); break; case hwmon_temp_crit_hyst: mutex_lock(&data->update_lock); reg = TMP401_TEMP_MSB_READ[3][channel]; - regval = tmp401_reg_read(data, reg); - if (regval < 0) + ret = regmap_read(regmap, reg, ®val); + if (ret < 0) goto unlock; *val = tmp401_register_to_temp(regval, data->extended_range); - regval = tmp401_reg_read(data, TMP401_TEMP_CRIT_HYST); - if (regval < 0) + ret = regmap_read(regmap, TMP401_TEMP_CRIT_HYST, ®val); + if (ret < 0) goto unlock; *val -= regval * 1000; - regval = 0; unlock: mutex_unlock(&data->update_lock); - if (regval < 0) - return regval; + if (ret < 0) + return ret; break; case hwmon_temp_fault: case hwmon_temp_min_alarm: case hwmon_temp_max_alarm: case hwmon_temp_crit_alarm: reg = TMP432_STATUS_REG[tmp401_status_reg_index[attr]]; - regval = tmp401_reg_read(data, reg); - if (regval < 0) - return regval; + ret = regmap_read(regmap, reg, ®val); + if (ret < 0) + return ret; *val = !!(regval & BIT(channel)); break; default: @@ -311,7 +363,9 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, long val) { struct tmp401_data *data = dev_get_drvdata(dev); - int reg, regval, ret, temp; + struct regmap *regmap = data->regmap; + unsigned int regval; + int reg, ret, temp; mutex_lock(&data->update_lock); switch (attr) { @@ -321,7 +375,14 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, reg = TMP401_TEMP_MSB_WRITE[tmp401_temp_reg_index[attr]][channel]; regval = tmp401_temp_to_register(val, data->extended_range, attr == hwmon_temp_crit ? 8 : 4); - ret = tmp401_reg_write(data, reg, regval); + ret = regmap_write(regmap, reg, regval); + if (ret) + break; + /* + * Read and write limit registers are different, so we need to + * reinitialize the cache. + */ + ret = regmap_reinit_cache(regmap, &tmp401_regmap_config); break; case hwmon_temp_crit_hyst: if (data->extended_range) @@ -330,13 +391,13 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, val = clamp_val(val, 0, 127000); reg = TMP401_TEMP_MSB_READ[3][channel]; - ret = tmp401_reg_read(data, reg); + ret = regmap_read(regmap, reg, ®val); if (ret < 0) break; - temp = tmp401_register_to_temp(ret, data->extended_range); + temp = tmp401_register_to_temp(regval, data->extended_range); val = clamp_val(val, temp - 255000, temp); regval = ((temp - val) + 500) / 1000; - ret = tmp401_reg_write(data, TMP401_TEMP_CRIT_HYST, regval); + ret = regmap_write(regmap, TMP401_TEMP_CRIT_HYST, regval); break; default: ret = -EOPNOTSUPP; @@ -349,13 +410,14 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val) { struct tmp401_data *data = dev_get_drvdata(dev); - int regval; + u32 regval; + int ret; switch (attr) { case hwmon_chip_update_interval: - regval = tmp401_reg_read(data, TMP401_CONVERSION_RATE_READ); - if (regval < 0) - return regval; + ret = regmap_read(data->regmap, TMP401_CONVERSION_RATE_READ, ®val); + if (ret < 0) + return ret; *val = (1 << (7 - regval)) * 125; break; case hwmon_chip_temp_reset_history: @@ -368,7 +430,7 @@ static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val return 0; } -static int tmp401_set_convrate(struct i2c_client *client, struct tmp401_data *data, long val) +static int tmp401_set_convrate(struct regmap *regmap, long val) { int err, rate; @@ -382,22 +444,26 @@ static int tmp401_set_convrate(struct i2c_client *client, struct tmp401_data *da */ val = clamp_val(val, 125, 16000); rate = 7 - __fls(val * 4 / (125 * 3)); - err = i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, rate); + err = regmap_write(regmap, TMP401_CONVERSION_RATE_WRITE, rate); if (err) return err; - return 0; + /* + * Read and write conversion rate registers are different, so we need to + * reinitialize the cache. + */ + return regmap_reinit_cache(regmap, &tmp401_regmap_config); } static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val) { struct tmp401_data *data = dev_get_drvdata(dev); - struct i2c_client *client = data->client; + struct regmap *regmap = data->regmap; int err; mutex_lock(&data->update_lock); switch (attr) { case hwmon_chip_update_interval: - err = tmp401_set_convrate(client, data, val); + err = tmp401_set_convrate(regmap, val); break; case hwmon_chip_temp_reset_history: if (val != 1) { @@ -408,7 +474,7 @@ static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val * Reset history by writing any value to any of the * minimum/maximum registers (0x30-0x37). */ - err = i2c_smbus_write_byte_data(client, 0x30, 0); + err = regmap_write(regmap, 0x30, 0); break; default: err = -EOPNOTSUPP; @@ -488,18 +554,23 @@ static const struct hwmon_ops tmp401_ops = { .write = tmp401_write, }; -static int tmp401_init_client(struct tmp401_data *data, - struct i2c_client *client) +/* chip initialization, detect, probe */ + +static int tmp401_init_client(struct tmp401_data *data) { - int config, config_orig, status = 0; + struct regmap *regmap = data->regmap; + u32 config, config_orig; + int ret; - /* Set the conversion rate to 2 Hz */ - i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); + /* Set conversion rate to 2 Hz */ + ret = regmap_write(regmap, TMP401_CONVERSION_RATE_WRITE, 5); + if (ret < 0) + return ret; /* Start conversions (disable shutdown if necessary) */ - config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); - if (config < 0) - return config; + ret = regmap_read(regmap, TMP401_CONFIG_READ, &config); + if (ret < 0) + return ret; config_orig = config; config &= ~TMP401_CONFIG_SHUTDOWN; @@ -507,11 +578,9 @@ static int tmp401_init_client(struct tmp401_data *data, data->extended_range = !!(config & TMP401_CONFIG_RANGE); if (config != config_orig) - status = i2c_smbus_write_byte_data(client, - TMP401_CONFIG_WRITE, - config); + ret = regmap_write(regmap, TMP401_CONFIG_WRITE, config); - return status; + return ret; } static int tmp401_detect(struct i2c_client *client, @@ -602,6 +671,10 @@ static int tmp401_probe(struct i2c_client *client) mutex_init(&data->update_lock); data->kind = i2c_match_id(tmp401_id, client)->driver_data; + data->regmap = devm_regmap_init(dev, NULL, data, &tmp401_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + /* initialize configuration data */ data->chip.ops = &tmp401_ops; data->chip.info = data->info; @@ -639,7 +712,7 @@ static int tmp401_probe(struct i2c_client *client) } /* Initialize the TMP401 chip */ - status = tmp401_init_client(data, client); + status = tmp401_init_client(data); if (status < 0) return status; -- 2.33.0