瀏覽代碼

Merge tag 'hwmon-for-linus-v4.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:
 "Fixes:

   - Drop reference to obsolete maintainer tree

   - Fix overflow bug in pmbus driver

   - Fix SMBUS timeout problem in jc42 driver

  For the SMBUS timeout handling, we had a brief discussion if this
  should be considered a bug fix or a feature. Peter says "it fixes real
  problems where the application misbehave due to faulty content when
  reading from an eeprom", and he needs the patch in his company's v4.14
  images. This is good enough for me and warrants backport to stable
  kernels"

* tag 'hwmon-for-linus-v4.15-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (jc42) optionally try to disable the SMBUS timeout
  hwmon: (pmbus) Use 64bit math for DIRECT format values
  hwmon: Drop reference to Jean's tree
Linus Torvalds 7 年之前
父節點
當前提交
49a418d783
共有 4 個文件被更改,包括 37 次插入10 次删除
  1. 4 0
      Documentation/devicetree/bindings/hwmon/jc42.txt
  2. 0 1
      MAINTAINERS
  3. 21 0
      drivers/hwmon/jc42.c
  4. 12 9
      drivers/hwmon/pmbus/pmbus_core.c

+ 4 - 0
Documentation/devicetree/bindings/hwmon/jc42.txt

@@ -34,6 +34,10 @@ Required properties:
 
 
 - reg: I2C address
 - reg: I2C address
 
 
+Optional properties:
+- smbus-timeout-disable: When set, the smbus timeout function will be disabled.
+			 This is not supported on all chips.
+
 Example:
 Example:
 
 
 temp-sensor@1a {
 temp-sensor@1a {

+ 0 - 1
MAINTAINERS

@@ -6174,7 +6174,6 @@ M:	Jean Delvare <jdelvare@suse.com>
 M:	Guenter Roeck <linux@roeck-us.net>
 M:	Guenter Roeck <linux@roeck-us.net>
 L:	linux-hwmon@vger.kernel.org
 L:	linux-hwmon@vger.kernel.org
 W:	http://hwmon.wiki.kernel.org/
 W:	http://hwmon.wiki.kernel.org/
-T:	quilt http://jdelvare.nerim.net/devel/linux/jdelvare-hwmon/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
 S:	Maintained
 S:	Maintained
 F:	Documentation/hwmon/
 F:	Documentation/hwmon/

+ 21 - 0
drivers/hwmon/jc42.c

@@ -22,6 +22,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
+#include <linux/bitops.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -45,6 +46,7 @@ static const unsigned short normal_i2c[] = {
 #define JC42_REG_TEMP		0x05
 #define JC42_REG_TEMP		0x05
 #define JC42_REG_MANID		0x06
 #define JC42_REG_MANID		0x06
 #define JC42_REG_DEVICEID	0x07
 #define JC42_REG_DEVICEID	0x07
+#define JC42_REG_SMBUS		0x22 /* NXP and Atmel, possibly others? */
 
 
 /* Status bits in temperature register */
 /* Status bits in temperature register */
 #define JC42_ALARM_CRIT_BIT	15
 #define JC42_ALARM_CRIT_BIT	15
@@ -75,6 +77,9 @@ static const unsigned short normal_i2c[] = {
 #define GT_MANID		0x1c68	/* Giantec */
 #define GT_MANID		0x1c68	/* Giantec */
 #define GT_MANID2		0x132d	/* Giantec, 2nd mfg ID */
 #define GT_MANID2		0x132d	/* Giantec, 2nd mfg ID */
 
 
+/* SMBUS register */
+#define SMBUS_STMOUT		BIT(7)  /* SMBus time-out, active low */
+
 /* Supported chips */
 /* Supported chips */
 
 
 /* Analog Devices */
 /* Analog Devices */
@@ -495,6 +500,22 @@ static int jc42_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 
 	data->extended = !!(cap & JC42_CAP_RANGE);
 	data->extended = !!(cap & JC42_CAP_RANGE);
 
 
+	if (device_property_read_bool(dev, "smbus-timeout-disable")) {
+		int smbus;
+
+		/*
+		 * Not all chips support this register, but from a
+		 * quick read of various datasheets no chip appears
+		 * incompatible with the below attempt to disable
+		 * the timeout. And the whole thing is opt-in...
+		 */
+		smbus = i2c_smbus_read_word_swapped(client, JC42_REG_SMBUS);
+		if (smbus < 0)
+			return smbus;
+		i2c_smbus_write_word_swapped(client, JC42_REG_SMBUS,
+					     smbus | SMBUS_STMOUT);
+	}
+
 	config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
 	config = i2c_smbus_read_word_swapped(client, JC42_REG_CONFIG);
 	if (config < 0)
 	if (config < 0)
 		return config;
 		return config;

+ 12 - 9
drivers/hwmon/pmbus/pmbus_core.c

@@ -21,6 +21,7 @@
 
 
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/math64.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/err.h>
@@ -499,8 +500,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
 static long pmbus_reg2data_direct(struct pmbus_data *data,
 static long pmbus_reg2data_direct(struct pmbus_data *data,
 				  struct pmbus_sensor *sensor)
 				  struct pmbus_sensor *sensor)
 {
 {
-	long val = (s16) sensor->data;
-	long m, b, R;
+	s64 b, val = (s16)sensor->data;
+	s32 m, R;
 
 
 	m = data->info->m[sensor->class];
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
 	b = data->info->b[sensor->class];
@@ -528,11 +529,12 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
 		R--;
 		R--;
 	}
 	}
 	while (R < 0) {
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = div_s64(val + 5LL, 10L);  /* round closest */
 		R++;
 		R++;
 	}
 	}
 
 
-	return (val - b) / m;
+	val = div_s64(val - b, m);
+	return clamp_val(val, LONG_MIN, LONG_MAX);
 }
 }
 
 
 /*
 /*
@@ -656,7 +658,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 				 struct pmbus_sensor *sensor, long val)
 				 struct pmbus_sensor *sensor, long val)
 {
 {
-	long m, b, R;
+	s64 b, val64 = val;
+	s32 m, R;
 
 
 	m = data->info->m[sensor->class];
 	m = data->info->m[sensor->class];
 	b = data->info->b[sensor->class];
 	b = data->info->b[sensor->class];
@@ -673,18 +676,18 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
 		R -= 3;		/* Adjust R and b for data in milli-units */
 		R -= 3;		/* Adjust R and b for data in milli-units */
 		b *= 1000;
 		b *= 1000;
 	}
 	}
-	val = val * m + b;
+	val64 = val64 * m + b;
 
 
 	while (R > 0) {
 	while (R > 0) {
-		val *= 10;
+		val64 *= 10;
 		R--;
 		R--;
 	}
 	}
 	while (R < 0) {
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val64 = div_s64(val64 + 5LL, 10L);  /* round closest */
 		R++;
 		R++;
 	}
 	}
 
 
-	return val;
+	return (u16)clamp_val(val64, S16_MIN, S16_MAX);
 }
 }
 
 
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,
 static u16 pmbus_data2reg_vid(struct pmbus_data *data,