Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Armin Wolf and committed by
Guenter Roeck
aa9f833d e75d16e5

+65
+4
Documentation/hwmon/sch5627.rst
··· 20 20 SMSC SCH5627 Super I/O chips include complete hardware monitoring 21 21 capabilities. They can monitor up to 5 voltages, 4 fans and 8 temperatures. 22 22 23 + In addition, the SCH5627 exports data describing which temperature sensors 24 + affect the speed of each fan. Setting pwmX_auto_channels_temp to 0 forces 25 + the corresponding fan to full speed until another value is written. 26 + 23 27 The SMSC SCH5627 hardware monitoring part also contains an integrated 24 28 watchdog. In order for this watchdog to function some motherboard specific 25 29 initialization most be done by the BIOS, so if the watchdog is not enabled
+61
drivers/hwmon/sch5627.c
··· 52 52 static const u16 SCH5627_REG_FAN_MIN[SCH5627_NO_FANS] = { 53 53 0x62, 0x64, 0x66, 0x68 }; 54 54 55 + static const u16 SCH5627_REG_PWM_MAP[SCH5627_NO_FANS] = { 56 + 0xA0, 0xA1, 0xA2, 0xA3 }; 57 + 55 58 static const u16 SCH5627_REG_IN_MSB[SCH5627_NO_IN] = { 56 59 0x22, 0x23, 0x24, 0x25, 0x189 }; 57 60 static const u16 SCH5627_REG_IN_LSN[SCH5627_NO_IN] = { ··· 226 223 static umode_t sch5627_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr, 227 224 int channel) 228 225 { 226 + if (type == hwmon_pwm && attr == hwmon_pwm_auto_channels_temp) 227 + return 0644; 228 + 229 229 return 0444; 230 230 } 231 231 ··· 284 278 break; 285 279 } 286 280 break; 281 + case hwmon_pwm: 282 + switch (attr) { 283 + case hwmon_pwm_auto_channels_temp: 284 + mutex_lock(&data->update_lock); 285 + ret = sch56xx_read_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel]); 286 + mutex_unlock(&data->update_lock); 287 + 288 + if (ret < 0) 289 + return ret; 290 + 291 + *val = ret; 292 + 293 + return 0; 294 + default: 295 + break; 296 + } 297 + break; 287 298 case hwmon_in: 288 299 ret = sch5627_update_in(data); 289 300 if (ret < 0) ··· 341 318 return -EOPNOTSUPP; 342 319 } 343 320 321 + static int sch5627_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, 322 + long val) 323 + { 324 + struct sch5627_data *data = dev_get_drvdata(dev); 325 + int ret; 326 + 327 + switch (type) { 328 + case hwmon_pwm: 329 + switch (attr) { 330 + case hwmon_pwm_auto_channels_temp: 331 + /* registers are 8 bit wide */ 332 + if (val > U8_MAX || val < 0) 333 + return -EINVAL; 334 + 335 + mutex_lock(&data->update_lock); 336 + ret = sch56xx_write_virtual_reg(data->addr, SCH5627_REG_PWM_MAP[channel], 337 + val); 338 + mutex_unlock(&data->update_lock); 339 + 340 + return ret; 341 + default: 342 + break; 343 + } 344 + break; 345 + default: 346 + break; 347 + } 348 + 349 + return -EOPNOTSUPP; 350 + } 351 + 344 352 static const struct hwmon_ops sch5627_ops = { 345 353 .is_visible = sch5627_is_visible, 346 354 .read = sch5627_read, 347 355 .read_string = sch5627_read_string, 356 + .write = sch5627_write, 348 357 }; 349 358 350 359 static const struct hwmon_channel_info *sch5627_info[] = { ··· 396 341 HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT, 397 342 HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT, 398 343 HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_FAULT 344 + ), 345 + HWMON_CHANNEL_INFO(pwm, 346 + HWMON_PWM_AUTO_CHANNELS_TEMP, 347 + HWMON_PWM_AUTO_CHANNELS_TEMP, 348 + HWMON_PWM_AUTO_CHANNELS_TEMP, 349 + HWMON_PWM_AUTO_CHANNELS_TEMP 399 350 ), 400 351 HWMON_CHANNEL_INFO(in, 401 352 HWMON_I_INPUT | HWMON_I_LABEL,