From: Guenter Roeck <linux@roeck-us.net>
To: "Václav Kubernát" <kubernat@cesnet.cz>
Cc: Jean Delvare <jdelvare@suse.com>,
Jonathan Corbet <corbet@lwn.net>,
linux-hwmon@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v5 2/5] hwmon: (max31790) Fix and split pwm*_enable
Date: Tue, 18 May 2021 14:16:09 -0700 [thread overview]
Message-ID: <20210518211609.GA3532746@roeck-us.net> (raw)
On Wed, May 12, 2021 at 03:30:48AM +0200, Václav Kubernát wrote:
> In the old code, pwm*_enable does two things. Firstly, it sets whether
> the chip should run in PWM or RPM mode. Secondly, it tells the chip
> whether it should monitor fan RPM. However, these two settings aren't
> tied together, so they shouldn't be set with a single value. In the new
> code, fan*_enable now controls fan RPM monitoring (pwm*_enable no longer
> controls that).
>
> According to the sysfs hwmon documentation, pwm*_enable has three
> possible values, 0 for "no control / full-speed", 1 for manual mode, and
> 2+ for automatic. The old code works fine for 1 and 2, but 0 only
> differs from 1 in that it just turns off fan speed monitoring. The chip
> actually does have a way to turn off fan controls (and only monitor),
> and what that does is that it sets PWM to 0% duty cycle. In the new
> code, 0 in pwm*_enable turns off the "control" feature of the chip.
>
> These two changes are closely connected together, mainly because the
> detection of the pwm*_enable value depended on whether fan speed
> monitoring is enabled (which is now controlled as written in the first
> paragraph).
>
> Signed-off-by: Václav Kubernát <kubernat@cesnet.cz>
> ---
> Documentation/hwmon/max31790.rst | 10 ++--
> drivers/hwmon/max31790.c | 78 +++++++++++++++++++++-----------
> 2 files changed, 58 insertions(+), 30 deletions(-)
>
> diff --git a/Documentation/hwmon/max31790.rst b/Documentation/hwmon/max31790.rst
> index f301385d8cef..d2ac4e926905 100644
> --- a/Documentation/hwmon/max31790.rst
> +++ b/Documentation/hwmon/max31790.rst
> @@ -34,10 +34,14 @@ also be configured to serve as tachometer inputs.
> Sysfs entries
> -------------
>
> -================== === =======================================================
> +================== === =============================================================
> +fan[1-12]_enable RW enable fan speed monitoring
> fan[1-12]_input RO fan tachometer speed in RPM
> fan[1-12]_fault RO fan experienced fault
> fan[1-6]_target RW desired fan speed in RPM
> -pwm[1-6]_enable RW regulator mode, 0=disabled, 1=manual mode, 2=rpm mode
> +pwm[1-6]_enable RW regulator mode, 0=no control, sets 0% PWM,
> + 1=manual (pwm) mode,
> + 2=rpm mode
> + setting rpm mode sets fan*_enable to 1
> pwm[1-6] RW fan target duty cycle (0-255)
> -================== === =======================================================
> +================== === =============================================================
> diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c
> index e3765ce4444a..5d4c551df010 100644
> --- a/drivers/hwmon/max31790.c
> +++ b/drivers/hwmon/max31790.c
> @@ -30,6 +30,7 @@
> #define MAX31790_FAN_CFG_RPM_MODE 0x80
> #define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08
> #define MAX31790_FAN_CFG_TACH_INPUT 0x01
> +#define MAX31790_FAN_CFG_CTRL_MON 0x10
>
> /* Fan Dynamics register bits */
> #define MAX31790_FAN_DYN_SR_SHIFT 5
> @@ -191,6 +192,9 @@ static int max31790_read_fan(struct device *dev, u32 attr, int channel,
> else
> *val = !!(fault & (1 << channel));
> return 0;
> + case hwmon_fan_enable:
> + *val = !!(data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN);
fan_config array size is 6, and there are up to 12 fans ... so this won't
work for fans 7..12.
> + return 0;
> default:
> return -EOPNOTSUPP;
> }
> @@ -233,6 +237,15 @@ static int max31790_write_fan(struct device *dev, u32 attr, int channel,
> MAX31790_REG_TARGET_COUNT(channel),
> target_count);
> break;
> + case hwmon_fan_enable:
> + if (val == 0)
> + data->fan_config[channel] &= ~MAX31790_FAN_CFG_TACH_INPUT_EN;
> + else
> + data->fan_config[channel] |= MAX31790_FAN_CFG_TACH_INPUT_EN;
> + err = regmap_write(regmap,
> + MAX31790_REG_FAN_CONFIG(channel),
> + data->fan_config[channel]);
> + break;
Same as above.
As it turns out, even the current code doesn't really work for fans 7..12.
sr = get_tach_period(data->fan_dynamics[channel]);
However, the data->fan_dynamics array has only 6 entries, not 12, so
reading fan[7-12]_input will result in bad/random values.
> default:
> err = -EOPNOTSUPP;
> break;
> @@ -260,6 +273,11 @@ static umode_t max31790_fan_is_visible(const void *_data, u32 attr, int channel)
> !(fan_config & MAX31790_FAN_CFG_TACH_INPUT))
> return 0644;
> return 0;
> + case hwmon_fan_enable:
> + if (channel < NR_CHANNEL ||
> + (fan_config & MAX31790_FAN_CFG_TACH_INPUT))
> + return 0644;
> + return 0;
> default:
> return 0;
> }
> @@ -281,12 +299,12 @@ static int max31790_read_pwm(struct device *dev, u32 attr, int channel,
> *val = read >> 8;
> return 0;
> case hwmon_pwm_enable:
> - if (data->fan_config[channel] & MAX31790_FAN_CFG_RPM_MODE)
> + if (data->fan_config[channel] & MAX31790_FAN_CFG_CTRL_MON)
> + *val = 0;
> + else if (data->fan_config[channel] & MAX31790_FAN_CFG_RPM_MODE)
> *val = 2;
> - else if (data->fan_config[channel] & MAX31790_FAN_CFG_TACH_INPUT_EN)
> + else
> *val = 1;
> - else
> - *val = 0;
> return 0;
> default:
> return -EOPNOTSUPP;
> @@ -298,35 +316,41 @@ static int max31790_write_pwm(struct device *dev, u32 attr, int channel,
> {
> struct max31790_data *data = dev_get_drvdata(dev);
> struct regmap *regmap = data->regmap;
> - u8 fan_config;
> + u8 fan_config = data->fan_config[channel];
> int err = 0;
>
> mutex_lock(&data->update_lock);
>
> switch (attr) {
> case hwmon_pwm_input:
> - if (val < 0 || val > 255) {
> + if (fan_config & MAX31790_FAN_CFG_CTRL_MON || val < 0 || val > 255) {
> err = -EINVAL;
> break;
> }
> +
> err = write_reg_word(regmap, MAX31790_REG_PWMOUT(channel), val << 8);
> break;
> case hwmon_pwm_enable:
> fan_config = data->fan_config[channel];
> - if (val == 0) {
> - fan_config &= ~(MAX31790_FAN_CFG_TACH_INPUT_EN |
> - MAX31790_FAN_CFG_RPM_MODE);
> - } else if (val == 1) {
> - fan_config = (fan_config |
> - MAX31790_FAN_CFG_TACH_INPUT_EN) &
> - ~MAX31790_FAN_CFG_RPM_MODE;
> + if (val == 0)
> + fan_config |= MAX31790_FAN_CFG_CTRL_MON;
> + else if (val == 1) {
> + fan_config &= ~(MAX31790_FAN_CFG_RPM_MODE | MAX31790_FAN_CFG_CTRL_MON);
> } else if (val == 2) {
> - fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN |
> - MAX31790_FAN_CFG_RPM_MODE;
> + fan_config &= ~(MAX31790_FAN_CFG_CTRL_MON);
> + fan_config |= MAX31790_FAN_CFG_RPM_MODE;
> } else {
> err = -EINVAL;
> break;
> }
> +
> + /*
> + * RPM mode implies enabled TACH input, so enable it in RPM
> + * mode.
> + */
> + if (val == 2)
> + fan_config |= MAX31790_FAN_CFG_TACH_INPUT_EN;
> +
> data->fan_config[channel] = fan_config;
> err = regmap_write(regmap,
> MAX31790_REG_FAN_CONFIG(channel),
> @@ -400,18 +424,18 @@ static umode_t max31790_is_visible(const void *data,
>
> static const struct hwmon_channel_info *max31790_info[] = {
> HWMON_CHANNEL_INFO(fan,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT,
> - HWMON_F_INPUT | HWMON_F_FAULT),
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT,
> + HWMON_F_ENABLE | HWMON_F_INPUT | HWMON_F_FAULT),
> HWMON_CHANNEL_INFO(pwm,
> HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
> HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
next reply other threads:[~2021-05-18 21:16 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-18 21:16 Guenter Roeck [this message]
2021-05-19 9:10 ` [PATCH v5 2/5] hwmon: (max31790) Fix and split pwm*_enable Jan Kundrát
2021-05-19 13:55 ` Guenter Roeck
2021-05-20 11:29 ` Jan Kundrát
2021-05-20 11:50 ` Guenter Roeck
-- strict thread matches above, loose matches on Subject: below --
2021-05-12 1:30 [PATCH v5 1/5] hwmon: (max31790) Rework to use regmap Václav Kubernát
2021-05-12 1:30 ` [PATCH v5 2/5] hwmon: (max31790) Fix and split pwm*_enable Václav Kubernát
2021-05-12 1:32 ` Václav Kubernát
2021-05-18 14:59 ` Guenter Roeck
2021-05-19 23:11 ` Guenter Roeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210518211609.GA3532746@roeck-us.net \
--to=linux@roeck-us.net \
--cc=corbet@lwn.net \
--cc=jdelvare@suse.com \
--cc=kubernat@cesnet.cz \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hwmon@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.