All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] hwmon: (lm90) Fix max6658 sporadic wrong temperature reading
@ 2019-06-28 19:06 Boyang Yu
  2019-06-30 20:39 ` Guenter Roeck
  0 siblings, 1 reply; 2+ messages in thread
From: Boyang Yu @ 2019-06-28 19:06 UTC (permalink / raw)
  To: Jean Delvare, Guenter Roeck; +Cc: linux-hwmon, deank, ryant, byu

max6658 may report unrealistically high temperature during
the driver initialization, for which, its overtemp alarm pin
also gets asserted. For certain devices implementing overtemp
protection based on that pin, it may further trigger a reset to
the device. By reproducing the problem, the wrong reading is
found to be coincident with changing the conversion rate.

To mitigate this issue, set the stop bit before changing the
conversion rate and unset it thereafter. After such change, the
wrong reading is not reproduced. Apply this change only to the
max6657 kind for now, controlled by flag LM90_PAUSE_ON_CONFIG.

Signed-off-by: Boyang Yu <byu@arista.com>
---
 drivers/hwmon/lm90.c | 42 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index e562a578f20e..bd00d8eac066 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -174,6 +174,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
 #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
 #define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
 #define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
+#define LM90_PAUSE_FOR_CONFIG	(1 << 8) /* Pause conversion for config	*/
 
 /* LM90 status */
 #define LM90_STATUS_LTHRM	(1 << 0) /* local THERM limit tripped */
@@ -367,6 +368,7 @@ static const struct lm90_params lm90_params[] = {
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
 	},
 	[max6657] = {
+		.flags = LM90_PAUSE_FOR_CONFIG,
 		.alert_alarms = 0x7c,
 		.max_convrate = 8,
 		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
@@ -567,6 +569,38 @@ static inline int lm90_select_remote_channel(struct i2c_client *client,
 	return 0;
 }
 
+static int lm90_write_convrate(struct i2c_client *client,
+			       struct lm90_data *data, int val)
+{
+	int err;
+	int config_orig, config_stop;
+
+	/* Save config and pause conversion */
+	if (data->flags & LM90_PAUSE_FOR_CONFIG) {
+		config_orig = lm90_read_reg(client, LM90_REG_R_CONFIG1);
+		if (config_orig < 0)
+			return config_orig;
+		config_stop = config_orig | 0x40;
+		if (config_orig != config_stop) {
+			err = i2c_smbus_write_byte_data(client,
+							LM90_REG_W_CONFIG1,
+							config_stop);
+			if (err < 0)
+				return err;
+		}
+	}
+
+	/* Set conv rate */
+	err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, val);
+
+	/* Revert change to config */
+	if (data->flags & LM90_PAUSE_FOR_CONFIG && config_orig != config_stop)
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
+					  config_orig);
+
+	return err;
+}
+
 /*
  * Set conversion rate.
  * client->update_lock must be held when calling this function (unless we are
@@ -587,7 +621,7 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
 		if (interval >= update_interval * 3 / 4)
 			break;
 
-	err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
+	err = lm90_write_convrate(client, data, i);
 	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
 	return err;
 }
@@ -1593,8 +1627,7 @@ static void lm90_restore_conf(void *_data)
 	struct i2c_client *client = data->client;
 
 	/* Restore initial configuration */
-	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
-				  data->convrate_orig);
+	lm90_write_convrate(client, data, data->convrate_orig);
 	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
 				  data->config_orig);
 }
@@ -1611,12 +1644,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
 	/*
 	 * Start the conversions.
 	 */
-	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
 	config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
 	if (config < 0)
 		return config;
 	data->config_orig = config;
 
+	lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
+
 	/* Check Temperature Range Select */
 	if (data->kind == adt7461 || data->kind == tmp451) {
 		if (config & 0x04)
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] hwmon: (lm90) Fix max6658 sporadic wrong temperature reading
  2019-06-28 19:06 [PATCH v2] hwmon: (lm90) Fix max6658 sporadic wrong temperature reading Boyang Yu
@ 2019-06-30 20:39 ` Guenter Roeck
  0 siblings, 0 replies; 2+ messages in thread
From: Guenter Roeck @ 2019-06-30 20:39 UTC (permalink / raw)
  To: Boyang Yu; +Cc: Jean Delvare, linux-hwmon, deank, ryant

On Fri, Jun 28, 2019 at 07:06:36PM +0000, Boyang Yu wrote:
> max6658 may report unrealistically high temperature during
> the driver initialization, for which, its overtemp alarm pin
> also gets asserted. For certain devices implementing overtemp
> protection based on that pin, it may further trigger a reset to
> the device. By reproducing the problem, the wrong reading is
> found to be coincident with changing the conversion rate.
> 
> To mitigate this issue, set the stop bit before changing the
> conversion rate and unset it thereafter. After such change, the
> wrong reading is not reproduced. Apply this change only to the
> max6657 kind for now, controlled by flag LM90_PAUSE_ON_CONFIG.
> 
> Signed-off-by: Boyang Yu <byu@arista.com>

