hwmon: (sch5627) Add pwmX_auto_channels_temp support
After doing some research, it seems that Fujitsu's hardware monitoring solution exports data describing which temperature sensors affect which fans, similar to the data in fan_source of the ftsteutates driver. Writing 0 into these registers forces the fans to full speed. Export this data with standard attributes. Signed-off-by: Armin Wolf <W_Armin@gmx.de> Link: https://lore.kernel.org/r/20220224061210.16452-3-W_Armin@gmx.de Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
e75d16e584
commit
aa9f833dfc
2 changed files with 65 additions and 0 deletions
|
@ -20,6 +20,10 @@ Description
|
||||||
SMSC SCH5627 Super I/O chips include complete hardware monitoring
|
SMSC SCH5627 Super I/O chips include complete hardware monitoring
|
||||||
capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
|
capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures.
|
||||||
|
|
||||||
|
In addition, the SCH5627 exports data describing which temperature sensors
|
||||||
|
affect the speed of each fan. Setting pwmX_auto_channels_temp to 0 forces
|
||||||
|
the corresponding fan to full speed until another value is written.
|
||||||
|
|
||||||
The SMSC SCH5627 hardware monitoring part also contains an integrated
|
The SMSC SCH5627 hardware monitoring part also contains an integrated
|
||||||
watchdog. In order for this watchdog to function some motherboard specific
|
watchdog. In order for this watchdog to function some motherboard specific
|
||||||
initialization most be done by the BIOS, so if the watchdog is not enabled
|
initialization most be done by the BIOS, so if the watchdog is not enabled
|
||||||
|
|
|
@ -52,6 +52,9 @@ static const u16 SCH5627_REG_FAN[SCH5627_NO_FANS] = {
|
||||||
static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
|
static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = {
|
||||||
0x62, 0x64, 0x66, 0x68 };
|
0x62, 0x64, 0x66, 0x68 };
|
||||||
|
|
||||||
|
static const u16 SCH5627_REG_PWM_MAP[SCH5627_NO_FANS] = {
|
||||||
|
0xA0, 0xA1, 0xA2, 0xA3 };
|
||||||
|
|
||||||
static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
|
static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = {
|
||||||
0x22, 0x23, 0x24, 0x25, 0x189 };
|
0x22, 0x23, 0x24, 0x25, 0x189 };
|
||||||
static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
|
static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = {
|
||||||
|
@ -223,6 +226,9 @@ static int reg_to_rpm(u16 reg)
|
||||||
static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
|
static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
|
||||||
int channel)
|
int channel)
|
||||||
{
|
{
|
||||||
|
if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp)
|
||||||
|
return 0644;
|
||||||
|
|
||||||
return 0444;
|
return 0444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +284,23 @@ static int sch5627_read(struct device *dev, enum hwmon_sensor_types type, u32 at
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case hwmon_pwm:
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_pwm_auto_channels_temp:
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case hwmon_in:
|
case hwmon_in:
|
||||||
ret = sch5627_update_in(data);
|
ret = sch5627_update_in(data);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -318,10 +341,42 @@ static int sch5627_read_string(struct device *dev, enum hwmon_sensor_types type,
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel,
|
||||||
|
long val)
|
||||||
|
{
|
||||||
|
struct sch5627_data *data = dev_get_drvdata(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case hwmon_pwm:
|
||||||
|
switch (attr) {
|
||||||
|
case hwmon_pwm_auto_channels_temp:
|
||||||
|
/* registers are 8 bit wide */
|
||||||
|
if (val > U8_MAX || val < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel],
|
||||||
|
val);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct hwmon_ops sch5627_ops = {
|
static const struct hwmon_ops sch5627_ops = {
|
||||||
.is_visible = sch5627_is_visible,
|
.is_visible = sch5627_is_visible,
|
||||||
.read = sch5627_read,
|
.read = sch5627_read,
|
||||||
.read_string = sch5627_read_string,
|
.read_string = sch5627_read_string,
|
||||||
|
.write = sch5627_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct hwmon_channel_info *sch5627_info[] = {
|
static const struct hwmon_channel_info *sch5627_info[] = {
|
||||||
|
@ -342,6 +397,12 @@ static const struct hwmon_channel_info *sch5627_info[] = {
|
||||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
|
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT,
|
||||||
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT
|
HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT
|
||||||
),
|
),
|
||||||
|
HWMON_CHANNEL_INFO(pwm,
|
||||||
|
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||||
|
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||||
|
HWMON_PWM_AUTO_CHANNELS_TEMP,
|
||||||
|
HWMON_PWM_AUTO_CHANNELS_TEMP
|
||||||
|
),
|
||||||
HWMON_CHANNEL_INFO(in,
|
HWMON_CHANNEL_INFO(in,
|
||||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||||
HWMON_I_INPUT | HWMON_I_LABEL,
|
HWMON_I_INPUT | HWMON_I_LABEL,
|
||||||
|
|
Loading…
Add table
Reference in a new issue