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:
parent
64176bde46
commit
29a9ac6414
|
@ -90,11 +90,28 @@ the data sheet are:
|
||||||
|
|
||||||
Enabling the device when it is already enabled has the side effect of setting
|
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 conversion frequency to 1 conv/s. The conversion time varies depending on
|
||||||
the resolution. The conversion time doubles with every bit of increased
|
the resolution.
|
||||||
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
|
The conversion time doubles with every bit of increased resolution. The
|
||||||
requested, one-shot is triggered, the device waits for 140 (conversion time) ms,
|
available resolutions are:
|
||||||
and only after that is the temperature value register read.
|
|
||||||
|
- 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 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
|
the temperatures are displayed in milli-degrees. This means, that some data is
|
||||||
|
@ -117,4 +134,4 @@ corresponding status bits.
|
||||||
Notes
|
Notes
|
||||||
-----
|
-----
|
||||||
|
|
||||||
PEC and resolution are not implemented.
|
PEC is not implemented.
|
||||||
|
|
|
@ -37,6 +37,9 @@
|
||||||
#define MAX31827_FLT_Q_1 0x0
|
#define MAX31827_FLT_Q_1 0x0
|
||||||
#define MAX31827_FLT_Q_4 0x2
|
#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_12_BIT_CNV_TIME 140
|
||||||
|
|
||||||
#define MAX31827_16_BIT_TO_M_DGR(x) (sign_extend32(x, 15) * 1000 / 16)
|
#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,
|
[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 {
|
struct max31827_state {
|
||||||
/*
|
/*
|
||||||
* Prevent simultaneous access to the i2c client.
|
* Prevent simultaneous access to the i2c client.
|
||||||
|
@ -72,6 +96,8 @@ struct max31827_state {
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
bool enable;
|
bool enable;
|
||||||
|
unsigned int resolution;
|
||||||
|
unsigned int update_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct regmap_config max31827_regmap = {
|
static const struct regmap_config max31827_regmap = {
|
||||||
|
@ -88,9 +114,9 @@ static int shutdown_write(struct max31827_state *st, unsigned int reg,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before the Temperature Threshold Alarm and Alarm Hysteresis Threshold
|
* Before the Temperature Threshold Alarm, Alarm Hysteresis Threshold
|
||||||
* register values are changed over I2C, the part must be in shutdown
|
* and Resolution bits from Configuration register are changed over I2C,
|
||||||
* mode.
|
* the part must be in shutdown mode.
|
||||||
*
|
*
|
||||||
* Mutex is used to ensure, that some other process doesn't change the
|
* Mutex is used to ensure, that some other process doesn't change the
|
||||||
* configuration register.
|
* configuration register.
|
||||||
|
@ -208,9 +234,18 @@ static int max31827_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
mutex_unlock(&st->lock);
|
mutex_unlock(&st->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
msleep(max31827_conv_times[st->resolution]);
|
||||||
msleep(MAX31827_12_BIT_CNV_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
ret = regmap_read(st->regmap, MAX31827_T_REG, &uval);
|
||||||
|
|
||||||
mutex_unlock(&st->lock);
|
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 = FIELD_PREP(MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||||
res);
|
res);
|
||||||
|
|
||||||
return regmap_update_bits(st->regmap,
|
ret = regmap_update_bits(st->regmap,
|
||||||
MAX31827_CONFIGURATION_REG,
|
MAX31827_CONFIGURATION_REG,
|
||||||
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
MAX31827_CONFIGURATION_CNV_RATE_MASK,
|
||||||
res);
|
res);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
st->update_interval = val;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -378,9 +417,70 @@ static int max31827_write(struct device *dev, enum hwmon_sensor_types type,
|
||||||
return -EOPNOTSUPP;
|
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[] = {
|
static const struct i2c_device_id max31827_i2c_ids[] = {
|
||||||
{ "max31827", max31827 },
|
{ "max31827", max31827 },
|
||||||
{ "max31828", max31828 },
|
{ "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,
|
hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, st,
|
||||||
&max31827_chip_info,
|
&max31827_chip_info,
|
||||||
NULL);
|
max31827_groups);
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue