diff options
author | Nicolin Chen <nicoleotsuka@gmail.com> | 2019-04-17 16:12:10 -0700 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2019-04-18 06:44:11 -0700 |
commit | 023912dbb80f5faf7a028aad6562774472d82a5a (patch) | |
tree | 906ecb878ef4645ad71f1b33f84ed46e2514d2bf /drivers/hwmon | |
parent | 521c0b6116ef60e4b96ba42dbf285b2ad69071d4 (diff) |
hwmon: (ina3221) Add voltage conversion time settings
The CONFIG register has two 3-bit fields for conversion time
settings of Bus-voltage and Shunt-voltage, respectively. The
conversion settings, along with averaging mode, allow users
to optimize available timing requirement.
This patch adds an 'update_interval' sysfs node through the
hwmon_chip_info of hwmon core. It reflects a total hardware
conversion time:
samples * channels * (Bus + Shunt conversion times)
Though INA3221 supports different conversion time setups for
Bus and Shunt voltages, this patch only adds the support of
a unified setting for both conversion times, by dividing the
conversion time into two equal values.
Signed-off-by: Nicolin Chen <nicoleotsuka@gmail.com>
[groeck: .rst related formatting changes in documentation]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/ina3221.c | 58 |
1 files changed, 50 insertions, 8 deletions
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c index 62040aac653c..e0637fed9585 100644 --- a/drivers/hwmon/ina3221.c +++ b/drivers/hwmon/ina3221.c @@ -144,19 +144,37 @@ static const int ina3221_avg_samples[] = { 1, 4, 16, 64, 128, 256, 512, 1024, }; -static inline int ina3221_wait_for_data(struct ina3221_data *ina) +/* Converting update_interval in msec to conversion time in usec */ +static inline u32 ina3221_interval_ms_to_conv_time(u16 config, int interval) +{ + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 samples_idx = INA3221_CONFIG_AVG(config); + u32 samples = ina3221_avg_samples[samples_idx]; + + /* Bisect the result to Bus and Shunt conversion times */ + return DIV_ROUND_CLOSEST(interval * 1000 / 2, channels * samples); +} + +/* Converting CONFIG register value to update_interval in usec */ +static inline u32 ina3221_reg_to_interval_us(u16 config) { - u32 channels = hweight16(ina->reg_config & INA3221_CONFIG_CHs_EN_MASK); - u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(ina->reg_config); - u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(ina->reg_config); - u32 samples_idx = INA3221_CONFIG_AVG(ina->reg_config); + u32 channels = hweight16(config & INA3221_CONFIG_CHs_EN_MASK); + u32 vbus_ct_idx = INA3221_CONFIG_VBUS_CT(config); + u32 vsh_ct_idx = INA3221_CONFIG_VSH_CT(config); + u32 samples_idx = INA3221_CONFIG_AVG(config); u32 samples = ina3221_avg_samples[samples_idx]; u32 vbus_ct = ina3221_conv_time[vbus_ct_idx]; u32 vsh_ct = ina3221_conv_time[vsh_ct_idx]; - u32 wait, cvrf; /* Calculate total conversion time */ - wait = channels * (vbus_ct + vsh_ct) * samples; + return channels * (vbus_ct + vsh_ct) * samples; +} + +static inline int ina3221_wait_for_data(struct ina3221_data *ina) +{ + u32 wait, cvrf; + + wait = ina3221_reg_to_interval_us(ina->reg_config); /* Polling the CVRF bit to make sure read data is ready */ return regmap_field_read_poll_timeout(ina->fields[F_CVRF], @@ -197,6 +215,11 @@ static int ina3221_read_chip(struct device *dev, u32 attr, long *val) regval = INA3221_CONFIG_AVG(ina->reg_config); *val = ina3221_avg_samples[regval]; return 0; + case hwmon_chip_update_interval: + /* Return in msec */ + *val = ina3221_reg_to_interval_us(ina->reg_config); + *val = DIV_ROUND_CLOSEST(*val, 1000); + return 0; default: return -EOPNOTSUPP; } @@ -325,6 +348,23 @@ static int ina3221_write_chip(struct device *dev, u32 attr, long val) /* Update reg_config accordingly */ ina->reg_config = tmp; return 0; + case hwmon_chip_update_interval: + tmp = ina3221_interval_ms_to_conv_time(ina->reg_config, val); + idx = find_closest(tmp, ina3221_conv_time, + ARRAY_SIZE(ina3221_conv_time)); + + /* Update Bus and Shunt voltage conversion times */ + tmp = INA3221_CONFIG_VBUS_CT_MASK | INA3221_CONFIG_VSH_CT_MASK; + tmp = (ina->reg_config & ~tmp) | + (idx << INA3221_CONFIG_VBUS_CT_SHIFT) | + (idx << INA3221_CONFIG_VSH_CT_SHIFT); + ret = regmap_write(ina->regmap, INA3221_CONFIG, tmp); + if (ret) + return ret; + + /* Update reg_config accordingly */ + ina->reg_config = tmp; + return 0; default: return -EOPNOTSUPP; } @@ -483,6 +523,7 @@ static umode_t ina3221_is_visible(const void *drvdata, case hwmon_chip: switch (attr) { case hwmon_chip_samples: + case hwmon_chip_update_interval: return 0644; default: return 0; @@ -528,7 +569,8 @@ static umode_t ina3221_is_visible(const void *drvdata, static const struct hwmon_channel_info *ina3221_info[] = { HWMON_CHANNEL_INFO(chip, - HWMON_C_SAMPLES), + HWMON_C_SAMPLES, + HWMON_C_UPDATE_INTERVAL), HWMON_CHANNEL_INFO(in, /* 0: dummy, skipped in is_visible */ HWMON_I_INPUT, |