hwmon: (nct7802) Add time step attributes for tweaking responsiveness

The nct7802 chip exposes two registers that allow setting the time
interval between successive duty increases or decreases in Smart Fan
mode. The units are intervals of 0.1 second. The default value at power
on is 10, so 1 second.

Add sysfs attributes for step_up_time and step_down_time to allow
controlling the responsiveness of the fan speed. Values are represented
as milliseconds to the user. When set, the value is clamped to the valid
range of 100 to 25500 (0.1 to 25.5 seconds), and rounded to the nearest
multiple of 100.

Signed-off-by: Ronan Dalton <ronan.dalton@alliedtelesis.co.nz>
Cc: linux-kernel@vger.kernel.org
Cc: linux-hwmon@vger.kernel.org
Cc: Guenter Roeck <linux@roeck-us.net>
Cc: Chris Packham <chris.packham@alliedtelesis.co.nz>
Link: https://lore.kernel.org/r/20260514003404.1548747-2-ronan.dalton@alliedtelesis.co.nz
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
Ronan Dalton
2026-05-14 12:34:04 +12:00
committed by Guenter Roeck
parent 4a9e6a9230
commit 1000878867
2 changed files with 107 additions and 0 deletions

View File

@@ -24,6 +24,22 @@ speed sensors.
Smart Fan™ speed control is available via pwmX_auto_point attributes.
Sysfs Attributes
----------------
Sysfs attributes unique to this chip are documented below. For common
attributes, see Documentation/hwmon/sysfs-interface.rst.
step_up_time
Time interval between successive duty cycle increases
when in Smart Fan mode. Specified in milliseconds and
rounded to intervals of 100 in the range 100-25500.
step_down_time
Time interval between successive duty cycle decreases
when in Smart Fan mode. Specified in milliseconds and
rounded to intervals of 100 in the range 100-25500.
Tested Boards and BIOS Versions
-------------------------------

View File

@@ -47,6 +47,8 @@ static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
#define REG_PWM(x) (0x60 + (x))
#define REG_SMARTFAN_EN(x) (0x64 + (x) / 2)
#define SMARTFAN_EN_SHIFT(x) ((x) % 2 * 4)
#define REG_SMARTFAN_STEP_UP_TIME 0x6e
#define REG_SMARTFAN_STEP_DOWN_TIME 0x6f
#define REG_VENDOR_ID 0xfd
#define REG_CHIP_ID 0xfe
#define REG_VERSION_ID 0xff
@@ -560,6 +562,77 @@ beep_store(struct device *dev, struct device_attribute *attr, const char *buf,
return err ? : count;
}
static ssize_t step_time_show(struct device *dev, struct device_attribute *attr,
char *buf, bool step_up)
{
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned int reg, val;
int ret;
if (step_up)
reg = REG_SMARTFAN_STEP_UP_TIME;
else
reg = REG_SMARTFAN_STEP_DOWN_TIME;
ret = regmap_read(data->regmap, reg, &val);
if (ret < 0)
return ret;
return sprintf(buf, "%u\n", val * 100); /* Convert from ds to ms */
}
static ssize_t step_up_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return step_time_show(dev, attr, buf, true);
}
static ssize_t step_down_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return step_time_show(dev, attr, buf, false);
}
static ssize_t step_time_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count, bool step_up)
{
struct nct7802_data *data = dev_get_drvdata(dev);
unsigned long val;
unsigned int reg;
int ret;
ret = kstrtoul(buf, 10, &val);
if (ret < 0)
return ret;
/* Clamp range, and convert from ms to ds */
val = DIV_ROUND_CLOSEST(clamp_val(val, 100, 25500), 100);
if (step_up)
reg = REG_SMARTFAN_STEP_UP_TIME;
else
reg = REG_SMARTFAN_STEP_DOWN_TIME;
ret = regmap_write(data->regmap, reg, val);
return ret ? : count;
}
static ssize_t step_up_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return step_time_store(dev, attr, buf, count, true);
}
static ssize_t step_down_time_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return step_time_store(dev, attr, buf, count, false);
}
static SENSOR_DEVICE_ATTR_RW(temp1_type, temp_type, 0);
static SENSOR_DEVICE_ATTR_2_RO(temp1_input, temp, 0x01, REG_TEMP_LSB);
static SENSOR_DEVICE_ATTR_2_RW(temp1_min, temp, 0x31, 0);
@@ -975,12 +1048,30 @@ static const struct attribute_group nct7802_auto_point_group = {
.attrs = nct7802_auto_point_attrs,
};
/* 7.2.102 0x6E FANCTL Step Up Time Register */
static SENSOR_DEVICE_ATTR_RW(step_up_time, step_up_time, 0);
/* 7.2.103 0x6F FANCTL Step Down Time Register */
static SENSOR_DEVICE_ATTR_RW(step_down_time, step_down_time, 0);
static struct attribute *nct7802_step_time_attrs[] = {
&sensor_dev_attr_step_up_time.dev_attr.attr,
&sensor_dev_attr_step_down_time.dev_attr.attr,
NULL
};
static const struct attribute_group nct7802_step_time_group = {
.attrs = nct7802_step_time_attrs,
};
static const struct attribute_group *nct7802_groups[] = {
&nct7802_temp_group,
&nct7802_in_group,
&nct7802_fan_group,
&nct7802_pwm_group,
&nct7802_auto_point_group,
&nct7802_step_time_group,
NULL
};