hwmon: (max31827) Add custom attribute for resolution

Added custom channel-specific (temp1) attribute for resolution. The wait
time for a conversion in one-shot mode (enable = 0) depends on the
resolution.

When resolution is 12-bit, the conversion time is 140ms, but the minimum
update_interval is 125ms. Handled this problem by waiting an additional
15ms (125ms + 15ms = 140ms).

Added 'mask' parameter to the shutdown_write() function. Now it can
either write or update bits, depending on the value of mask. This is
needed, because for alarms a write is necessary, but for resolution only
the resolution bits should be updated.

Signed-off-by: Daniel Matyas <daniel.matyas@analog.com>
Link: https://lore.kernel.org/r/20231031182158.124608-5-daniel.matyas@analog.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Daniel Matyas 2023-10-31 20:21:57 +02:00 committed by Guenter Roeck
parent 64176bde46
commit 29a9ac6414
2 changed files with 134 additions and 17 deletions

View File

@ -90,11 +90,28 @@ the data sheet are:
Enabling the device when it is already enabled has the side effect of setting
the conversion frequency to 1 conv/s. The conversion time varies depending on
the resolution. The conversion time doubles with every bit of increased
resolution. For 10 bit resolution 35ms are needed, while for 12 bit resolution
(default) 140ms. When chip is in shutdown mode and a read operation is
requested, one-shot is triggered, the device waits for 140 (conversion time) ms,
and only after that is the temperature value register read.
the resolution.
The conversion time doubles with every bit of increased resolution. The
available resolutions are:
- 8 bit -> 8.75 ms conversion time
- 9 bit -> 17.5 ms conversion time
- 10 bit -> 35 ms conversion time
- 12 bit (default) -> 140 ms conversion time
There is a temp1_resolution attribute which indicates the unit change in the
input temperature in milli-degrees C.
- 1000 mC -> 8 bit
- 500 mC -> 9 bit
- 250 mC -> 10 bit
- 62 mC -> 12 bit (default) - actually this is 62.5, but the fil returns 62
When chip is in shutdown mode and a read operation is requested, one-shot is
triggered, the device waits for <conversion time> ms, and only after that is
the temperature value register read. Note that the conversion times are rounded
up to the nearest possible integer.
The LSB of the temperature values is 0.0625 degrees Celsius, but the values of
the temperatures are displayed in milli-degrees. This means, that some data is
@ -117,4 +134,4 @@ corresponding status bits.
Notes
-----
PEC and resolution are not implemented.
PEC is not implemented.

View File

@ -37,6 +37,9 @@
#define MAX31827_FLT_Q_1 0x0
#define MAX31827_FLT_Q_4 0x2
#define MAX31827_8_BIT_CNV_TIME 9
#define MAX31827_9_BIT_CNV_TIME 18
#define MAX31827_10_BIT_CNV_TIME 35
#define MAX31827_12_BIT_CNV_TIME 140
#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16)
@ -65,6 +68,27 @@ static const u16 max31827_conversions[] = {
[MAX31827_CNV_8_HZ] = 125,
};
enum max31827_resolution {
MAX31827_RES_8_BIT = 0,
MAX31827_RES_9_BIT,
MAX31827_RES_10_BIT,
MAX31827_RES_12_BIT,
};
static const u16 max31827_resolutions[] = {
[MAX31827_RES_8_BIT] = 1000,
[MAX31827_RES_9_BIT] = 500,
[MAX31827_RES_10_BIT] = 250,
[MAX31827_RES_12_BIT] = 62,
};
static const u16 max31827_conv_times[] = {
[MAX31827_RES_8_BIT] = MAX31827_8_BIT_CNV_TIME,
[MAX31827_RES_9_BIT] = MAX31827_9_BIT_CNV_TIME,
[MAX31827_RES_10_BIT] = MAX31827_10_BIT_CNV_TIME,
[MAX31827_RES_12_BIT] = MAX31827_12_BIT_CNV_TIME,
};
struct max31827_state {
/*
* Prevent simultaneous access to the i2c client.
@ -72,6 +96,8 @@ struct max31827_state {
struct mutex lock;
struct regmap *regmap;
bool enable;
unsigned int resolution;
unsigned int update_interval;
};
static const struct regmap_config max31827_regmap = {
@ -88,9 +114,9 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg,
int ret;
/*
* Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
* register values are changed over I2C, the part must be in shutdown
* mode.
* Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold
* and Resolution bits from Configuration register are changed over I2C,
* the part must be in shutdown mode.
*
* Mutex is used to ensure, that some other process doesn't change the
* configuration register.
@ -208,9 +234,18 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
mutex_unlock(&st->lock);
return ret;
}
msleep(MAX31827_12_BIT_CNV_TIME);
msleep(max31827_conv_times[st->resolution]);
}
/*
* For 12-bit resolution the conversion time is 140 ms,
* thus an additional 15 ms is needed to complete the
* conversion: 125 ms + 15 ms = 140 ms
*/
if (max31827_resolutions[st->resolution] == 12 &&
st->update_interval == 125)
usleep_range(15000, 20000);
ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
mutex_unlock(&st->lock);
@ -367,10 +402,14 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
res = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
res);
return regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_CNV_RATE_MASK,
res);
ret = regmap_update_bits(st->regmap,
MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_CNV_RATE_MASK,
res);
if (ret)
return ret;
st->update_interval = val;
}
break;
@ -378,9 +417,70 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
return -EOPNOTSUPP;
}
return -EOPNOTSUPP;
return 0;
}
static ssize_t temp1_resolution_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
struct max31827_state *st = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = regmap_read(st->regmap, MAX31827_CONFIGURATION_REG, &val);
if (ret)
return ret;
val = FIELD_GET(MAX31827_CONFIGURATION_RESOLUTION_MASK, val);
return scnprintf(buf, PAGE_SIZE, "%u\n", max31827_resolutions[val]);
}
static ssize_t temp1_resolution_store(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct max31827_state *st = dev_get_drvdata(dev);
unsigned int idx = 0;
unsigned int val;
int ret;
ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
/*
* Convert the desired resolution into register
* bits. idx is already initialized with 0.
*
* This was inspired by lm73 driver.
*/
while (idx < ARRAY_SIZE(max31827_resolutions) &&
val < max31827_resolutions[idx])
idx++;
if (idx == ARRAY_SIZE(max31827_resolutions))
idx = ARRAY_SIZE(max31827_resolutions) - 1;
st->resolution = idx;
ret = shutdown_write(st, MAX31827_CONFIGURATION_REG,
MAX31827_CONFIGURATION_RESOLUTION_MASK,
FIELD_PREP(MAX31827_CONFIGURATION_RESOLUTION_MASK,
idx));
return ret ? ret : count;
}
static DEVICE_ATTR_RW(temp1_resolution);
static struct attribute *max31827_attrs[] = {
&dev_attr_temp1_resolution.attr,
NULL
};
ATTRIBUTE_GROUPS(max31827);
static const struct i2c_device_id max31827_i2c_ids[] = {
{ "max31827", max31827 },
{ "max31828", max31828 },
@ -529,7 +629,7 @@ static int max31827_probe(struct i2c_client *client)
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
&max31827_chip_info,
NULL);
max31827_groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}