All of lore.kernel.org
 help / color / mirror / Atom feed
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,

             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.