Commit 2a3e75a7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'hwmon-for-v6.3-rc3' of...

Merge tag 'hwmon-for-v6.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - ltc2992, adm1266: Set missing can_sleep flag

 - tmp512/tmp513: Drop of_match_ptr for ID table to fix build with
   !CONFIG_OF

 - ucd90320: Fix back-to-back access problem

 - ina3221: Fix bad error return from probe function

 - xgene: Fix use-after-free bug in remove function

 - adt7475: Fix hysteresis register bit masks, and fix association of
   'smoothing' attributes

* tag 'hwmon-for-v6.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (ltc2992) Set `can_sleep` flag for GPIO chip
  hwmon: (adm1266) Set `can_sleep` flag for GPIO chip
  hwmon: tmp512: drop of_match_ptr for ID table
  hwmon: (ucd90320) Add minimum delay between bus accesses
  hwmon: (ina3221) return prober error code
  hwmon: (xgene) Fix use after free bug in xgene_hwmon_remove due to race condition
  hwmon: (adt7475) Fix masking of hysteresis registers
  hwmon: (adt7475) Display smoothing attributes in correct order
parents f900bffe ab007093
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -488,10 +488,10 @@ static ssize_t temp_store(struct device *dev, struct device_attribute *attr,
		val = (temp - val) / 1000;

		if (sattr->index != 1) {
			data->temp[HYSTERSIS][sattr->index] &= 0xF0;
			data->temp[HYSTERSIS][sattr->index] &= 0x0F;
			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF) << 4;
		} else {
			data->temp[HYSTERSIS][sattr->index] &= 0x0F;
			data->temp[HYSTERSIS][sattr->index] &= 0xF0;
			data->temp[HYSTERSIS][sattr->index] |= (val & 0xF);
		}

@@ -556,11 +556,11 @@ static ssize_t temp_st_show(struct device *dev, struct device_attribute *attr,
		val = data->enh_acoustics[0] & 0xf;
		break;
	case 1:
		val = (data->enh_acoustics[1] >> 4) & 0xf;
		val = data->enh_acoustics[1] & 0xf;
		break;
	case 2:
	default:
		val = data->enh_acoustics[1] & 0xf;
		val = (data->enh_acoustics[1] >> 4) & 0xf;
		break;
	}

+1 −1
Original line number Diff line number Diff line
@@ -772,7 +772,7 @@ static int ina3221_probe_child_from_dt(struct device *dev,
		return ret;
	} else if (val > INA3221_CHANNEL3) {
		dev_err(dev, "invalid reg %d of %pOFn\n", val, child);
		return ret;
		return -EINVAL;
	}

	input = &ina->inputs[val];
+1 −0
Original line number Diff line number Diff line
@@ -323,6 +323,7 @@ static int ltc2992_config_gpio(struct ltc2992_state *st)
	st->gc.label = name;
	st->gc.parent = &st->client->dev;
	st->gc.owner = THIS_MODULE;
	st->gc.can_sleep = true;
	st->gc.base = -1;
	st->gc.names = st->gpio_names;
	st->gc.ngpio = ARRAY_SIZE(st->gpio_names);
+1 −0
Original line number Diff line number Diff line
@@ -301,6 +301,7 @@ static int adm1266_config_gpio(struct adm1266_data *data)
	data->gc.label = name;
	data->gc.parent = &data->client->dev;
	data->gc.owner = THIS_MODULE;
	data->gc.can_sleep = true;
	data->gc.base = -1;
	data->gc.names = data->gpio_names;
	data->gc.ngpio = ARRAY_SIZE(data->gpio_names);
+75 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */

#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -16,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/pmbus.h>
#include <linux/gpio/driver.h>
#include <linux/timekeeping.h>
#include "pmbus.h"

enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd90320, ucd9090,
@@ -65,6 +67,7 @@ struct ucd9000_data {
	struct gpio_chip gpio;
#endif
	struct dentry *debugfs;
	ktime_t write_time;
};
#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)

@@ -73,6 +76,73 @@ struct ucd9000_debugfs_entry {
	u8 index;
};

/*
 * It has been observed that the UCD90320 randomly fails register access when
 * doing another access right on the back of a register write. To mitigate this
 * make sure that there is a minimum delay between a write access and the
 * following access. The 250us is based on experimental data. At a delay of
 * 200us the issue seems to go away. Add a bit of extra margin to allow for
 * system to system differences.
 */
#define UCD90320_WAIT_DELAY_US 250

static inline void ucd90320_wait(const struct ucd9000_data *data)
{
	s64 delta = ktime_us_delta(ktime_get(), data->write_time);

	if (delta < UCD90320_WAIT_DELAY_US)
		udelay(UCD90320_WAIT_DELAY_US - delta);
}

static int ucd90320_read_word_data(struct i2c_client *client, int page,
				   int phase, int reg)
{
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
	struct ucd9000_data *data = to_ucd9000_data(info);

	if (reg >= PMBUS_VIRT_BASE)
		return -ENXIO;

	ucd90320_wait(data);
	return pmbus_read_word_data(client, page, phase, reg);
}

static int ucd90320_read_byte_data(struct i2c_client *client, int page, int reg)
{
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
	struct ucd9000_data *data = to_ucd9000_data(info);

	ucd90320_wait(data);
	return pmbus_read_byte_data(client, page, reg);
}

static int ucd90320_write_word_data(struct i2c_client *client, int page,
				    int reg, u16 word)
{
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
	struct ucd9000_data *data = to_ucd9000_data(info);
	int ret;

	ucd90320_wait(data);
	ret = pmbus_write_word_data(client, page, reg, word);
	data->write_time = ktime_get();

	return ret;
}

static int ucd90320_write_byte(struct i2c_client *client, int page, u8 value)
{
	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
	struct ucd9000_data *data = to_ucd9000_data(info);
	int ret;

	ucd90320_wait(data);
	ret = pmbus_write_byte(client, page, value);
	data->write_time = ktime_get();

	return ret;
}

static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
{
	int fan_config = 0;
@@ -598,6 +668,11 @@ static int ucd9000_probe(struct i2c_client *client)
		info->read_byte_data = ucd9000_read_byte_data;
		info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
		  | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
	} else if (mid->driver_data == ucd90320) {
		info->read_byte_data = ucd90320_read_byte_data;
		info->read_word_data = ucd90320_read_word_data;
		info->write_byte = ucd90320_write_byte;
		info->write_word_data = ucd90320_write_word_data;
	}

	ucd9000_probe_gpio(client, mid, data);
Loading