mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-21 22:47:51 -04:00
hwmon: (ina238) Add update_interval_us attribute
The INA238 family supports eight conversion time steps from 50 us to 4120 us (SQ52206: 66 us to 8230 us). At the millisecond granularity of update_interval, the four shortest steps (50, 84, 150, 280 us) all round to the same value and cannot be individually selected. Add support for the generic update_interval_us attribute, which reports and programs the same ADC cycle time as update_interval but in microseconds, giving userspace full access to all conversion time steps. Both attributes reflect the total cycle time including the active averaging count: the reported value is the raw conversion time multiplied by the number of averaged samples, and writes apply the inverse mapping. Signed-off-by: Ferdinand Schwenk <ferdinand.schwenk@advastore.com> Link: https://lore.kernel.org/r/20260609-hwmon-ina238-update-interval-us-v2-v3-3-016b55567950@advastore.com [groeck: Fixed some multi-line alignment issues] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
committed by
Guenter Roeck
parent
8250814145
commit
b47f4a72c6
@@ -106,4 +106,8 @@ energy1_input Energy measurement (uJ)
|
||||
temp1_input Die temperature measurement (mC)
|
||||
temp1_max Maximum die temperature threshold (mC)
|
||||
temp1_max_alarm Maximum die temperature alarm
|
||||
|
||||
samples ADC averaging count (1, 4, 16, 64, 128, 256, 512, 1024)
|
||||
update_interval Total ADC conversion cycle time including averaging (ms)
|
||||
update_interval_us Total ADC conversion cycle time including averaging (us)
|
||||
======================= =======================================================
|
||||
|
||||
@@ -316,21 +316,38 @@ static inline u32 ina238_samples(struct ina238_data *data)
|
||||
INA238_ADC_CONFIG_AVG_SHIFT];
|
||||
}
|
||||
|
||||
/* Converting update_interval in msec to a single conversion time in usec */
|
||||
static inline u32 ina238_interval_ms_to_conv_time(long interval, u32 samples)
|
||||
/* Converting update_interval(_us) to a per-field conversion time in usec.
|
||||
* interval_us is the total ADC cycle time including averaging in microseconds.
|
||||
* All three conversion fields (VBUSCT, VSHCT, VTCT) are set equal, so the
|
||||
* per-field time is interval_us / (samples * 3).
|
||||
*/
|
||||
static inline u32 ina238_interval_us_to_conv_time(u32 interval_us, u32 samples)
|
||||
{
|
||||
u64 interval_us;
|
||||
|
||||
interval = clamp_val(interval, 0, INT_MAX / 1000);
|
||||
interval_us = (u64)interval * 1000;
|
||||
|
||||
/*
|
||||
* update_interval reports the ADC cycle time including averaging.
|
||||
* The target per-field conversion time is interval_us / (samples * 3).
|
||||
*/
|
||||
return DIV_ROUND_CLOSEST_ULL(interval_us, samples * 3);
|
||||
}
|
||||
|
||||
/* Write a per-field conversion time (in usec) to the ADC_CONFIG register */
|
||||
static int ina238_write_conv_time(struct ina238_data *data, u32 conv_time_us)
|
||||
{
|
||||
u16 adc_config;
|
||||
int idx, ret;
|
||||
|
||||
idx = find_closest(conv_time_us, data->config->conv_time,
|
||||
ARRAY_SIZE(ina238_conv_time));
|
||||
adc_config = (data->adc_config &
|
||||
~(INA238_ADC_CONFIG_VBUSCT_MASK |
|
||||
INA238_ADC_CONFIG_VSHCT_MASK |
|
||||
INA238_ADC_CONFIG_VTCT_MASK)) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VBUSCT_SHIFT) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VSHCT_SHIFT) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VTCT_SHIFT);
|
||||
ret = regmap_write(data->regmap, INA238_ADC_CONFIG, adc_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->adc_config = adc_config;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ina238_read_chip(struct device *dev, u32 attr, long *val)
|
||||
{
|
||||
struct ina238_data *data = dev_get_drvdata(dev);
|
||||
@@ -344,6 +361,10 @@ static int ina238_read_chip(struct device *dev, u32 attr, long *val)
|
||||
*val = DIV_ROUND_CLOSEST(ina238_reg_to_interval_us(data) *
|
||||
ina238_samples(data), 1000);
|
||||
return 0;
|
||||
case hwmon_chip_update_interval_us:
|
||||
/* Return in usec */
|
||||
*val = ina238_reg_to_interval_us(data) * ina238_samples(data);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -367,21 +388,14 @@ static int ina238_write_chip(struct device *dev, u32 attr, long val)
|
||||
data->adc_config = adc_config;
|
||||
return 0;
|
||||
case hwmon_chip_update_interval:
|
||||
val = ina238_interval_ms_to_conv_time(val, ina238_samples(data));
|
||||
idx = find_closest(val, data->config->conv_time,
|
||||
ARRAY_SIZE(ina238_conv_time));
|
||||
adc_config = (data->adc_config &
|
||||
~(INA238_ADC_CONFIG_VBUSCT_MASK |
|
||||
INA238_ADC_CONFIG_VSHCT_MASK |
|
||||
INA238_ADC_CONFIG_VTCT_MASK)) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VBUSCT_SHIFT) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VSHCT_SHIFT) |
|
||||
((u16)idx << INA238_ADC_CONFIG_VTCT_SHIFT);
|
||||
ret = regmap_write(data->regmap, INA238_ADC_CONFIG, adc_config);
|
||||
if (ret)
|
||||
return ret;
|
||||
data->adc_config = adc_config;
|
||||
return 0;
|
||||
/* Convert ms to us before passing to the shared helper */
|
||||
val = clamp_val(val, 0, INT_MAX / 1000) * 1000;
|
||||
return ina238_write_conv_time(data,
|
||||
ina238_interval_us_to_conv_time((u32)val, ina238_samples(data)));
|
||||
case hwmon_chip_update_interval_us:
|
||||
val = clamp_val(val, 0, INT_MAX);
|
||||
return ina238_write_conv_time(data,
|
||||
ina238_interval_us_to_conv_time((u32)val, ina238_samples(data)));
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -763,6 +777,7 @@ static umode_t ina238_is_visible(const void *drvdata,
|
||||
switch (attr) {
|
||||
case hwmon_chip_samples:
|
||||
case hwmon_chip_update_interval:
|
||||
case hwmon_chip_update_interval_us:
|
||||
return 0644;
|
||||
default:
|
||||
return 0;
|
||||
@@ -831,7 +846,8 @@ static umode_t ina238_is_visible(const void *drvdata,
|
||||
|
||||
static const struct hwmon_channel_info * const ina238_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_SAMPLES | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_C_SAMPLES | HWMON_C_UPDATE_INTERVAL |
|
||||
HWMON_C_UPDATE_INTERVAL_US),
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
/* 0: shunt voltage */
|
||||
INA238_HWMON_IN_CONFIG,
|
||||
|
||||
Reference in New Issue
Block a user