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 <[email protected]>
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)