[PATCH] hwmon: (max31790) Add support for fanX_div

From: Václav Kubernát
Date: Thu Jun 03 2021 - 09:14:42 EST


Right now, the divisor (which determines the speed range) can be only
set by setting fanX_min or fanX_target. This is fine for RPM mode, but
in other cases, it might not be enough. This patch makes it possible to
set the divisor independently.

Signed-off-by: Václav Kubernát <kubernat@xxxxxxxxx>
---
Documentation/hwmon/max31790.rst | 4 ++
drivers/hwmon/max31790.c | 68 ++++++++++++++++++++++++++------
2 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst
index 9225c2a78b68..818e4fe8c797 100644
--- a/Documentation/hwmon/max31790.rst
+++ b/Documentation/hwmon/max31790.rst
@@ -50,6 +50,10 @@ fan[1-12]_min RW minimum fan speed in RPM. Equivalent to target fan speed
and the chip will report a fault condition if the fan
speed is below the target fan speed.
fan[1-6]_target RW desired fan speed in RPM
+fan[1-12]_div RW fan speed range
+ The value is RO for companion channels (7-12). For those
+ channels, the value matches the value of the primary channel.
+ Setting fanX_target or fanX_min also sets this value.
pwm[1-6]_enable RW regulator mode, 0=disabled (duty cycle=0%), 1=manual mode, 2=rpm mode
pwm[1-6] RW read: current pwm duty cycle,
write: target pwm duty cycle (0-255)
diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c
index 39a4ece4276a..f6c38094c19c 100644
--- a/drivers/hwmon/max31790.c
+++ b/drivers/hwmon/max31790.c
@@ -160,6 +160,26 @@ static u8 bits_for_tach_period(int rpm)
return bits;
}

+static int bits_for_speed_range(long speed_range)
+{
+ switch (speed_range) {
+ case 1:
+ return 0x0;
+ case 2:
+ return 0x1;
+ case 4:
+ return 0x2;
+ case 8:
+ return 0x3;
+ case 16:
+ return 0x4;
+ case 32:
+ return 0x5;
+ default:
+ return -1;
+ }
+}
+
static int max31790_read_fan(struct device *dev, u32 attr, int channel,
long *val)
{
@@ -173,6 +193,9 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
case hwmon_fan_enable:
*val = !!(data->fan_config[channel % NR_CHANNEL] & MAX31790_FAN_CFG_TACH_INPUT_EN);
return 0;
+ case hwmon_fan_div:
+ *val = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
+ return 0;
case hwmon_fan_input:
sr = get_tach_period(data->fan_dynamics[channel % NR_CHANNEL]);
if (data->tach[channel] == FAN_COUNT_REG_MAX)
@@ -293,6 +316,20 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
MAX31790_REG_TARGET_COUNT(channel),
data->target_count[channel]);
break;
+ case hwmon_fan_div:
+ sr = bits_for_speed_range(val);
+ if (sr < 0) {
+ err = -EINVAL;
+ break;
+ }
+
+ data->fan_dynamics[channel] = ((data->fan_dynamics[channel] &
+ ~MAX31790_FAN_DYN_SR_MASK) |
+ (sr << MAX31790_FAN_DYN_SR_SHIFT));
+ err = i2c_smbus_write_byte_data(client,
+ MAX31790_REG_FAN_DYNAMICS(channel),
+ data->fan_dynamics[channel]);
+ break;
default:
err = -EOPNOTSUPP;
break;
@@ -311,6 +348,7 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel)
switch (attr) {
case hwmon_fan_min:
case hwmon_fan_enable:
+ case hwmon_fan_div:
if (channel < NR_CHANNEL)
return 0644;
if (fan_config & MAX31790_FAN_CFG_TACH_INPUT)
@@ -481,23 +519,29 @@ static umode_t max31790_is_visible(const void *data,
static const struct hwmon_channel_info *max31790_info[] = {
HWMON_CHANNEL_INFO(fan,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
+ HWMON_F_FAULT | HWMON_F_DIV,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
+ HWMON_F_FAULT | HWMON_F_DIV,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
+ HWMON_F_FAULT | HWMON_F_DIV,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
+ HWMON_F_FAULT | HWMON_F_DIV,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
+ HWMON_F_FAULT | HWMON_F_DIV,
HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_TARGET |
- HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
- HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT),
+ HWMON_F_FAULT | HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV,
+ HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT |
+ HWMON_F_DIV),
HWMON_CHANNEL_INFO(pwm,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
--
2.31.1