Applied.

Thanks,
Guenter

> ---
>  drivers/hwmon/lm90.c | 42 ++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 38 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
> index e562a578f20e..bd00d8eac066 100644
> --- a/drivers/hwmon/lm90.c
> +++ b/drivers/hwmon/lm90.c
> @@ -174,6 +174,7 @@ enum chips { lm90, adm1032, lm99, lm86, max6657, max6659, adt7461, max6680,
>  #define LM90_HAVE_EMERGENCY_ALARM (1 << 5)/* emergency alarm		*/
>  #define LM90_HAVE_TEMP3		(1 << 6) /* 3rd temperature sensor	*/
>  #define LM90_HAVE_BROKEN_ALERT	(1 << 7) /* Broken alert		*/
> +#define LM90_PAUSE_FOR_CONFIG	(1 << 8) /* Pause conversion for config	*/
>  
>  /* LM90 status */
>  #define LM90_STATUS_LTHRM	(1 << 0) /* local THERM limit tripped */
> @@ -367,6 +368,7 @@ static const struct lm90_params lm90_params[] = {
>  		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
>  	},
>  	[max6657] = {
> +		.flags = LM90_PAUSE_FOR_CONFIG,
>  		.alert_alarms = 0x7c,
>  		.max_convrate = 8,
>  		.reg_local_ext = MAX6657_REG_R_LOCAL_TEMPL,
> @@ -567,6 +569,38 @@ static inline int lm90_select_remote_channel(struct i2c_client *client,
>  	return 0;
>  }
>  
> +static int lm90_write_convrate(struct i2c_client *client,
> +			       struct lm90_data *data, int val)
> +{
> +	int err;
> +	int config_orig, config_stop;
> +
> +	/* Save config and pause conversion */
> +	if (data->flags & LM90_PAUSE_FOR_CONFIG) {
> +		config_orig = lm90_read_reg(client, LM90_REG_R_CONFIG1);
> +		if (config_orig < 0)
> +			return config_orig;
> +		config_stop = config_orig | 0x40;
> +		if (config_orig != config_stop) {
> +			err = i2c_smbus_write_byte_data(client,
> +							LM90_REG_W_CONFIG1,
> +							config_stop);
> +			if (err < 0)
> +				return err;
> +		}
> +	}
> +
> +	/* Set conv rate */
> +	err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, val);
> +
> +	/* Revert change to config */
> +	if (data->flags & LM90_PAUSE_FOR_CONFIG && config_orig != config_stop)
> +		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
> +					  config_orig);
> +
> +	return err;
> +}
> +
>  /*
>   * Set conversion rate.
>   * client->update_lock must be held when calling this function (unless we are
> @@ -587,7 +621,7 @@ static int lm90_set_convrate(struct i2c_client *client, struct lm90_data *data,
>  		if (interval >= update_interval * 3 / 4)
>  			break;
>  
> -	err = i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE, i);
> +	err = lm90_write_convrate(client, data, i);
>  	data->update_interval = DIV_ROUND_CLOSEST(update_interval, 64);
>  	return err;
>  }
> @@ -1593,8 +1627,7 @@ static void lm90_restore_conf(void *_data)
>  	struct i2c_client *client = data->client;
>  
>  	/* Restore initial configuration */
> -	i2c_smbus_write_byte_data(client, LM90_REG_W_CONVRATE,
> -				  data->convrate_orig);
> +	lm90_write_convrate(client, data, data->convrate_orig);
>  	i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
>  				  data->config_orig);
>  }
> @@ -1611,12 +1644,13 @@ static int lm90_init_client(struct i2c_client *client, struct lm90_data *data)
>  	/*
>  	 * Start the conversions.
>  	 */
> -	lm90_set_convrate(client, data, 500);	/* 500ms; 2Hz conversion rate */
>  	config = lm90_read_reg(client, LM90_REG_R_CONFIG1);
>  	if (config < 0)
>  		return config;
>  	data->config_orig = config;
>  
> +	lm90_set_convrate(client, data, 500); /* 500ms; 2Hz conversion rate */
> +
>  	/* Check Temperature Range Select */
>  	if (data->kind == adt7461 || data->kind == tmp451) {
>  		if (config & 0x04)

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-06-30 20:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-28 19:06 [PATCH v2] hwmon: (lm90) Fix max6658 sporadic wrong temperature reading Boyang Yu
2019-06-30 20:39 ` Guenter Roeck

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.