Commit 50152fb6 authored by Guenter Roeck's avatar Guenter Roeck

hwmon: (tmp401) Use regmap

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: default avatarGuenter Roeck <linux@roeck-us.net>
parent ca53e764
...@@ -1951,6 +1951,7 @@ config SENSORS_TMP108 ...@@ -1951,6 +1951,7 @@ config SENSORS_TMP108
config SENSORS_TMP401 config SENSORS_TMP401
tristate "Texas Instruments TMP401 and compatibles" tristate "Texas Instruments TMP401 and compatibles"
depends on I2C depends on I2C
select REGMAP
help help
If you say yes here you get support for Texas Instruments TMP401, If you say yes here you get support for Texas Instruments TMP401,
TMP411, TMP431, TMP432, and TMP435 temperature sensor chips. TMP411, TMP431, TMP432, and TMP435 temperature sensor chips.
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/slab.h> #include <linux/slab.h>
/* Addresses to scan */ /* Addresses to scan */
...@@ -114,6 +115,7 @@ MODULE_DEVICE_TABLE(i2c, tmp401_id); ...@@ -114,6 +115,7 @@ MODULE_DEVICE_TABLE(i2c, tmp401_id);
struct tmp401_data { struct tmp401_data {
struct i2c_client *client; struct i2c_client *client;
struct regmap *regmap;
struct mutex update_lock; struct mutex update_lock;
enum chips kind; enum chips kind;
...@@ -128,32 +130,30 @@ struct tmp401_data { ...@@ -128,32 +130,30 @@ struct tmp401_data {
struct hwmon_chip_info chip; struct hwmon_chip_info chip;
}; };
static int tmp401_register_to_temp(u16 reg, bool extended) /* regmap */
{
int temp = reg;
if (extended)
temp -= 64 * 256;
return DIV_ROUND_CLOSEST(temp * 125, 32); static bool tmp401_regmap_is_volatile(struct device *dev, unsigned int reg)
}
static u16 tmp401_temp_to_register(long temp, bool extended, int zbits)
{ {
if (extended) { switch (reg) {
temp = clamp_val(temp, -64000, 191000); case 0: /* local temp msb */
temp += 64000; case 1: /* remote temp msb */
} else { case 2: /* status */
temp = clamp_val(temp, 0, 127000); 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; struct i2c_client *client = data->client;
int val, regval; int regval;
switch (reg) { switch (reg) {
case 0: /* local temp msb */ case 0: /* local temp msb */
...@@ -172,55 +172,71 @@ static int tmp401_reg_read(struct tmp401_data *data, unsigned int reg) ...@@ -172,55 +172,71 @@ static int tmp401_reg_read(struct tmp401_data *data, unsigned int reg)
/* work around register overlap between TMP411 and TMP432 */ /* work around register overlap between TMP411 and TMP432 */
if (reg == 0xf6) if (reg == 0xf6)
reg = 0x36; 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 0x19: /* critical limits, 8-bit registers */
case 0x1a: case 0x1a:
case 0x20: case 0x20:
regval = i2c_smbus_read_byte_data(client, reg); regval = i2c_smbus_read_byte_data(client, reg);
if (regval < 0) if (regval < 0)
return regval; return regval;
return regval << 8; *val = regval << 8;
break;
case 0x1b: case 0x1b:
case 0x35 ... 0x37: case 0x35 ... 0x37:
if (data->kind == tmp432) if (data->kind == tmp432) {
return i2c_smbus_read_byte_data(client, reg); regval = i2c_smbus_read_byte_data(client, reg);
if (regval < 0)
return regval;
*val = regval;
break;
}
/* simulate TMP432 status registers */ /* simulate TMP432 status registers */
regval = i2c_smbus_read_byte_data(client, TMP401_STATUS); regval = i2c_smbus_read_byte_data(client, TMP401_STATUS);
if (regval < 0) if (regval < 0)
return regval; return regval;
val = 0; *val = 0;
switch (reg) { switch (reg) {
case 0x1b: /* open / fault */ case 0x1b: /* open / fault */
if (regval & TMP401_STATUS_REMOTE_OPEN) if (regval & TMP401_STATUS_REMOTE_OPEN)
val |= BIT(1); *val |= BIT(1);
break; break;
case 0x35: /* high limit */ case 0x35: /* high limit */
if (regval & TMP401_STATUS_LOCAL_HIGH) if (regval & TMP401_STATUS_LOCAL_HIGH)
val |= BIT(0); *val |= BIT(0);
if (regval & TMP401_STATUS_REMOTE_HIGH) if (regval & TMP401_STATUS_REMOTE_HIGH)
val |= BIT(1); *val |= BIT(1);
break; break;
case 0x36: /* low limit */ case 0x36: /* low limit */
if (regval & TMP401_STATUS_LOCAL_LOW) if (regval & TMP401_STATUS_LOCAL_LOW)
val |= BIT(0); *val |= BIT(0);
if (regval & TMP401_STATUS_REMOTE_LOW) if (regval & TMP401_STATUS_REMOTE_LOW)
val |= BIT(1); *val |= BIT(1);
break; break;
case 0x37: /* therm / crit limit */ case 0x37: /* therm / crit limit */
if (regval & TMP401_STATUS_LOCAL_CRIT) if (regval & TMP401_STATUS_LOCAL_CRIT)
val |= BIT(0); *val |= BIT(0);
if (regval & TMP401_STATUS_REMOTE_CRIT) if (regval & TMP401_STATUS_REMOTE_CRIT)
val |= BIT(1); *val |= BIT(1);
break; break;
} }
return val; break;
default: 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; struct i2c_client *client = data->client;
switch (reg) { switch (reg) {
...@@ -240,6 +256,41 @@ static int tmp401_reg_write(struct tmp401_data *data, unsigned int reg, unsigned ...@@ -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[] = { static const u8 tmp401_temp_reg_index[] = {
[hwmon_temp_input] = 0, [hwmon_temp_input] = 0,
[hwmon_temp_min] = 1, [hwmon_temp_min] = 1,
...@@ -259,7 +310,9 @@ static const u8 tmp401_status_reg_index[] = { ...@@ -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) static int tmp401_temp_read(struct device *dev, u32 attr, int channel, long *val)
{ {
struct tmp401_data *data = dev_get_drvdata(dev); struct tmp401_data *data = dev_get_drvdata(dev);
int reg, regval; struct regmap *regmap = data->regmap;
unsigned int regval;
int reg, ret;
switch (attr) { switch (attr) {
case hwmon_temp_input: case hwmon_temp_input:
...@@ -269,36 +322,35 @@ static int tmp401_temp_read(struct device *dev, u32 attr, int channel, long *val ...@@ -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_lowest:
case hwmon_temp_highest: case hwmon_temp_highest:
reg = TMP401_TEMP_MSB_READ[tmp401_temp_reg_index[attr]][channel]; reg = TMP401_TEMP_MSB_READ[tmp401_temp_reg_index[attr]][channel];
regval = tmp401_reg_read(data, reg); ret = regmap_read(regmap, reg, &regval);
if (regval < 0) if (ret < 0)
return regval; return ret;
*val = tmp401_register_to_temp(regval, data->extended_range); *val = tmp401_register_to_temp(regval, data->extended_range);
break; break;
case hwmon_temp_crit_hyst: case hwmon_temp_crit_hyst:
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
reg = TMP401_TEMP_MSB_READ[3][channel]; reg = TMP401_TEMP_MSB_READ[3][channel];
regval = tmp401_reg_read(data, reg); ret = regmap_read(regmap, reg, &regval);
if (regval < 0) if (ret < 0)
goto unlock; goto unlock;
*val = tmp401_register_to_temp(regval, data->extended_range); *val = tmp401_register_to_temp(regval, data->extended_range);
regval = tmp401_reg_read(data, TMP401_TEMP_CRIT_HYST); ret = regmap_read(regmap, TMP401_TEMP_CRIT_HYST, &regval);
if (regval < 0) if (ret < 0)
goto unlock; goto unlock;
*val -= regval * 1000; *val -= regval * 1000;
regval = 0;
unlock: unlock:
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
if (regval < 0) if (ret < 0)
return regval; return ret;
break; break;
case hwmon_temp_fault: case hwmon_temp_fault:
case hwmon_temp_min_alarm: case hwmon_temp_min_alarm:
case hwmon_temp_max_alarm: case hwmon_temp_max_alarm:
case hwmon_temp_crit_alarm: case hwmon_temp_crit_alarm:
reg = TMP432_STATUS_REG[tmp401_status_reg_index[attr]]; reg = TMP432_STATUS_REG[tmp401_status_reg_index[attr]];
regval = tmp401_reg_read(data, reg); ret = regmap_read(regmap, reg, &regval);
if (regval < 0) if (ret < 0)
return regval; return ret;
*val = !!(regval & BIT(channel)); *val = !!(regval & BIT(channel));
break; break;
default: default:
...@@ -311,7 +363,9 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, ...@@ -311,7 +363,9 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel,
long val) long val)
{ {
struct tmp401_data *data = dev_get_drvdata(dev); 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); mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
...@@ -321,7 +375,14 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, ...@@ -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]; reg = TMP401_TEMP_MSB_WRITE[tmp401_temp_reg_index[attr]][channel];
regval = tmp401_temp_to_register(val, data->extended_range, regval = tmp401_temp_to_register(val, data->extended_range,
attr == hwmon_temp_crit ? 8 : 4); 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; break;
case hwmon_temp_crit_hyst: case hwmon_temp_crit_hyst:
if (data->extended_range) if (data->extended_range)
...@@ -330,13 +391,13 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, ...@@ -330,13 +391,13 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel,
val = clamp_val(val, 0, 127000); val = clamp_val(val, 0, 127000);
reg = TMP401_TEMP_MSB_READ[3][channel]; reg = TMP401_TEMP_MSB_READ[3][channel];
ret = tmp401_reg_read(data, reg); ret = regmap_read(regmap, reg, &regval);
if (ret < 0) if (ret < 0)
break; 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); val = clamp_val(val, temp - 255000, temp);
regval = ((temp - val) + 500) / 1000; 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; break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
...@@ -349,13 +410,14 @@ static int tmp401_temp_write(struct device *dev, u32 attr, int channel, ...@@ -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) static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val)
{ {
struct tmp401_data *data = dev_get_drvdata(dev); struct tmp401_data *data = dev_get_drvdata(dev);
int regval; u32 regval;
int ret;
switch (attr) { switch (attr) {
case hwmon_chip_update_interval: case hwmon_chip_update_interval:
regval = tmp401_reg_read(data, TMP401_CONVERSION_RATE_READ); ret = regmap_read(data->regmap, TMP401_CONVERSION_RATE_READ, &regval);
if (regval < 0) if (ret < 0)
return regval; return ret;
*val = (1 << (7 - regval)) * 125; *val = (1 << (7 - regval)) * 125;
break; break;
case hwmon_chip_temp_reset_history: case hwmon_chip_temp_reset_history:
...@@ -368,7 +430,7 @@ static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val ...@@ -368,7 +430,7 @@ static int tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val
return 0; 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; int err, rate;
...@@ -382,22 +444,26 @@ static int tmp401_set_convrate(struct i2c_client *client, struct tmp401_data *da ...@@ -382,22 +444,26 @@ static int tmp401_set_convrate(struct i2c_client *client, struct tmp401_data *da
*/ */
val = clamp_val(val, 125, 16000); val = clamp_val(val, 125, 16000);
rate = 7 - __fls(val * 4 / (125 * 3)); 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) if (err)
return 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) static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val)
{ {
struct tmp401_data *data = dev_get_drvdata(dev); struct tmp401_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client; struct regmap *regmap = data->regmap;
int err; int err;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
switch (attr) { switch (attr) {
case hwmon_chip_update_interval: case hwmon_chip_update_interval:
err = tmp401_set_convrate(client, data, val); err = tmp401_set_convrate(regmap, val);
break; break;
case hwmon_chip_temp_reset_history: case hwmon_chip_temp_reset_history:
if (val != 1) { if (val != 1) {
...@@ -408,7 +474,7 @@ static int tmp401_chip_write(struct device *dev, u32 attr, int channel, long val ...@@ -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 * Reset history by writing any value to any of the
* minimum/maximum registers (0x30-0x37). * minimum/maximum registers (0x30-0x37).
*/ */
err = i2c_smbus_write_byte_data(client, 0x30, 0); err = regmap_write(regmap, 0x30, 0);
break; break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
...@@ -489,18 +555,23 @@ static const struct hwmon_ops tmp401_ops = { ...@@ -489,18 +555,23 @@ static const struct hwmon_ops tmp401_ops = {
.write = tmp401_write, .write = tmp401_write,
}; };
static int tmp401_init_client(struct tmp401_data *data, /* chip initialization, detect, probe */
struct i2c_client *client)
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 */ /* Set conversion rate to 2 Hz */
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); ret = regmap_write(regmap, TMP401_CONVERSION_RATE_WRITE, 5);
if (ret < 0)
return ret;
/* Start conversions (disable shutdown if necessary) */ /* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); ret = regmap_read(regmap, TMP401_CONFIG_READ, &config);
if (config < 0) if (ret < 0)
return config; return ret;
config_orig = config; config_orig = config;
config &= ~TMP401_CONFIG_SHUTDOWN; config &= ~TMP401_CONFIG_SHUTDOWN;
...@@ -508,11 +579,9 @@ static int tmp401_init_client(struct tmp401_data *data, ...@@ -508,11 +579,9 @@ static int tmp401_init_client(struct tmp401_data *data,
data->extended_range = !!(config & TMP401_CONFIG_RANGE); data->extended_range = !!(config & TMP401_CONFIG_RANGE);
if (config != config_orig) if (config != config_orig)
status = i2c_smbus_write_byte_data(client, ret = regmap_write(regmap, TMP401_CONFIG_WRITE, config);
TMP401_CONFIG_WRITE,
config);
return status; return ret;
} }
static int tmp401_detect(struct i2c_client *client, static int tmp401_detect(struct i2c_client *client,
...@@ -603,6 +672,10 @@ static int tmp401_probe(struct i2c_client *client) ...@@ -603,6 +672,10 @@ static int tmp401_probe(struct i2c_client *client)
mutex_init(&data->update_lock); mutex_init(&data->update_lock);
data->kind = i2c_match_id(tmp401_id, client)->driver_data; 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 */ /* initialize configuration data */
data->chip.ops = &tmp401_ops; data->chip.ops = &tmp401_ops;
data->chip.info = data->info; data->chip.info = data->info;
...@@ -640,7 +713,7 @@ static int tmp401_probe(struct i2c_client *client) ...@@ -640,7 +713,7 @@ static int tmp401_probe(struct i2c_client *client)
} }
/* Initialize the TMP401 chip */ /* Initialize the TMP401 chip */
status = tmp401_init_client(data, client); status = tmp401_init_client(data);
if (status < 0) if (status < 0)
return status; return status;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment