Skip to content

Commit

Permalink
hwmon: (max31827) Add custom attribute for resolution
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Daniel Matyas authored and Guenter Roeck committed Dec 11, 2023
1 parent 64176bd commit 29a9ac6
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 17 deletions.
29 changes: 23 additions & 6 deletions Documentation/hwmon/max31827.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -117,4 +134,4 @@ corresponding status bits.
Notes
-----

PEC and resolution are not implemented.
PEC is not implemented.
122 changes: 111 additions & 11 deletions drivers/hwmon/max31827.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -65,13 +68,36 @@ 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.
*/
struct mutex lock;
struct regmap *regmap;
bool enable;
unsigned int resolution;
unsigned int update_interval;
};

static const struct regmap_config max31827_regmap = {
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -367,20 +402,85 @@ 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;

default:
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 },
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 29a9ac6

Please sign in to comment.