Commit 49a418d7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.15-rc2' of...

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
parents 2db767d9 68615eb0
...@@ -34,6 +34,10 @@ Required properties: ...@@ -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 {
......
...@@ -6174,7 +6174,6 @@ M: Jean Delvare <jdelvare@suse.com> ...@@ -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/
......
...@@ -22,6 +22,7 @@ ...@@ -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[] = { ...@@ -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[] = { ...@@ -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) ...@@ -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;
......
...@@ -21,6 +21,7 @@ ...@@ -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, ...@@ -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; s64 b, val = (s16)sensor->data;
long m, b, R; 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, ...@@ -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, ...@@ -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, ...@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment