diff mbox series

[v1,2/4] hwmon: (it87) Add calls to smbus_enable/smbus_disable as required.

Message ID 20230409034718.1938695-3-frank@crawford.emu.id.au (mailing list archive)
State Changes Requested
Headers show
Series hwmon: (it87) Add access control for SMBus | expand

Commit Message

Frank Crawford April 9, 2023, 3:47 a.m. UTC
Disable/re-enable access through SMBus for chip registers when they are
are being read or written.

For simple cases this is done at the same time as when a mutex is set,
however, within loops or during initialisation it is done separately.

Signed-off-by: Frank Crawford <frank@crawford.emu.id.au>
---
 drivers/hwmon/it87.c | 181 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 135 insertions(+), 46 deletions(-)

Comments

Guenter Roeck April 12, 2023, 6:44 p.m. UTC | #1
On Sun, Apr 09, 2023 at 01:47:16PM +1000, Frank Crawford wrote:
> Disable/re-enable access through SMBus for chip registers when they are
> are being read or written.
> 
> For simple cases this is done at the same time as when a mutex is set,
> however, within loops or during initialisation it is done separately.
> 
> Signed-off-by: Frank Crawford <frank@crawford.emu.id.au>

This gives me:

ERROR: code indent should use tabs where possible
#629: FILE: drivers/hwmon/it87.c:3268:
+^I    ^I^I     it87_read_value(data, IT87_REG_CHIPID) != 0x90) {$

WARNING: please, no space before tabs
#629: FILE: drivers/hwmon/it87.c:3268:
+^I    ^I^I     it87_read_value(data, IT87_REG_CHIPID) != 0x90) {$

> ---
>  drivers/hwmon/it87.c | 181 ++++++++++++++++++++++++++++++++-----------
>  1 file changed, 135 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
> index b74dd861f0fe..1ca3247efb9e 100644
> --- a/drivers/hwmon/it87.c
> +++ b/drivers/hwmon/it87.c
> @@ -746,6 +746,7 @@ static int smbus_enable(struct it87_data *data)
>  
>  /*
>   * Must be called with data->update_lock held, except during initialization.
> + * Must be called with SMBus accesses disabled.
>   * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
>   * would slow down the IT87 access and should not be necessary.
>   */
> @@ -757,6 +758,7 @@ static int it87_read_value(struct it87_data *data, u8 reg)
>  
>  /*
>   * Must be called with data->update_lock held, except during initialization.
> + * Must be called with SMBus accesses disabled.
>   * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
>   * would slow down the IT87 access and should not be necessary.
>   */
> @@ -816,15 +818,39 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
>  	}
>  }
>  
> +static int it87_lock(struct it87_data *data)
> +{
> +	int err;
> +
> +	mutex_lock(&data->update_lock);
> +	err = smbus_disable(data);
> +	if (err)
> +		mutex_unlock(&data->update_lock);
> +	return err;
> +}
> +
> +static void it87_unlock(struct it87_data *data)
> +{
> +	smbus_enable(data);
> +	mutex_unlock(&data->update_lock);
> +}
> +
>  static struct it87_data *it87_update_device(struct device *dev)
>  {
>  	struct it87_data *data = dev_get_drvdata(dev);
> +	struct it87_data *ret = data;
> +	int err;
>  	int i;
>  
>  	mutex_lock(&data->update_lock);
>  
>  	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
> -	    !data->valid) {
> +		       !data->valid) {
> +		err = smbus_disable(data);
> +		if (err) {
> +			ret = ERR_PTR(err);
> +			goto unlock;
> +		}
>  		if (update_vbat) {
>  			/*
>  			 * Cleared after each update, so reenable.  Value
> @@ -927,11 +953,11 @@ static struct it87_data *it87_update_device(struct device *dev)
>  		}
>  		data->last_updated = jiffies;
>  		data->valid = true;
> +		smbus_enable(data);
>  	}
> -
> +unlock:
>  	mutex_unlock(&data->update_lock);
> -
> -	return data;
> +	return ret;
>  }
>  
>  static ssize_t show_in(struct device *dev, struct device_attribute *attr,
> @@ -953,17 +979,21 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
>  	int index = sattr->index;
>  	int nr = sattr->nr;
>  	unsigned long val;
> +	int err;
>  
>  	if (kstrtoul(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	data->in[nr][index] = in_to_reg(data, nr, val);
>  	it87_write_value(data,
>  			 index == 1 ? IT87_REG_VIN_MIN(nr)
>  				    : IT87_REG_VIN_MAX(nr),
>  			 data->in[nr][index]);
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1042,11 +1072,14 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	long val;
>  	u8 reg, regval;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
>  
>  	switch (index) {
>  	default:
> @@ -1069,7 +1102,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
>  
>  	data->temp[nr][index] = TEMP_TO_REG(val);
>  	it87_write_value(data, reg, data->temp[nr][index]);
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1126,10 +1159,15 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	long val;
>  	u8 reg, extra;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
>  	reg &= ~(1 << nr);
>  	reg &= ~(8 << nr);
> @@ -1152,17 +1190,19 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
>  		reg |= (nr + 1) << 6;
>  	else if (has_temp_old_peci(data, nr) && val == 6)
>  		extra |= 0x80;
> -	else if (val != 0)
> -		return -EINVAL;
> +	else if (val != 0) {
> +		count = -EINVAL;
> +		goto unlock;
> +	}
>  
> -	mutex_lock(&data->update_lock);
>  	data->sensor = reg;
>  	data->extra = extra;
>  	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
>  	if (has_temp_old_peci(data, nr))
>  		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
>  	data->valid = false;	/* Force cache refresh */
> -	mutex_unlock(&data->update_lock);
> +unlock:
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1263,12 +1303,15 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
>  
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	long val;
> +	int err;
>  	u8 reg;
>  
>  	if (kstrtol(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
>  
>  	if (has_16bit_fans(data)) {
>  		data->fan[nr][index] = FAN16_TO_REG(val);
> @@ -1295,7 +1338,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
>  				 data->fan[nr][index]);
>  	}
>  
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1306,13 +1349,16 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	int nr = sensor_attr->index;
>  	unsigned long val;
> -	int min;
> +	int min, err;
>  	u8 old;
>  
>  	if (kstrtoul(buf, 10, &val) < 0)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	old = it87_read_value(data, IT87_REG_FAN_DIV);
>  
>  	/* Save fan min limit */
> @@ -1340,7 +1386,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
>  	data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
>  	it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
>  
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1381,6 +1427,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	int nr = sensor_attr->index;
>  	long val;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
>  		return -EINVAL;
> @@ -1391,7 +1438,9 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
>  			return -EINVAL;
>  	}
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
>  
>  	if (val == 0) {
>  		if (nr < 3 && data->type != it8603) {
> @@ -1442,7 +1491,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
>  		}
>  	}
>  
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1453,11 +1502,15 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	int nr = sensor_attr->index;
>  	long val;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	it87_update_pwm_ctrl(data, nr);
>  	if (has_newer_autopwm(data)) {
>  		/*
> @@ -1465,8 +1518,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
>  		 * is read-only so we can't write the value.
>  		 */
>  		if (data->pwm_ctrl[nr] & 0x80) {
> -			mutex_unlock(&data->update_lock);
> -			return -EBUSY;
> +			count = -EBUSY;
> +			goto unlock;
>  		}
>  		data->pwm_duty[nr] = pwm_to_reg(data, val);
>  		it87_write_value(data, IT87_REG_PWM_DUTY[nr],
> @@ -1483,7 +1536,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
>  					 data->pwm_ctrl[nr]);
>  		}
>  	}
> -	mutex_unlock(&data->update_lock);
> +unlock:
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1494,6 +1548,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	int nr = sensor_attr->index;
>  	unsigned long val;
> +	int err;
>  	int i;
>  
>  	if (kstrtoul(buf, 10, &val) < 0)
> @@ -1508,7 +1563,10 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
>  			break;
>  	}
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	if (nr == 0) {
>  		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
>  		data->fan_ctl |= i << 4;
> @@ -1518,7 +1576,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
>  		data->extra |= i << 4;
>  		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
>  	}
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  
>  	return count;
>  }
> @@ -1548,6 +1606,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	int nr = sensor_attr->index;
>  	long val;
> +	int err;
>  	u8 reg;
>  
>  	if (kstrtol(buf, 10, &val) < 0)
> @@ -1570,7 +1629,10 @@ static ssize_t set_pwm_temp_map(struct device *dev,
>  		return -EINVAL;
>  	}
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	it87_update_pwm_ctrl(data, nr);
>  	data->pwm_temp_map[nr] = reg;
>  	/*
> @@ -1582,7 +1644,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
>  						data->pwm_temp_map[nr];
>  		it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
>  	}
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1609,18 +1671,22 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
>  	int point = sensor_attr->index;
>  	int regaddr;
>  	long val;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
>  	if (has_newer_autopwm(data))
>  		regaddr = IT87_REG_AUTO_TEMP(nr, 3);
>  	else
>  		regaddr = IT87_REG_AUTO_PWM(nr, point);
>  	it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1642,15 +1708,19 @@ static ssize_t set_auto_pwm_slope(struct device *dev,
>  	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
>  	int nr = sensor_attr->index;
>  	unsigned long val;
> +	int err;
>  
>  	if (kstrtoul(buf, 10, &val) < 0 || val > 127)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
>  	it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
>  			 data->auto_pwm[nr][1]);
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1682,11 +1752,15 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
>  	int point = sensor_attr->index;
>  	long val;
>  	int reg;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	if (has_newer_autopwm(data) && !point) {
>  		reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
>  		reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
> @@ -1699,7 +1773,7 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
>  			point--;
>  		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
>  	}
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1902,13 +1976,16 @@ static ssize_t clear_intrusion(struct device *dev,
>  			       size_t count)
>  {
>  	struct it87_data *data = dev_get_drvdata(dev);
> -	int config;
> +	int err, config;
>  	long val;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || val != 0)
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	config = it87_read_value(data, IT87_REG_CONFIG);
>  	if (config < 0) {
>  		count = config;
> @@ -1918,8 +1995,7 @@ static ssize_t clear_intrusion(struct device *dev,
>  		/* Invalidate cache to force re-read */
>  		data->valid = false;
>  	}
> -	mutex_unlock(&data->update_lock);
> -
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -1958,18 +2034,22 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
>  	int bitnr = to_sensor_dev_attr(attr)->index;
>  	struct it87_data *data = dev_get_drvdata(dev);
>  	long val;
> +	int err;
>  
>  	if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
>  		return -EINVAL;
>  
> -	mutex_lock(&data->update_lock);
> +	err = it87_lock(data);
> +	if (err)
> +		return err;
> +
>  	data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
>  	if (val)
>  		data->beeps |= BIT(bitnr);
>  	else
>  		data->beeps &= ~BIT(bitnr);
>  	it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  	return count;
>  }
>  
> @@ -3129,6 +3209,7 @@ static int it87_probe(struct platform_device *pdev)
>  	struct it87_sio_data *sio_data = dev_get_platdata(dev);
>  	int enable_pwm_interface;
>  	struct device *hwmon_dev;
> +	int err;
>  
>  	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
>  	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
> @@ -3174,15 +3255,21 @@ static int it87_probe(struct platform_device *pdev)
>  		break;
>  	}
>  
> -	/* Now, we do the remaining detection. */
> -	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
> -	    it87_read_value(data, IT87_REG_CHIPID) != 0x90)
> -		return -ENODEV;
> -
>  	platform_set_drvdata(pdev, data);
>  
>  	mutex_init(&data->update_lock);
>  
> +	err = smbus_disable(data);
> +	if (err)
> +		return err;
> +
> +	/* Now, we do the remaining detection. */
> +	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
> +	    		     it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
> +		smbus_enable(data);
> +		return -ENODEV;
> +	}
> +
>  	/* Check PWM configuration */
>  	enable_pwm_interface = it87_check_pwm(dev);
>  	if (!enable_pwm_interface)
> @@ -3243,6 +3330,8 @@ static int it87_probe(struct platform_device *pdev)
>  	/* Initialize the IT87 chip */
>  	it87_init_device(pdev);
>  
> +	smbus_enable(data);
> +
>  	if (!sio_data->skip_vid) {
>  		data->has_vid = true;
>  		data->vrm = vid_which_vrm();
> @@ -3310,7 +3399,7 @@ static int it87_resume(struct device *dev)
>  
>  	it87_resume_sio(pdev);
>  
> -	mutex_lock(&data->update_lock);
> +	it87_lock(data);

Not checking for error here means that the lock was not acquired if
it87_lock() failed, yet it87_unlock() is called below. I don't really
know how to best handle this situation, but calling unlock if the lock
was not acquired is definitely wrong.

Guenter

>  
>  	it87_check_pwm(dev);
>  	it87_check_limit_regs(data);
> @@ -3323,7 +3412,7 @@ static int it87_resume(struct device *dev)
>  	/* force update */
>  	data->valid = false;
>  
> -	mutex_unlock(&data->update_lock);
> +	it87_unlock(data);
>  
>  	it87_update_device(dev);
>
diff mbox series

Patch

diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index b74dd861f0fe..1ca3247efb9e 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -746,6 +746,7 @@  static int smbus_enable(struct it87_data *data)
 
 /*
  * Must be called with data->update_lock held, except during initialization.
+ * Must be called with SMBus accesses disabled.
  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
  * would slow down the IT87 access and should not be necessary.
  */
@@ -757,6 +758,7 @@  static int it87_read_value(struct it87_data *data, u8 reg)
 
 /*
  * Must be called with data->update_lock held, except during initialization.
+ * Must be called with SMBus accesses disabled.
  * We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
  * would slow down the IT87 access and should not be necessary.
  */
@@ -816,15 +818,39 @@  static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
 	}
 }
 
+static int it87_lock(struct it87_data *data)
+{
+	int err;
+
+	mutex_lock(&data->update_lock);
+	err = smbus_disable(data);
+	if (err)
+		mutex_unlock(&data->update_lock);
+	return err;
+}
+
+static void it87_unlock(struct it87_data *data)
+{
+	smbus_enable(data);
+	mutex_unlock(&data->update_lock);
+}
+
 static struct it87_data *it87_update_device(struct device *dev)
 {
 	struct it87_data *data = dev_get_drvdata(dev);
+	struct it87_data *ret = data;
+	int err;
 	int i;
 
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
-	    !data->valid) {
+		       !data->valid) {
+		err = smbus_disable(data);
+		if (err) {
+			ret = ERR_PTR(err);
+			goto unlock;
+		}
 		if (update_vbat) {
 			/*
 			 * Cleared after each update, so reenable.  Value
@@ -927,11 +953,11 @@  static struct it87_data *it87_update_device(struct device *dev)
 		}
 		data->last_updated = jiffies;
 		data->valid = true;
+		smbus_enable(data);
 	}
-
+unlock:
 	mutex_unlock(&data->update_lock);
-
-	return data;
+	return ret;
 }
 
 static ssize_t show_in(struct device *dev, struct device_attribute *attr,
@@ -953,17 +979,21 @@  static ssize_t set_in(struct device *dev, struct device_attribute *attr,
 	int index = sattr->index;
 	int nr = sattr->nr;
 	unsigned long val;
+	int err;
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	data->in[nr][index] = in_to_reg(data, nr, val);
 	it87_write_value(data,
 			 index == 1 ? IT87_REG_VIN_MIN(nr)
 				    : IT87_REG_VIN_MAX(nr),
 			 data->in[nr][index]);
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1042,11 +1072,14 @@  static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	long val;
 	u8 reg, regval;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
 
 	switch (index) {
 	default:
@@ -1069,7 +1102,7 @@  static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
 
 	data->temp[nr][index] = TEMP_TO_REG(val);
 	it87_write_value(data, reg, data->temp[nr][index]);
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1126,10 +1159,15 @@  static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	long val;
 	u8 reg, extra;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0)
 		return -EINVAL;
 
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
 	reg &= ~(1 << nr);
 	reg &= ~(8 << nr);
@@ -1152,17 +1190,19 @@  static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
 		reg |= (nr + 1) << 6;
 	else if (has_temp_old_peci(data, nr) && val == 6)
 		extra |= 0x80;
-	else if (val != 0)
-		return -EINVAL;
+	else if (val != 0) {
+		count = -EINVAL;
+		goto unlock;
+	}
 
-	mutex_lock(&data->update_lock);
 	data->sensor = reg;
 	data->extra = extra;
 	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
 	if (has_temp_old_peci(data, nr))
 		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
 	data->valid = false;	/* Force cache refresh */
-	mutex_unlock(&data->update_lock);
+unlock:
+	it87_unlock(data);
 	return count;
 }
 
@@ -1263,12 +1303,15 @@  static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
 
 	struct it87_data *data = dev_get_drvdata(dev);
 	long val;
+	int err;
 	u8 reg;
 
 	if (kstrtol(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
 
 	if (has_16bit_fans(data)) {
 		data->fan[nr][index] = FAN16_TO_REG(val);
@@ -1295,7 +1338,7 @@  static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
 				 data->fan[nr][index]);
 	}
 
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1306,13 +1349,16 @@  static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = sensor_attr->index;
 	unsigned long val;
-	int min;
+	int min, err;
 	u8 old;
 
 	if (kstrtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	old = it87_read_value(data, IT87_REG_FAN_DIV);
 
 	/* Save fan min limit */
@@ -1340,7 +1386,7 @@  static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 	data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
 	it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
 
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1381,6 +1427,7 @@  static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = sensor_attr->index;
 	long val;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
 		return -EINVAL;
@@ -1391,7 +1438,9 @@  static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
 			return -EINVAL;
 	}
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
 
 	if (val == 0) {
 		if (nr < 3 && data->type != it8603) {
@@ -1442,7 +1491,7 @@  static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
 		}
 	}
 
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1453,11 +1502,15 @@  static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = sensor_attr->index;
 	long val;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	it87_update_pwm_ctrl(data, nr);
 	if (has_newer_autopwm(data)) {
 		/*
@@ -1465,8 +1518,8 @@  static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 		 * is read-only so we can't write the value.
 		 */
 		if (data->pwm_ctrl[nr] & 0x80) {
-			mutex_unlock(&data->update_lock);
-			return -EBUSY;
+			count = -EBUSY;
+			goto unlock;
 		}
 		data->pwm_duty[nr] = pwm_to_reg(data, val);
 		it87_write_value(data, IT87_REG_PWM_DUTY[nr],
@@ -1483,7 +1536,8 @@  static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
 					 data->pwm_ctrl[nr]);
 		}
 	}
-	mutex_unlock(&data->update_lock);
+unlock:
+	it87_unlock(data);
 	return count;
 }
 
@@ -1494,6 +1548,7 @@  static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = sensor_attr->index;
 	unsigned long val;
+	int err;
 	int i;
 
 	if (kstrtoul(buf, 10, &val) < 0)
@@ -1508,7 +1563,10 @@  static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
 			break;
 	}
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	if (nr == 0) {
 		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
 		data->fan_ctl |= i << 4;
@@ -1518,7 +1576,7 @@  static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
 		data->extra |= i << 4;
 		it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
 	}
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 
 	return count;
 }
@@ -1548,6 +1606,7 @@  static ssize_t set_pwm_temp_map(struct device *dev,
 	struct it87_data *data = dev_get_drvdata(dev);
 	int nr = sensor_attr->index;
 	long val;
+	int err;
 	u8 reg;
 
 	if (kstrtol(buf, 10, &val) < 0)
@@ -1570,7 +1629,10 @@  static ssize_t set_pwm_temp_map(struct device *dev,
 		return -EINVAL;
 	}
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	it87_update_pwm_ctrl(data, nr);
 	data->pwm_temp_map[nr] = reg;
 	/*
@@ -1582,7 +1644,7 @@  static ssize_t set_pwm_temp_map(struct device *dev,
 						data->pwm_temp_map[nr];
 		it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
 	}
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1609,18 +1671,22 @@  static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
 	int point = sensor_attr->index;
 	int regaddr;
 	long val;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	data->auto_pwm[nr][point] = pwm_to_reg(data, val);
 	if (has_newer_autopwm(data))
 		regaddr = IT87_REG_AUTO_TEMP(nr, 3);
 	else
 		regaddr = IT87_REG_AUTO_PWM(nr, point);
 	it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1642,15 +1708,19 @@  static ssize_t set_auto_pwm_slope(struct device *dev,
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	unsigned long val;
+	int err;
 
 	if (kstrtoul(buf, 10, &val) < 0 || val > 127)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
 	it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
 			 data->auto_pwm[nr][1]);
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1682,11 +1752,15 @@  static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
 	int point = sensor_attr->index;
 	long val;
 	int reg;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	if (has_newer_autopwm(data) && !point) {
 		reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
 		reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
@@ -1699,7 +1773,7 @@  static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
 			point--;
 		it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
 	}
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -1902,13 +1976,16 @@  static ssize_t clear_intrusion(struct device *dev,
 			       size_t count)
 {
 	struct it87_data *data = dev_get_drvdata(dev);
-	int config;
+	int err, config;
 	long val;
 
 	if (kstrtol(buf, 10, &val) < 0 || val != 0)
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	config = it87_read_value(data, IT87_REG_CONFIG);
 	if (config < 0) {
 		count = config;
@@ -1918,8 +1995,7 @@  static ssize_t clear_intrusion(struct device *dev,
 		/* Invalidate cache to force re-read */
 		data->valid = false;
 	}
-	mutex_unlock(&data->update_lock);
-
+	it87_unlock(data);
 	return count;
 }
 
@@ -1958,18 +2034,22 @@  static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
 	int bitnr = to_sensor_dev_attr(attr)->index;
 	struct it87_data *data = dev_get_drvdata(dev);
 	long val;
+	int err;
 
 	if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
 		return -EINVAL;
 
-	mutex_lock(&data->update_lock);
+	err = it87_lock(data);
+	if (err)
+		return err;
+
 	data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
 	if (val)
 		data->beeps |= BIT(bitnr);
 	else
 		data->beeps &= ~BIT(bitnr);
 	it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 	return count;
 }
 
@@ -3129,6 +3209,7 @@  static int it87_probe(struct platform_device *pdev)
 	struct it87_sio_data *sio_data = dev_get_platdata(dev);
 	int enable_pwm_interface;
 	struct device *hwmon_dev;
+	int err;
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 	if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -3174,15 +3255,21 @@  static int it87_probe(struct platform_device *pdev)
 		break;
 	}
 
-	/* Now, we do the remaining detection. */
-	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
-	    it87_read_value(data, IT87_REG_CHIPID) != 0x90)
-		return -ENODEV;
-
 	platform_set_drvdata(pdev, data);
 
 	mutex_init(&data->update_lock);
 
+	err = smbus_disable(data);
+	if (err)
+		return err;
+
+	/* Now, we do the remaining detection. */
+	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
+	    		     it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
+		smbus_enable(data);
+		return -ENODEV;
+	}
+
 	/* Check PWM configuration */
 	enable_pwm_interface = it87_check_pwm(dev);
 	if (!enable_pwm_interface)
@@ -3243,6 +3330,8 @@  static int it87_probe(struct platform_device *pdev)
 	/* Initialize the IT87 chip */
 	it87_init_device(pdev);
 
+	smbus_enable(data);
+
 	if (!sio_data->skip_vid) {
 		data->has_vid = true;
 		data->vrm = vid_which_vrm();
@@ -3310,7 +3399,7 @@  static int it87_resume(struct device *dev)
 
 	it87_resume_sio(pdev);
 
-	mutex_lock(&data->update_lock);
+	it87_lock(data);
 
 	it87_check_pwm(dev);
 	it87_check_limit_regs(data);
@@ -3323,7 +3412,7 @@  static int it87_resume(struct device *dev)
 	/* force update */
 	data->valid = false;
 
-	mutex_unlock(&data->update_lock);
+	it87_unlock(data);
 
 	it87_update_device(dev);