diff options
author | Zhikui Ren <zhikui.ren@intel.com> | 2022-01-21 04:26:31 +0300 |
---|---|---|
committer | Zhikui Ren <zhikui.ren@intel.com> | 2022-03-10 01:11:54 +0300 |
commit | f99c8aa5142aaa83cb19aaacf2166dafbb3828aa (patch) | |
tree | 78e42bbe8dc792c1e3087a032a2997c43b171cb7 /drivers/hwmon | |
parent | 4e36b22c7f85525a2fd7a4afecc12f7d3c84de04 (diff) | |
download | linux-f99c8aa5142aaa83cb19aaacf2166dafbb3828aa.tar.xz |
hwmon: (pmbus) auto detect pmbus fan pwm mode
PMBus device with fan controls have two possible control modes RPM and
PWM. RPM mode is assumed and FANx_TARGET sensor is always created to
provide read and write access of fan speed control. PWM only devices have
been able to use the FANx_TARGET sensor to read commanded fan speed
correctly because the pmbus core driver caches the write value and return
it when the TARGET sensor is read.
Recent pmbus_core driver change clears the cached value once the write to
FANx_TARGET completes. Read FANx_TARGET sensor now reads from actual PMBus
register. As a result, RPM mode only device, FANx_TARGET sensor always
read 0.
Add detection of current fan control mode during pmbus_identify and set
flag PMBUS_HAVE_PWM12 and/or PMBUS_HAVE_PWM34 if PWM mode is detected.
PWMx and PWMx_ENABLE sensors will be created based on these flags.
Fixes: 1ae5aaf5d1c5 ("hwmon: (pmbus) Clear sensor data after chip write"
Signed-off-by: Zhikui Ren <zhikui.ren@intel.com>
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.c | 8 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 58 |
2 files changed, 64 insertions, 2 deletions
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index d0d386990af5..ce2f020f09d7 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -29,6 +29,7 @@ static void pmbus_find_sensor_groups(struct i2c_client *client, struct pmbus_driver_info *info) { int page; + int fan_mode; /* Sensors detected on page 0 only */ if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN)) @@ -47,13 +48,20 @@ static void pmbus_find_sensor_groups(struct i2c_client *client, info->func[0] |= PMBUS_HAVE_FAN12; if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) info->func[0] |= PMBUS_HAVE_STATUS_FAN12; + fan_mode = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_12); + if ((fan_mode & (PB_FAN_1_RPM | PB_FAN_2_RPM)) != (PB_FAN_1_RPM | PB_FAN_2_RPM)) + info->func[0] |= PMBUS_HAVE_PWM12; } if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { info->func[0] |= PMBUS_HAVE_FAN34; if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) info->func[0] |= PMBUS_HAVE_STATUS_FAN34; + fan_mode = pmbus_read_byte_data(client, page, PMBUS_FAN_CONFIG_34); + if ((fan_mode & (PB_FAN_1_RPM | PB_FAN_2_RPM)) != (PB_FAN_1_RPM | PB_FAN_2_RPM)) + info->func[0] |= PMBUS_HAVE_PWM34; } + if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) info->func[0] |= PMBUS_HAVE_TEMP; if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ec44e4847c48..ceb1b4db985e 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -241,12 +241,32 @@ int pmbus_write_word_data(struct i2c_client *client, int page, u8 reg, } EXPORT_SYMBOL_NS_GPL(pmbus_write_word_data, PMBUS); +static int pmbus_update_fan_config(struct i2c_client *client, int page, int id, + u8 config, u8 mask) +{ + int from; + int rv; + u8 to; + + from = pmbus_read_byte_data(client, page, pmbus_fan_config_registers[id]); + if (from < 0) + return from; + + to = (from & ~mask) | (config & mask); + if (to != from) { + rv = pmbus_write_byte_data(client, page, pmbus_fan_config_registers[id], to); + if (rv < 0) + return rv; + } + return 0; +} static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, u16 word) { int bit; int id; + int config; int rv; switch (reg) { @@ -255,6 +275,18 @@ static int pmbus_write_virt_reg(struct i2c_client *client, int page, int reg, bit = pmbus_fan_rpm_mask[id]; rv = pmbus_update_fan(client, page, id, bit, bit, word); break; + case PMBUS_VIRT_PWM_1 ... PMBUS_VIRT_PWM_4: + id = reg - PMBUS_VIRT_PWM_1; + bit = pmbus_fan_rpm_mask[id]; + /* 0 is pwm mode */ + rv = pmbus_update_fan(client, page, id, 0, bit, word); + break; + case PMBUS_VIRT_PWM_ENABLE_1 ... PMBUS_VIRT_PWM_ENABLE_4: + id = reg - PMBUS_VIRT_PWM_ENABLE_1; + bit = pmbus_fan_rpm_mask[id]; + config = word ? bit : 0; + rv = pmbus_update_fan_config(client, page, id, config, bit); + break; default: rv = -ENXIO; break; @@ -293,8 +325,7 @@ int pmbus_update_fan(struct i2c_client *client, int page, int id, int rv; u8 to; - from = pmbus_read_byte_data(client, page, - pmbus_fan_config_registers[id]); + from = pmbus_read_byte_data(client, page, pmbus_fan_config_registers[id]); if (from < 0) return from; @@ -323,16 +354,39 @@ int pmbus_read_word_data(struct i2c_client *client, int page, int phase, u8 reg) } EXPORT_SYMBOL_NS_GPL(pmbus_read_word_data, PMBUS); +static int pmbus_get_fan_config(struct i2c_client *client, int page, int id, u8 mask) +{ + int from; + + from = pmbus_read_byte_data(client, page, pmbus_fan_config_registers[id]); + if (from < 0) + return from; + + return from & mask; +} + static int pmbus_read_virt_reg(struct i2c_client *client, int page, int reg) { int rv; int id; + int bit; switch (reg) { case PMBUS_VIRT_FAN_TARGET_1 ... PMBUS_VIRT_FAN_TARGET_4: id = reg - PMBUS_VIRT_FAN_TARGET_1; rv = pmbus_get_fan_rate_device(client, page, id, rpm); break; + case PMBUS_VIRT_PWM_1 ... PMBUS_VIRT_PWM_4: + id = reg - PMBUS_VIRT_PWM_1; + rv = pmbus_get_fan_rate_device(client, page, id, percent); + break; + case PMBUS_VIRT_PWM_ENABLE_1 ... PMBUS_VIRT_PWM_ENABLE_4: + id = reg - PMBUS_VIRT_PWM_ENABLE_1; + bit = pmbus_fan_rpm_mask[id]; + rv = pmbus_get_fan_config(client, page, id, bit); + if (rv >= 0) + rv = !rv; /* PWM is enabled when rpm bit is not set (rv = 0) */ + break; default: rv = -ENXIO; break; |