Commit 24d734a2 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'hwmon-for-linus-v4.13-rc1' of...

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

Pull hwmon updates from Guenter Roeck:

 - Add PMBus client driver for IR35221

 - Add support for NCT6795D to nct6775 driver

 - Functional improvements to adt7475, aspeed-pwm-tacho, and ibmpowernv
   drivers

 - Minor fixes and cleanups in various drivers

* tag 'hwmon-for-linus-v4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (22 commits)
  hwmon: (aspeed-pwm-tacho) Poll with short sleeps.
  hwmon: (aspeed-pwm-tacho) reduce fan_tach period
  hwmon: (ibmpowernv) Add current(A) sensor
  hwmon: (ibmpowernv) introduce a legacy_compatibles array
  hwmon: (pwm-fan) Switch to new atomic PWM API
  hwmon: (scpi) Fix the scale of SCP sensor readings
  hwmon: (aspeed-pwm-tacho) Enable both edge measurement.
  hwmon: (ibmpowernv) Add highest/lowest attributes to sensors
  hwmon: (pmbus) move header file out of I2C realm
  hwmon: (max6639) move header file out of I2C realm
  hwmon: (ltc4245) move header file out of I2C realm
  hwmon: (ds620) move header file out of I2C realm
  hwmon: (ads1015) move header file out of I2C realm
  hwmon: (adt7475) temperature smoothing
  hwmon: (adt7475) add high frequency support
  hwmon: (adt7475) fan stall prevention
  hwmon: (adt7475) replace find_nearest() with find_closest()
  hwmon: (pmbus) Add client driver for IR35221
  hwmon: (nct6775) Add support for NCT6795D
  hwmon: (nct6775) Improve fan detection
  ...
parents 17ece345 44b41366
...@@ -40,7 +40,7 @@ By default all inputs are exported. ...@@ -40,7 +40,7 @@ By default all inputs are exported.
Platform Data Platform Data
------------- -------------
In linux/i2c/ads1015.h platform data is defined, channel_data contains In linux/platform_data/ads1015.h platform data is defined, channel_data contains
configuration data for the used input combinations: configuration data for the used input combinations:
- pga is the programmable gain amplifier (values are full scale) - pga is the programmable gain amplifier (values are full scale)
0: +/- 6.144 V 0: +/- 6.144 V
......
...@@ -109,6 +109,15 @@ fan speed) is applied. PWM values range from 0 (off) to 255 (full speed). ...@@ -109,6 +109,15 @@ fan speed) is applied. PWM values range from 0 (off) to 255 (full speed).
Fan speed may be set to maximum when the temperature sensor associated with Fan speed may be set to maximum when the temperature sensor associated with
the PWM control exceeds temp#_max. the PWM control exceeds temp#_max.
At Tmin - hysteresis the PWM output can either be off (0% duty cycle) or at the
minimum (i.e. auto_point1_pwm). This behaviour can be configured using the
pwm[1-*]_stall_disable sysfs attribute. A value of 0 means the fans will shut
off. A value of 1 means the fans will run at auto_point1_pwm.
The responsiveness of the ADT747x to temperature changes can be configured.
This allows smoothing of the fan speed transition. To set the transition time
set the value in ms in the temp[1-*]_smoothing sysfs attribute.
Notes Notes
----- -----
......
Kernel driver ir35221
=====================
Supported chips:
* Infinion IR35221
Prefix: 'ir35221'
Addresses scanned: -
Datasheet: Datasheet is not publicly available.
Author: Samuel Mendoza-Jonas <sam@mendozajonas.com>
Description
-----------
IR35221 is a Digital DC-DC Multiphase Converter
Usage Notes
-----------
This driver does not probe for PMBus devices. You will have to instantiate
devices explicitly.
Example: the following commands will load the driver for an IR35221
at address 0x70 on I2C bus #4:
# modprobe ir35221
# echo ir35221 0x70 > /sys/bus/i2c/devices/i2c-4/new_device
Sysfs attributes
----------------
curr1_label "iin"
curr1_input Measured input current
curr1_max Maximum current
curr1_max_alarm Current high alarm
curr[2-3]_label "iout[1-2]"
curr[2-3]_input Measured output current
curr[2-3]_crit Critical maximum current
curr[2-3]_crit_alarm Current critical high alarm
curr[2-3]_highest Highest output current
curr[2-3]_lowest Lowest output current
curr[2-3]_max Maximum current
curr[2-3]_max_alarm Current high alarm
in1_label "vin"
in1_input Measured input voltage
in1_crit Critical maximum input voltage
in1_crit_alarm Input voltage critical high alarm
in1_highest Highest input voltage
in1_lowest Lowest input voltage
in1_min Minimum input voltage
in1_min_alarm Input voltage low alarm
in[2-3]_label "vout[1-2]"
in[2-3]_input Measured output voltage
in[2-3]_lcrit Critical minimum output voltage
in[2-3]_lcrit_alarm Output voltage critical low alarm
in[2-3]_crit Critical maximum output voltage
in[2-3]_crit_alarm Output voltage critical high alarm
in[2-3]_highest Highest output voltage
in[2-3]_lowest Lowest output voltage
in[2-3]_max Maximum output voltage
in[2-3]_max_alarm Output voltage high alarm
in[2-3]_min Minimum output voltage
in[2-3]_min_alarm Output voltage low alarm
power1_label "pin"
power1_input Measured input power
power1_alarm Input power high alarm
power1_max Input power limit
power[2-3]_label "pout[1-2]"
power[2-3]_input Measured output power
power[2-3]_max Output power limit
power[2-3]_max_alarm Output power high alarm
temp[1-2]_input Measured temperature
temp[1-2]_crit Critical high temperature
temp[1-2]_crit_alarm Chip temperature critical high alarm
temp[1-2]_highest Highest temperature
temp[1-2]_lowest Lowest temperature
temp[1-2]_max Maximum temperature
temp[1-2]_max_alarm Chip temperature high alarm
...@@ -96,7 +96,7 @@ slowly, -EAGAIN will be returned when you read the sysfs attribute containing ...@@ -96,7 +96,7 @@ slowly, -EAGAIN will be returned when you read the sysfs attribute containing
the sensor reading. the sensor reading.
The LTC4245 chip can be configured to sample all GPIO pins with two methods: The LTC4245 chip can be configured to sample all GPIO pins with two methods:
1) platform data -- see include/linux/i2c/ltc4245.h 1) platform data -- see include/linux/platform_data/ltc4245.h
2) OF device tree -- add the "ltc4245,use-extra-gpios" property to each chip 2) OF device tree -- add the "ltc4245,use-extra-gpios" property to each chip
The default mode of operation is to sample a single GPIO pin. The default mode of operation is to sample a single GPIO pin.
...@@ -253,7 +253,7 @@ Specifically, it provides the following information. ...@@ -253,7 +253,7 @@ Specifically, it provides the following information.
PMBus driver platform data PMBus driver platform data
========================== ==========================
PMBus platform data is defined in include/linux/i2c/pmbus.h. Platform data PMBus platform data is defined in include/linux/pmbus.h. Platform data
currently only provides a flag field with a single bit used. currently only provides a flag field with a single bit used.
#define PMBUS_SKIP_STATUS_CHECK (1 << 0) #define PMBUS_SKIP_STATUS_CHECK (1 << 0)
......
...@@ -478,7 +478,7 @@ L: linux-hwmon@vger.kernel.org ...@@ -478,7 +478,7 @@ L: linux-hwmon@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/hwmon/ads1015 F: Documentation/hwmon/ads1015
F: drivers/hwmon/ads1015.c F: drivers/hwmon/ads1015.c
F: include/linux/i2c/ads1015.h F: include/linux/platform_data/ads1015.h
ADT746X FAN DRIVER ADT746X FAN DRIVER
M: Colin Leroy <colin@colino.net> M: Colin Leroy <colin@colino.net>
...@@ -10179,7 +10179,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git ...@@ -10179,7 +10179,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git
S: Maintained S: Maintained
F: Documentation/hwmon/pmbus F: Documentation/hwmon/pmbus
F: drivers/hwmon/pmbus/ F: drivers/hwmon/pmbus/
F: include/linux/i2c/pmbus.h F: include/linux/pmbus.h
PMC SIERRA MaxRAID DRIVER PMC SIERRA MaxRAID DRIVER
L: linux-scsi@vger.kernel.org L: linux-scsi@vger.kernel.org
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/i2c/ads1015.h> #include <linux/platform_data/ads1015.h>
/* ADS1015 registers */ /* ADS1015 registers */
enum { enum {
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/hwmon-vid.h> #include <linux/hwmon-vid.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/util_macros.h>
/* Indexes for the sysfs hooks */ /* Indexes for the sysfs hooks */
...@@ -78,6 +79,9 @@ ...@@ -78,6 +79,9 @@
#define REG_TEMP_TRANGE_BASE 0x5F #define REG_TEMP_TRANGE_BASE 0x5F
#define REG_ENHANCE_ACOUSTICS1 0x62
#define REG_ENHANCE_ACOUSTICS2 0x63
#define REG_PWM_MIN_BASE 0x64 #define REG_PWM_MIN_BASE 0x64
#define REG_TEMP_TMIN_BASE 0x67 #define REG_TEMP_TMIN_BASE 0x67
...@@ -208,6 +212,7 @@ struct adt7475_data { ...@@ -208,6 +212,7 @@ struct adt7475_data {
u8 range[3]; u8 range[3];
u8 pwmctl[3]; u8 pwmctl[3];
u8 pwmchan[3]; u8 pwmchan[3];
u8 enh_acoustics[2];
u8 vid; u8 vid;
u8 vrm; u8 vrm;
...@@ -314,35 +319,6 @@ static void adt7475_write_word(struct i2c_client *client, int reg, u16 val) ...@@ -314,35 +319,6 @@ static void adt7475_write_word(struct i2c_client *client, int reg, u16 val)
i2c_smbus_write_byte_data(client, reg, val & 0xFF); i2c_smbus_write_byte_data(client, reg, val & 0xFF);
} }
/*
* Find the nearest value in a table - used for pwm frequency and
* auto temp range
*/
static int find_nearest(long val, const int *array, int size)
{
int i;
if (val < array[0])
return 0;
if (val > array[size - 1])
return size - 1;
for (i = 0; i < size - 1; i++) {
int a, b;
if (val > array[i + 1])
continue;
a = val - array[i];
b = array[i + 1] - val;
return (a <= b) ? i : i + 1;
}
return 0;
}
static ssize_t show_voltage(struct device *dev, struct device_attribute *attr, static ssize_t show_voltage(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -550,6 +526,88 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, ...@@ -550,6 +526,88 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
return count; return count;
} }
/* Assuming CONFIG6[SLOW] is 0 */
static const int ad7475_st_map[] = {
37500, 18800, 12500, 7500, 4700, 3100, 1600, 800,
};
static ssize_t show_temp_st(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct adt7475_data *data = i2c_get_clientdata(client);
long val;
switch (sattr->index) {
case 0:
val = data->enh_acoustics[0] & 0xf;
break;
case 1:
val = (data->enh_acoustics[1] >> 4) & 0xf;
break;
case 2:
default:
val = data->enh_acoustics[1] & 0xf;
break;
}
if (val & 0x8)
return sprintf(buf, "%d\n", ad7475_st_map[val & 0x7]);
else
return sprintf(buf, "0\n");
}
static ssize_t set_temp_st(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct adt7475_data *data = i2c_get_clientdata(client);
unsigned char reg;
int shift, idx;
ulong val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
switch (sattr->index) {
case 0:
reg = REG_ENHANCE_ACOUSTICS1;
shift = 0;
idx = 0;
break;
case 1:
reg = REG_ENHANCE_ACOUSTICS2;
shift = 0;
idx = 1;
break;
case 2:
default:
reg = REG_ENHANCE_ACOUSTICS2;
shift = 4;
idx = 1;
break;
}
if (val > 0) {
val = find_closest_descending(val, ad7475_st_map,
ARRAY_SIZE(ad7475_st_map));
val |= 0x8;
}
mutex_lock(&data->lock);
data->enh_acoustics[idx] &= ~(0xf << shift);
data->enh_acoustics[idx] |= (val << shift);
i2c_smbus_write_byte_data(client, reg, data->enh_acoustics[idx]);
mutex_unlock(&data->lock);
return count;
}
/* /*
* Table of autorange values - the user will write the value in millidegrees, * Table of autorange values - the user will write the value in millidegrees,
* and we'll convert it * and we'll convert it
...@@ -606,7 +664,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr, ...@@ -606,7 +664,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr,
val -= temp; val -= temp;
/* Find the nearest table entry to what the user wrote */ /* Find the nearest table entry to what the user wrote */
val = find_nearest(val, autorange_table, ARRAY_SIZE(autorange_table)); val = find_closest(val, autorange_table, ARRAY_SIZE(autorange_table));
data->range[sattr->index] &= ~0xF0; data->range[sattr->index] &= ~0xF0;
data->range[sattr->index] |= val << 4; data->range[sattr->index] |= val << 4;
...@@ -728,6 +786,43 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, ...@@ -728,6 +786,43 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF); data->pwm[sattr->nr][sattr->index] = clamp_val(val, 0, 0xFF);
i2c_smbus_write_byte_data(client, reg, i2c_smbus_write_byte_data(client, reg,
data->pwm[sattr->nr][sattr->index]); data->pwm[sattr->nr][sattr->index]);
mutex_unlock(&data->lock);
return count;
}
static ssize_t show_stall_disable(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct adt7475_data *data = i2c_get_clientdata(client);
u8 mask = BIT(5 + sattr->index);
return sprintf(buf, "%d\n", !!(data->enh_acoustics[0] & mask));
}
static ssize_t set_stall_disable(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
struct i2c_client *client = to_i2c_client(dev);
struct adt7475_data *data = i2c_get_clientdata(client);
long val;
u8 mask = BIT(5 + sattr->index);
if (kstrtol(buf, 10, &val))
return -EINVAL;
mutex_lock(&data->lock);
data->enh_acoustics[0] &= ~mask;
if (val)
data->enh_acoustics[0] |= mask;
i2c_smbus_write_byte_data(client, REG_ENHANCE_ACOUSTICS1,
data->enh_acoustics[0]);
mutex_unlock(&data->lock); mutex_unlock(&data->lock);
...@@ -839,7 +934,7 @@ static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr, ...@@ -839,7 +934,7 @@ static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr,
/* List of frequencies for the PWM */ /* List of frequencies for the PWM */
static const int pwmfreq_table[] = { static const int pwmfreq_table[] = {
11, 14, 22, 29, 35, 44, 58, 88 11, 14, 22, 29, 35, 44, 58, 88, 22500
}; };
static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr, static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
...@@ -847,9 +942,10 @@ static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr, ...@@ -847,9 +942,10 @@ static ssize_t show_pwmfreq(struct device *dev, struct device_attribute *attr,
{ {
struct adt7475_data *data = adt7475_update_device(dev); struct adt7475_data *data = adt7475_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int i = clamp_val(data->range[sattr->index] & 0xf, 0,
ARRAY_SIZE(pwmfreq_table) - 1);
return sprintf(buf, "%d\n", return sprintf(buf, "%d\n", pwmfreq_table[i]);
pwmfreq_table[data->range[sattr->index] & 7]);
} }
static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr, static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
...@@ -864,13 +960,13 @@ static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr, ...@@ -864,13 +960,13 @@ static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr,
if (kstrtol(buf, 10, &val)) if (kstrtol(buf, 10, &val))
return -EINVAL; return -EINVAL;
out = find_nearest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table)); out = find_closest(val, pwmfreq_table, ARRAY_SIZE(pwmfreq_table));
mutex_lock(&data->lock); mutex_lock(&data->lock);
data->range[sattr->index] = data->range[sattr->index] =
adt7475_read(TEMP_TRANGE_REG(sattr->index)); adt7475_read(TEMP_TRANGE_REG(sattr->index));
data->range[sattr->index] &= ~7; data->range[sattr->index] &= ~0xf;
data->range[sattr->index] |= out; data->range[sattr->index] |= out;
i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index), i2c_smbus_write_byte_data(client, TEMP_TRANGE_REG(sattr->index),
...@@ -995,6 +1091,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, ...@@ -995,6 +1091,8 @@ static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 0); THERM, 0);
static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 0); set_temp, HYSTERSIS, 0);
static SENSOR_DEVICE_ATTR_2(temp1_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
set_temp_st, 0, 0);
static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, INPUT, 1);
static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1); static SENSOR_DEVICE_ATTR_2(temp2_alarm, S_IRUGO, show_temp, NULL, ALARM, 1);
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
...@@ -1011,6 +1109,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, ...@@ -1011,6 +1109,8 @@ static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 1); THERM, 1);
static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 1); set_temp, HYSTERSIS, 1);
static SENSOR_DEVICE_ATTR_2(temp2_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
set_temp_st, 0, 1);
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2); static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, INPUT, 2);
static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2); static SENSOR_DEVICE_ATTR_2(temp3_alarm, S_IRUGO, show_temp, NULL, ALARM, 2);
static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2); static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_temp, NULL, FAULT, 2);
...@@ -1028,6 +1128,8 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp, ...@@ -1028,6 +1128,8 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp, set_temp,
THERM, 2); THERM, 2);
static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp, static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp,
set_temp, HYSTERSIS, 2); set_temp, HYSTERSIS, 2);
static SENSOR_DEVICE_ATTR_2(temp3_smoothing, S_IRUGO | S_IWUSR, show_temp_st,
set_temp_st, 0, 2);
static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0); static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_tach, NULL, INPUT, 0);
static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach, static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_tach, set_tach,
MIN, 0); MIN, 0);
...@@ -1056,6 +1158,8 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, ...@@ -1056,6 +1158,8 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 0); set_pwm, MIN, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 0); set_pwm, MAX, 0);
static SENSOR_DEVICE_ATTR_2(pwm1_stall_disable, S_IRUGO | S_IWUSR,
show_stall_disable, set_stall_disable, 0, 0);
static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT, static SENSOR_DEVICE_ATTR_2(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
1); 1);
static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq, static SENSOR_DEVICE_ATTR_2(pwm2_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
...@@ -1068,6 +1172,8 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, ...@@ -1068,6 +1172,8 @@ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 1); set_pwm, MIN, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 1); set_pwm, MAX, 1);
static SENSOR_DEVICE_ATTR_2(pwm2_stall_disable, S_IRUGO | S_IWUSR,
show_stall_disable, set_stall_disable, 0, 1);
static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT, static SENSOR_DEVICE_ATTR_2(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, INPUT,
2); 2);
static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq, static SENSOR_DEVICE_ATTR_2(pwm3_freq, S_IRUGO | S_IWUSR, show_pwmfreq,
...@@ -1080,6 +1186,8 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, ...@@ -1080,6 +1186,8 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MIN, 2); set_pwm, MIN, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm,
set_pwm, MAX, 2); set_pwm, MAX, 2);
static SENSOR_DEVICE_ATTR_2(pwm3_stall_disable, S_IRUGO | S_IWUSR,
show_stall_disable, set_stall_disable, 0, 2);
/* Non-standard name, might need revisiting */ /* Non-standard name, might need revisiting */
static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit); static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit);
...@@ -1106,6 +1214,7 @@ static struct attribute *adt7475_attrs[] = { ...@@ -1106,6 +1214,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_smoothing.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr, &sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr, &sensor_dev_attr_temp2_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr,
...@@ -1115,6 +1224,7 @@ static struct attribute *adt7475_attrs[] = { ...@@ -1115,6 +1224,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr, &sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_smoothing.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr, &sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr,
...@@ -1125,6 +1235,7 @@ static struct attribute *adt7475_attrs[] = { ...@@ -1125,6 +1235,7 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr, &sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr, &sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_smoothing.dev_attr.attr,
&sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr,
...@@ -1140,12 +1251,14 @@ static struct attribute *adt7475_attrs[] = { ...@@ -1140,12 +1251,14 @@ static struct attribute *adt7475_attrs[] = {
&sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_stall_disable.dev_attr.attr,
&sensor_dev_attr_pwm3.dev_attr.attr, &sensor_dev_attr_pwm3.dev_attr.attr,
&sensor_dev_attr_pwm3_freq.dev_attr.attr, &sensor_dev_attr_pwm3_freq.dev_attr.attr,
&sensor_dev_attr_pwm3_enable.dev_attr.attr, &sensor_dev_attr_pwm3_enable.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm3_stall_disable.dev_attr.attr,
&dev_attr_pwm_use_point2_pwm_at_crit.attr, &dev_attr_pwm_use_point2_pwm_at_crit.attr,
NULL, NULL,
}; };
...@@ -1164,6 +1277,7 @@ static struct attribute *pwm2_attrs[] = { ...@@ -1164,6 +1277,7 @@ static struct attribute *pwm2_attrs[] = {
&sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_stall_disable.dev_attr.attr,
NULL NULL
}; };
......
...@@ -146,14 +146,26 @@ ...@@ -146,14 +146,26 @@
#define PWM_MAX 255 #define PWM_MAX 255
#define BOTH_EDGES 0x02 /* 10b */
#define M_PWM_DIV_H 0x00 #define M_PWM_DIV_H 0x00
#define M_PWM_DIV_L 0x05 #define M_PWM_DIV_L 0x05
#define M_PWM_PERIOD 0x5F #define M_PWM_PERIOD 0x5F
#define M_TACH_CLK_DIV 0x00 #define M_TACH_CLK_DIV 0x00
#define M_TACH_MODE 0x00 /*
#define M_TACH_UNIT 0x1000 * 5:4 Type N fan tach mode selection bit:
* 00: falling
* 01: rising
* 10: both
* 11: reserved.
*/
#define M_TACH_MODE 0x02 /* 10b */
#define M_TACH_UNIT 0x00c0
#define INIT_FAN_CTRL 0xFF #define INIT_FAN_CTRL 0xFF
/* How long we sleep in us while waiting for an RPM result. */
#define ASPEED_RPM_STATUS_SLEEP_USEC 500
struct aspeed_pwm_tacho_data { struct aspeed_pwm_tacho_data {
struct regmap *regmap; struct regmap *regmap;
unsigned long clk_freq; unsigned long clk_freq;
...@@ -163,6 +175,7 @@ struct aspeed_pwm_tacho_data { ...@@ -163,6 +175,7 @@ struct aspeed_pwm_tacho_data {
u8 type_pwm_clock_division_h[3]; u8 type_pwm_clock_division_h[3];
u8 type_pwm_clock_division_l[3]; u8 type_pwm_clock_division_l[3];
u8 type_fan_tach_clock_division[3]; u8 type_fan_tach_clock_division[3];
u8 type_fan_tach_mode[3];
u16 type_fan_tach_unit[3]; u16 type_fan_tach_unit[3];
u8 pwm_port_type[8]; u8 pwm_port_type[8];
u8 pwm_port_fan_ctrl[8]; u8 pwm_port_fan_ctrl[8];
...@@ -498,8 +511,9 @@ static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data ...@@ -498,8 +511,9 @@ static u32 aspeed_get_fan_tach_ch_measure_period(struct aspeed_pwm_tacho_data
static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv, static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
u8 fan_tach_ch) u8 fan_tach_ch)
{ {
u32 raw_data, tach_div, clk_source, sec, val; u32 raw_data, tach_div, clk_source, msec, usec, val;
u8 fan_tach_ch_source, type; u8 fan_tach_ch_source, type, mode, both;
int ret;
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0); regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0);
regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch); regmap_write(priv->regmap, ASPEED_PTCR_TRIGGER, 0x1 << fan_tach_ch);
...@@ -507,16 +521,31 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv, ...@@ -507,16 +521,31 @@ static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv,
fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch]; fan_tach_ch_source = priv->fan_tach_ch_source[fan_tach_ch];
type = priv->pwm_port_type[fan_tach_ch_source]; type = priv->pwm_port_type[fan_tach_ch_source];
sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type)); msec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type));
msleep(sec); usec = msec * 1000;
ret = regmap_read_poll_timeout(
priv->regmap,
ASPEED_PTCR_RESULT,
val,
(val & RESULT_STATUS_MASK),
ASPEED_RPM_STATUS_SLEEP_USEC,
usec);
regmap_read(priv->regmap, ASPEED_PTCR_RESULT, &val); /* return -ETIMEDOUT if we didn't get an answer. */
if (!(val & RESULT_STATUS_MASK)) if (ret)
return -ETIMEDOUT; return ret;
raw_data = val & RESULT_VALUE_MASK; raw_data = val & RESULT_VALUE_MASK;
tach_div = priv->type_fan_tach_clock_division[type]; tach_div = priv->type_fan_tach_clock_division[type];
tach_div = 0x4 << (tach_div * 2); /*
* We need the mode to determine if the raw_data is double (from
* counting both edges).
*/
mode = priv->type_fan_tach_mode[type];
both = (mode & BOTH_EDGES) ? 1 : 0;
tach_div = (0x4 << both) << (tach_div * 2);
clk_source = priv->clk_freq; clk_source = priv->clk_freq;
if (raw_data == 0) if (raw_data == 0)
...@@ -702,6 +731,7 @@ static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv) ...@@ -702,6 +731,7 @@ static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv)
aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true); aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true);
priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV; priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV;
priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT; priv->type_fan_tach_unit[TYPEM] = M_TACH_UNIT;
priv->type_fan_tach_mode[TYPEM] = M_TACH_MODE;
aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE, aspeed_set_tacho_type_values(priv->regmap, TYPEM, M_TACH_MODE,
M_TACH_UNIT, M_TACH_CLK_DIV); M_TACH_UNIT, M_TACH_CLK_DIV);
} }
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/i2c/ds620.h> #include <linux/platform_data/ds620.h>
/* /*
* Many DS620 constants specified below * Many DS620 constants specified below
......
...@@ -50,22 +50,34 @@ enum sensors { ...@@ -50,22 +50,34 @@ enum sensors {
TEMP, TEMP,
POWER_SUPPLY, POWER_SUPPLY,
POWER_INPUT, POWER_INPUT,
CURRENT,
MAX_SENSOR_TYPE, MAX_SENSOR_TYPE,
}; };
#define INVALID_INDEX (-1U) #define INVALID_INDEX (-1U)
/*
* 'compatible' string properties for sensor types as defined in old
* PowerNV firmware (skiboot). These are ordered as 'enum sensors'.
*/
static const char * const legacy_compatibles[] = {
"ibm,opal-sensor-cooling-fan",
"ibm,opal-sensor-amb-temp",
"ibm,opal-sensor-power-supply",
"ibm,opal-sensor-power"
};
static struct sensor_group { static struct sensor_group {
const char *name; const char *name; /* matches property 'sensor-type' */
const char *compatible;
struct attribute_group group; struct attribute_group group;
u32 attr_count; u32 attr_count;
u32 hwmon_index; u32 hwmon_index;
} sensor_groups[] = { } sensor_groups[] = {
{"fan", "ibm,opal-sensor-cooling-fan"}, { "fan" },
{"temp", "ibm,opal-sensor-amb-temp"}, { "temp" },
{"in", "ibm,opal-sensor-power-supply"}, { "in" },
{"power", "ibm,opal-sensor-power"} { "power" },
{ "curr" },
}; };
struct sensor_data { struct sensor_data {
...@@ -239,8 +251,8 @@ static int get_sensor_type(struct device_node *np) ...@@ -239,8 +251,8 @@ static int get_sensor_type(struct device_node *np)
enum sensors type; enum sensors type;
const char *str; const char *str;
for (type = 0; type < MAX_SENSOR_TYPE; type++) { for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) {
if (of_device_is_compatible(np, sensor_groups[type].compatible)) if (of_device_is_compatible(np, legacy_compatibles[type]))
return type; return type;
} }
...@@ -298,10 +310,14 @@ static int populate_attr_groups(struct platform_device *pdev) ...@@ -298,10 +310,14 @@ static int populate_attr_groups(struct platform_device *pdev)
sensor_groups[type].attr_count++; sensor_groups[type].attr_count++;
/* /*
* add a new attribute for labels * add attributes for labels, min and max
*/ */
if (!of_property_read_string(np, "label", &label)) if (!of_property_read_string(np, "label", &label))
sensor_groups[type].attr_count++; sensor_groups[type].attr_count++;
if (of_find_property(np, "sensor-data-min", NULL))
sensor_groups[type].attr_count++;
if (of_find_property(np, "sensor-data-max", NULL))
sensor_groups[type].attr_count++;
} }
of_node_put(opal); of_node_put(opal);
...@@ -337,6 +353,41 @@ static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, ...@@ -337,6 +353,41 @@ static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name,
sdata->dev_attr.show = show; sdata->dev_attr.show = show;
} }
static void populate_sensor(struct sensor_data *sdata, int od, int hd, int sid,
const char *attr_name, enum sensors type,
const struct attribute_group *pgroup,
ssize_t (*show)(struct device *dev,
struct device_attribute *attr,
char *buf))
{
sdata->id = sid;
sdata->type = type;
sdata->opal_index = od;
sdata->hwmon_index = hd;
create_hwmon_attr(sdata, attr_name, show);
pgroup->attrs[sensor_groups[type].attr_count++] = &sdata->dev_attr.attr;
}
static char *get_max_attr(enum sensors type)
{
switch (type) {
case POWER_INPUT:
return "input_highest";
default:
return "highest";
}
}
static char *get_min_attr(enum sensors type)
{
switch (type) {
case POWER_INPUT:
return "input_lowest";
default:
return "lowest";
}
}
/* /*
* Iterate through the device tree for each child of 'sensors' node, create * Iterate through the device tree for each child of 'sensors' node, create
* a sysfs attribute file, the file is named by translating the DT node name * a sysfs attribute file, the file is named by translating the DT node name
...@@ -417,16 +468,31 @@ static int create_device_attrs(struct platform_device *pdev) ...@@ -417,16 +468,31 @@ static int create_device_attrs(struct platform_device *pdev)
* attribute. They are related to the same * attribute. They are related to the same
* sensor. * sensor.
*/ */
sdata[count].type = type;
sdata[count].opal_index = sdata[count - 1].opal_index;
sdata[count].hwmon_index = sdata[count - 1].hwmon_index;
make_sensor_label(np, &sdata[count], label); make_sensor_label(np, &sdata[count], label);
populate_sensor(&sdata[count], opal_index,
sdata[count - 1].hwmon_index,
sensor_id, "label", type, pgroups[type],
show_label);
count++;
}
create_hwmon_attr(&sdata[count], "label", show_label); if (!of_property_read_u32(np, "sensor-data-max", &sensor_id)) {
attr_name = get_max_attr(type);
populate_sensor(&sdata[count], opal_index,
sdata[count - 1].hwmon_index,
sensor_id, attr_name, type,
pgroups[type], show_sensor);
count++;
}
pgroups[type]->attrs[sensor_groups[type].attr_count++] = if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) {
&sdata[count++].dev_attr.attr; attr_name = get_min_attr(type);
populate_sensor(&sdata[count], opal_index,
sdata[count - 1].hwmon_index,
sensor_id, attr_name, type,
pgroups[type], show_sensor);
count++;
} }
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c/ltc4245.h> #include <linux/platform_data/ltc4245.h>
/* Here are names of the chip's registers (a.k.a. commands) */ /* Here are names of the chip's registers (a.k.a. commands) */
enum ltc4245_cmd { enum ltc4245_cmd {
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/i2c/max6639.h> #include <linux/platform_data/max6639.h>
/* Addresses to scan */ /* Addresses to scan */
static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END };
......
...@@ -40,6 +40,8 @@ ...@@ -40,6 +40,8 @@
* nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3 * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
* nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3 * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
* nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3 * nct6793d 15 6 6 2+6 0xd120 0xc1 0x5ca3
* nct6795d 14 6 6 2+6 0xd350 0xc1 0x5ca3
*
* *
* #temp lists the number of monitored temperature sources (first value) plus * #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value). * the number of directly connectable temperature sensors (second value).
...@@ -58,13 +60,15 @@ ...@@ -58,13 +60,15 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/io.h> #include <linux/io.h>
#include "lm75.h" #include "lm75.h"
#define USE_ALTERNATE #define USE_ALTERNATE
enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793 }; enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
nct6795 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */ /* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = { static const char * const nct6775_device_names[] = {
...@@ -75,6 +79,7 @@ static const char * const nct6775_device_names[] = { ...@@ -75,6 +79,7 @@ static const char * const nct6775_device_names[] = {
"nct6791", "nct6791",
"nct6792", "nct6792",
"nct6793", "nct6793",
"nct6795",
}; };
static const char * const nct6775_sio_names[] __initconst = { static const char * const nct6775_sio_names[] __initconst = {
...@@ -85,6 +90,7 @@ static const char * const nct6775_sio_names[] __initconst = { ...@@ -85,6 +90,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6791D", "NCT6791D",
"NCT6792D", "NCT6792D",
"NCT6793D", "NCT6793D",
"NCT6795D",
}; };
static unsigned short force_id; static unsigned short force_id;
...@@ -104,6 +110,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); ...@@ -104,6 +110,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define NCT6775_LD_ACPI 0x0a #define NCT6775_LD_ACPI 0x0a
#define NCT6775_LD_HWM 0x0b #define NCT6775_LD_HWM 0x0b
#define NCT6775_LD_VID 0x0d #define NCT6775_LD_VID 0x0d
#define NCT6775_LD_12 0x12
#define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
...@@ -117,6 +124,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); ...@@ -117,6 +124,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6791_ID 0xc800 #define SIO_NCT6791_ID 0xc800
#define SIO_NCT6792_ID 0xc910 #define SIO_NCT6792_ID 0xc910
#define SIO_NCT6793_ID 0xd120 #define SIO_NCT6793_ID 0xd120
#define SIO_NCT6795_ID 0xd350
#define SIO_ID_MASK 0xFFF0 #define SIO_ID_MASK 0xFFF0
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
...@@ -360,12 +368,24 @@ static const char *const nct6775_temp_label[] = { ...@@ -360,12 +368,24 @@ static const char *const nct6775_temp_label[] = {
"PCH_DIM3_TEMP" "PCH_DIM3_TEMP"
}; };
static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1] #define NCT6775_TEMP_MASK 0x001ffffe
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 };
static const u16 NCT6775_REG_TEMP_ALTERNATE[32] = {
[13] = 0x661,
[14] = 0x662,
[15] = 0x664,
};
static const u16 NCT6775_REG_TEMP_CRIT[ARRAY_SIZE(nct6775_temp_label) - 1] static const u16 NCT6775_REG_TEMP_CRIT[32] = {
= { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06, [4] = 0xa00,
0xa07 }; [5] = 0xa01,
[6] = 0xa02,
[7] = 0xa03,
[8] = 0xa04,
[9] = 0xa05,
[10] = 0xa06,
[11] = 0xa07
};
/* NCT6776 specific data */ /* NCT6776 specific data */
...@@ -434,11 +454,18 @@ static const char *const nct6776_temp_label[] = { ...@@ -434,11 +454,18 @@ static const char *const nct6776_temp_label[] = {
"BYTE_TEMP" "BYTE_TEMP"
}; };
static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] #define NCT6776_TEMP_MASK 0x007ffffe
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 };
static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = {
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; [14] = 0x401,
[15] = 0x402,
[16] = 0x404,
};
static const u16 NCT6776_REG_TEMP_CRIT[32] = {
[11] = 0x709,
[12] = 0x70a,
};
/* NCT6779 specific data */ /* NCT6779 specific data */
...@@ -525,17 +552,19 @@ static const char *const nct6779_temp_label[] = { ...@@ -525,17 +552,19 @@ static const char *const nct6779_temp_label[] = {
"Virtual_TEMP" "Virtual_TEMP"
}; };
#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5) #define NCT6779_TEMP_MASK 0x07ffff7e
#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label) #define NCT6791_TEMP_MASK 0x87ffff7e
static const u16 NCT6779_REG_TEMP_ALTERNATE[NCT6791_NUM_LABELS - 1] static const u16 NCT6779_REG_TEMP_ALTERNATE[32]
= { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0, = { 0x490, 0x491, 0x492, 0x493, 0x494, 0x495, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407,
0x408, 0 }; 0x408, 0 };
static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1] static const u16 NCT6779_REG_TEMP_CRIT[32] = {
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; [15] = 0x709,
[16] = 0x70a,
};
/* NCT6791 specific data */ /* NCT6791 specific data */
...@@ -602,6 +631,8 @@ static const char *const nct6792_temp_label[] = { ...@@ -602,6 +631,8 @@ static const char *const nct6792_temp_label[] = {
"Virtual_TEMP" "Virtual_TEMP"
}; };
#define NCT6792_TEMP_MASK 0x9fffff7e
static const char *const nct6793_temp_label[] = { static const char *const nct6793_temp_label[] = {
"", "",
"SYSTIN", "SYSTIN",
...@@ -637,6 +668,45 @@ static const char *const nct6793_temp_label[] = { ...@@ -637,6 +668,45 @@ static const char *const nct6793_temp_label[] = {
"Virtual_TEMP" "Virtual_TEMP"
}; };
#define NCT6793_TEMP_MASK 0xbfff037e
static const char *const nct6795_temp_label[] = {
"",
"SYSTIN",
"CPUTIN",
"AUXTIN0",
"AUXTIN1",
"AUXTIN2",
"AUXTIN3",
"",
"SMBUSMASTER 0",
"SMBUSMASTER 1",
"SMBUSMASTER 2",
"SMBUSMASTER 3",
"SMBUSMASTER 4",
"SMBUSMASTER 5",
"SMBUSMASTER 6",
"SMBUSMASTER 7",
"PECI Agent 0",
"PECI Agent 1",
"PCH_CHIP_CPU_MAX_TEMP",
"PCH_CHIP_TEMP",
"PCH_CPU_TEMP",
"PCH_MCH_TEMP",
"PCH_DIM0_TEMP",
"PCH_DIM1_TEMP",
"PCH_DIM2_TEMP",
"PCH_DIM3_TEMP",
"BYTE_TEMP0",
"BYTE_TEMP1",
"PECI Agent 0 Calibration",
"PECI Agent 1 Calibration",
"",
"Virtual_TEMP"
};
#define NCT6795_TEMP_MASK 0xbfffff7e
/* NCT6102D/NCT6106D specific data */ /* NCT6102D/NCT6106D specific data */
#define NCT6106_REG_VBAT 0x318 #define NCT6106_REG_VBAT 0x318
...@@ -731,11 +801,16 @@ static const s8 NCT6106_BEEP_BITS[] = { ...@@ -731,11 +801,16 @@ static const s8 NCT6106_BEEP_BITS[] = {
34, -1 /* intrusion0, intrusion1 */ 34, -1 /* intrusion0, intrusion1 */
}; };
static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = {
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 }; [14] = 0x51,
[15] = 0x52,
[16] = 0x54,
};
static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] static const u16 NCT6106_REG_TEMP_CRIT[32] = {
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 }; [11] = 0x204,
[12] = 0x205,
};
static enum pwm_enable reg_to_pwm_enable(int pwm, int mode) static enum pwm_enable reg_to_pwm_enable(int pwm, int mode)
{ {
...@@ -810,7 +885,7 @@ static u16 fan_to_reg(u32 fan, unsigned int divreg) ...@@ -810,7 +885,7 @@ static u16 fan_to_reg(u32 fan, unsigned int divreg)
static inline unsigned int static inline unsigned int
div_from_reg(u8 reg) div_from_reg(u8 reg)
{ {
return 1 << reg; return BIT(reg);
} }
/* /*
...@@ -850,7 +925,7 @@ struct nct6775_data { ...@@ -850,7 +925,7 @@ struct nct6775_data {
u8 temp_src[NUM_TEMP]; u8 temp_src[NUM_TEMP];
u16 reg_temp_config[NUM_TEMP]; u16 reg_temp_config[NUM_TEMP];
const char * const *temp_label; const char * const *temp_label;
int temp_label_num; u32 temp_mask;
u16 REG_CONFIG; u16 REG_CONFIG;
u16 REG_VBAT; u16 REG_VBAT;
...@@ -1155,6 +1230,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) ...@@ -1155,6 +1230,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
return reg == 0x150 || reg == 0x153 || reg == 0x155 || return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
reg == 0x402 || reg == 0x402 ||
...@@ -1276,7 +1352,7 @@ static void nct6775_update_fan_div(struct nct6775_data *data) ...@@ -1276,7 +1352,7 @@ static void nct6775_update_fan_div(struct nct6775_data *data)
data->fan_div[1] = (i & 0x70) >> 4; data->fan_div[1] = (i & 0x70) >> 4;
i = nct6775_read_value(data, NCT6775_REG_FANDIV2); i = nct6775_read_value(data, NCT6775_REG_FANDIV2);
data->fan_div[2] = i & 0x7; data->fan_div[2] = i & 0x7;
if (data->has_fan & (1 << 3)) if (data->has_fan & BIT(3))
data->fan_div[3] = (i & 0x70) >> 4; data->fan_div[3] = (i & 0x70) >> 4;
} }
...@@ -1298,7 +1374,7 @@ static void nct6775_init_fan_div(struct nct6775_data *data) ...@@ -1298,7 +1374,7 @@ static void nct6775_init_fan_div(struct nct6775_data *data)
* We'll compute a better divider later on. * We'll compute a better divider later on.
*/ */
for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) { for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) {
if (!(data->has_fan & (1 << i))) if (!(data->has_fan & BIT(i)))
continue; continue;
if (data->fan_div[i] == 0) { if (data->fan_div[i] == 0) {
data->fan_div[i] = 7; data->fan_div[i] = 7;
...@@ -1321,7 +1397,7 @@ static void nct6775_init_fan_common(struct device *dev, ...@@ -1321,7 +1397,7 @@ static void nct6775_init_fan_common(struct device *dev,
* prevents the unnecessary warning when fanX_min is reported as 0. * prevents the unnecessary warning when fanX_min is reported as 0.
*/ */
for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
if (data->has_fan_min & (1 << i)) { if (data->has_fan_min & BIT(i)) {
reg = nct6775_read_value(data, data->REG_FAN_MIN[i]); reg = nct6775_read_value(data, data->REG_FAN_MIN[i]);
if (!reg) if (!reg)
nct6775_write_value(data, data->REG_FAN_MIN[i], nct6775_write_value(data, data->REG_FAN_MIN[i],
...@@ -1356,7 +1432,7 @@ static void nct6775_select_fan_div(struct device *dev, ...@@ -1356,7 +1432,7 @@ static void nct6775_select_fan_div(struct device *dev,
div_from_reg(fan_div)); div_from_reg(fan_div));
/* Preserve min limit if possible */ /* Preserve min limit if possible */
if (data->has_fan_min & (1 << nr)) { if (data->has_fan_min & BIT(nr)) {
fan_min = data->fan_min[nr]; fan_min = data->fan_min[nr];
if (fan_div > data->fan_div[nr]) { if (fan_div > data->fan_div[nr]) {
if (fan_min != 255 && fan_min > 1) if (fan_min != 255 && fan_min > 1)
...@@ -1387,7 +1463,7 @@ static void nct6775_update_pwm(struct device *dev) ...@@ -1387,7 +1463,7 @@ static void nct6775_update_pwm(struct device *dev)
bool duty_is_dc; bool duty_is_dc;
for (i = 0; i < data->pwm_num; i++) { for (i = 0; i < data->pwm_num; i++) {
if (!(data->has_pwm & (1 << i))) if (!(data->has_pwm & BIT(i)))
continue; continue;
duty_is_dc = data->REG_PWM_MODE[i] && duty_is_dc = data->REG_PWM_MODE[i] &&
...@@ -1457,7 +1533,7 @@ static void nct6775_update_pwm_limits(struct device *dev) ...@@ -1457,7 +1533,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
u16 reg_t; u16 reg_t;
for (i = 0; i < data->pwm_num; i++) { for (i = 0; i < data->pwm_num; i++) {
if (!(data->has_pwm & (1 << i))) if (!(data->has_pwm & BIT(i)))
continue; continue;
for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) { for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) {
...@@ -1507,6 +1583,7 @@ static void nct6775_update_pwm_limits(struct device *dev) ...@@ -1507,6 +1583,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]); data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK) if (reg & data->CRITICAL_PWM_ENABLE_MASK)
...@@ -1534,7 +1611,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) ...@@ -1534,7 +1611,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
/* Measured voltages and limits */ /* Measured voltages and limits */
for (i = 0; i < data->in_num; i++) { for (i = 0; i < data->in_num; i++) {
if (!(data->have_in & (1 << i))) if (!(data->have_in & BIT(i)))
continue; continue;
data->in[i][0] = nct6775_read_value(data, data->in[i][0] = nct6775_read_value(data,
...@@ -1549,14 +1626,14 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) ...@@ -1549,14 +1626,14 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { for (i = 0; i < ARRAY_SIZE(data->rpm); i++) {
u16 reg; u16 reg;
if (!(data->has_fan & (1 << i))) if (!(data->has_fan & BIT(i)))
continue; continue;
reg = nct6775_read_value(data, data->REG_FAN[i]); reg = nct6775_read_value(data, data->REG_FAN[i]);
data->rpm[i] = data->fan_from_reg(reg, data->rpm[i] = data->fan_from_reg(reg,
data->fan_div[i]); data->fan_div[i]);
if (data->has_fan_min & (1 << i)) if (data->has_fan_min & BIT(i))
data->fan_min[i] = nct6775_read_value(data, data->fan_min[i] = nct6775_read_value(data,
data->REG_FAN_MIN[i]); data->REG_FAN_MIN[i]);
data->fan_pulses[i] = data->fan_pulses[i] =
...@@ -1571,7 +1648,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) ...@@ -1571,7 +1648,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
/* Measured temperatures and limits */ /* Measured temperatures and limits */
for (i = 0; i < NUM_TEMP; i++) { for (i = 0; i < NUM_TEMP; i++) {
if (!(data->have_temp & (1 << i))) if (!(data->have_temp & BIT(i)))
continue; continue;
for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) { for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) {
if (data->reg_temp[j][i]) if (data->reg_temp[j][i])
...@@ -1580,7 +1657,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) ...@@ -1580,7 +1657,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->reg_temp[j][i]); data->reg_temp[j][i]);
} }
if (i >= NUM_TEMP_FIXED || if (i >= NUM_TEMP_FIXED ||
!(data->have_temp_fixed & (1 << i))) !(data->have_temp_fixed & BIT(i)))
continue; continue;
data->temp_offset[i] data->temp_offset[i]
= nct6775_read_value(data, data->REG_TEMP_OFFSET[i]); = nct6775_read_value(data, data->REG_TEMP_OFFSET[i]);
...@@ -1801,7 +1878,7 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj, ...@@ -1801,7 +1878,7 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj,
struct nct6775_data *data = dev_get_drvdata(dev); struct nct6775_data *data = dev_get_drvdata(dev);
int in = index / 5; /* voltage index */ int in = index / 5; /* voltage index */
if (!(data->have_in & (1 << in))) if (!(data->have_in & BIT(in)))
return 0; return 0;
return attr->mode; return attr->mode;
...@@ -1911,7 +1988,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, ...@@ -1911,7 +1988,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
* even with the highest divider (128) * even with the highest divider (128)
*/ */
data->fan_min[nr] = 254; data->fan_min[nr] = 254;
new_div = 7; /* 128 == (1 << 7) */ new_div = 7; /* 128 == BIT(7) */
dev_warn(dev, dev_warn(dev,
"fan%u low limit %lu below minimum %u, set to minimum\n", "fan%u low limit %lu below minimum %u, set to minimum\n",
nr + 1, val, data->fan_from_reg_min(254, 7)); nr + 1, val, data->fan_from_reg_min(254, 7));
...@@ -1921,7 +1998,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, ...@@ -1921,7 +1998,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
* even with the lowest divider (1) * even with the lowest divider (1)
*/ */
data->fan_min[nr] = 1; data->fan_min[nr] = 1;
new_div = 0; /* 1 == (1 << 0) */ new_div = 0; /* 1 == BIT(0) */
dev_warn(dev, dev_warn(dev,
"fan%u low limit %lu above maximum %u, set to maximum\n", "fan%u low limit %lu above maximum %u, set to maximum\n",
nr + 1, val, data->fan_from_reg_min(1, 0)); nr + 1, val, data->fan_from_reg_min(1, 0));
...@@ -2008,14 +2085,14 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj, ...@@ -2008,14 +2085,14 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj,
int fan = index / 6; /* fan index */ int fan = index / 6; /* fan index */
int nr = index % 6; /* attribute index */ int nr = index % 6; /* attribute index */
if (!(data->has_fan & (1 << fan))) if (!(data->has_fan & BIT(fan)))
return 0; return 0;
if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1) if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1)
return 0; return 0;
if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1) if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1)
return 0; return 0;
if (nr == 4 && !(data->has_fan_min & (1 << fan))) if (nr == 4 && !(data->has_fan_min & BIT(fan)))
return 0; return 0;
if (nr == 5 && data->kind != nct6775) if (nr == 5 && data->kind != nct6775)
return 0; return 0;
...@@ -2193,7 +2270,10 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj, ...@@ -2193,7 +2270,10 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj,
int temp = index / 10; /* temp index */ int temp = index / 10; /* temp index */
int nr = index % 10; /* attribute index */ int nr = index % 10; /* attribute index */
if (!(data->have_temp & (1 << temp))) if (!(data->have_temp & BIT(temp)))
return 0;
if (nr == 1 && !data->temp_label)
return 0; return 0;
if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0) if (nr == 2 && find_temp_source(data, temp, data->num_temp_alarms) < 0)
...@@ -2215,7 +2295,7 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj, ...@@ -2215,7 +2295,7 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj,
return 0; return 0;
/* offset and type only apply to fixed sensors */ /* offset and type only apply to fixed sensors */
if (nr > 7 && !(data->have_temp_fixed & (1 << temp))) if (nr > 7 && !(data->have_temp_fixed & BIT(temp)))
return 0; return 0;
return attr->mode; return attr->mode;
...@@ -2484,7 +2564,7 @@ show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src) ...@@ -2484,7 +2564,7 @@ show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src)
int i, sel = 0; int i, sel = 0;
for (i = 0; i < NUM_TEMP; i++) { for (i = 0; i < NUM_TEMP; i++) {
if (!(data->have_temp & (1 << i))) if (!(data->have_temp & BIT(i)))
continue; continue;
if (src == data->temp_src[i]) { if (src == data->temp_src[i]) {
sel = i + 1; sel = i + 1;
...@@ -2520,7 +2600,7 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, ...@@ -2520,7 +2600,7 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr,
return err; return err;
if (val == 0 || val > NUM_TEMP) if (val == 0 || val > NUM_TEMP)
return -EINVAL; return -EINVAL;
if (!(data->have_temp & (1 << (val - 1))) || !data->temp_src[val - 1]) if (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
...@@ -2562,7 +2642,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, ...@@ -2562,7 +2642,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr,
return err; return err;
if (val > NUM_TEMP) if (val > NUM_TEMP)
return -EINVAL; return -EINVAL;
if (val && (!(data->have_temp & (1 << (val - 1))) || if (val && (!(data->have_temp & BIT(val - 1)) ||
!data->temp_src[val - 1])) !data->temp_src[val - 1]))
return -EINVAL; return -EINVAL;
...@@ -2923,6 +3003,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, ...@@ -2923,6 +3003,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val); val);
reg = nct6775_read_value(data, reg = nct6775_read_value(data,
...@@ -2995,7 +3076,7 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj, ...@@ -2995,7 +3076,7 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj,
int pwm = index / 36; /* pwm index */ int pwm = index / 36; /* pwm index */
int nr = index % 36; /* attribute index */ int nr = index % 36; /* attribute index */
if (!(data->has_pwm & (1 << pwm))) if (!(data->has_pwm & BIT(pwm)))
return 0; return 0;
if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */ if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */
...@@ -3246,7 +3327,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) ...@@ -3246,7 +3327,7 @@ static inline void nct6775_init_device(struct nct6775_data *data)
/* Enable temperature sensors if needed */ /* Enable temperature sensors if needed */
for (i = 0; i < NUM_TEMP; i++) { for (i = 0; i < NUM_TEMP; i++) {
if (!(data->have_temp & (1 << i))) if (!(data->have_temp & BIT(i)))
continue; continue;
if (!data->reg_temp_config[i]) if (!data->reg_temp_config[i])
continue; continue;
...@@ -3264,7 +3345,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) ...@@ -3264,7 +3345,7 @@ static inline void nct6775_init_device(struct nct6775_data *data)
diode = nct6775_read_value(data, data->REG_DIODE); diode = nct6775_read_value(data, data->REG_DIODE);
for (i = 0; i < data->temp_fixed_num; i++) { for (i = 0; i < data->temp_fixed_num; i++) {
if (!(data->have_temp_fixed & (1 << i))) if (!(data->have_temp_fixed & BIT(i)))
continue; continue;
if ((tmp & (data->DIODE_MASK << i))) /* diode */ if ((tmp & (data->DIODE_MASK << i))) /* diode */
data->temp_type[i] data->temp_type[i]
...@@ -3290,8 +3371,8 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3290,8 +3371,8 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
if (data->kind == nct6775) { if (data->kind == nct6775) {
regval = superio_inb(sioreg, 0x2c); regval = superio_inb(sioreg, 0x2c);
fan3pin = regval & (1 << 6); fan3pin = regval & BIT(6);
pwm3pin = regval & (1 << 7); pwm3pin = regval & BIT(7);
/* On NCT6775, fan4 shares pins with the fdc interface */ /* On NCT6775, fan4 shares pins with the fdc interface */
fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80);
...@@ -3357,28 +3438,57 @@ nct6775_check_fan_inputs(struct nct6775_data *data) ...@@ -3357,28 +3438,57 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
pwm4pin = false; pwm4pin = false;
pwm5pin = false; pwm5pin = false;
pwm6pin = false; pwm6pin = false;
} else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */ } else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */
regval = superio_inb(sioreg, 0x1c); int regval_1b, regval_2a, regval_eb;
fan3pin = !(regval & (1 << 5)); regval = superio_inb(sioreg, 0x1c);
fan4pin = !(regval & (1 << 6));
fan5pin = !(regval & (1 << 7));
pwm3pin = !(regval & (1 << 0)); fan3pin = !(regval & BIT(5));
pwm4pin = !(regval & (1 << 1)); fan4pin = !(regval & BIT(6));
pwm5pin = !(regval & (1 << 2)); fan5pin = !(regval & BIT(7));
fan4min = fan4pin; pwm3pin = !(regval & BIT(0));
pwm4pin = !(regval & BIT(1));
pwm5pin = !(regval & BIT(2));
if (data->kind == nct6791 || data->kind == nct6792 || regval = superio_inb(sioreg, 0x2d);
data->kind == nct6793) { switch (data->kind) {
regval = superio_inb(sioreg, 0x2d); case nct6791:
fan6pin = (regval & (1 << 1)); case nct6792:
pwm6pin = (regval & (1 << 0)); fan6pin = regval & BIT(1);
} else { /* NCT6779D */ pwm6pin = regval & BIT(0);
break;
case nct6793:
case nct6795:
regval_1b = superio_inb(sioreg, 0x1b);
regval_2a = superio_inb(sioreg, 0x2a);
if (!pwm5pin)
pwm5pin = regval & BIT(7);
fan6pin = regval & BIT(1);
pwm6pin = regval & BIT(0);
if (!fan5pin)
fan5pin = regval_1b & BIT(5);
superio_select(sioreg, NCT6775_LD_12);
regval_eb = superio_inb(sioreg, 0xeb);
if (!fan5pin)
fan5pin = regval_eb & BIT(5);
if (!pwm5pin)
pwm5pin = (regval_eb & BIT(4)) &&
!(regval_2a & BIT(0));
if (!fan6pin)
fan6pin = regval_eb & BIT(3);
if (!pwm6pin)
pwm6pin = regval_eb & BIT(2);
break;
default: /* NCT6779D */
fan6pin = false; fan6pin = false;
pwm6pin = false; pwm6pin = false;
break;
} }
fan4min = fan4pin;
} }
/* fan 1 and 2 (0x03) are always present */ /* fan 1 and 2 (0x03) are always present */
...@@ -3403,16 +3513,15 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, ...@@ -3403,16 +3513,15 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp,
continue; continue;
src = nct6775_read_value(data, regp[i]); src = nct6775_read_value(data, regp[i]);
src &= 0x1f; src &= 0x1f;
if (!src || (*mask & (1 << src))) if (!src || (*mask & BIT(src)))
continue; continue;
if (src >= data->temp_label_num || if (!(data->temp_mask & BIT(src)))
!strlen(data->temp_label[src]))
continue; continue;
index = __ffs(*available); index = __ffs(*available);
nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src); nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src);
*available &= ~(1 << index); *available &= ~BIT(index);
*mask |= 1 << src; *mask |= BIT(src);
} }
} }
...@@ -3464,7 +3573,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3464,7 +3573,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->fan_from_reg_min = fan_from_reg13; data->fan_from_reg_min = fan_from_reg13;
data->temp_label = nct6776_temp_label; data->temp_label = nct6776_temp_label;
data->temp_label_num = ARRAY_SIZE(nct6776_temp_label); data->temp_mask = NCT6776_TEMP_MASK;
data->REG_VBAT = NCT6106_REG_VBAT; data->REG_VBAT = NCT6106_REG_VBAT;
data->REG_DIODE = NCT6106_REG_DIODE; data->REG_DIODE = NCT6106_REG_DIODE;
...@@ -3542,7 +3651,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3542,7 +3651,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->speed_tolerance_limit = 15; data->speed_tolerance_limit = 15;
data->temp_label = nct6775_temp_label; data->temp_label = nct6775_temp_label;
data->temp_label_num = ARRAY_SIZE(nct6775_temp_label); data->temp_mask = NCT6775_TEMP_MASK;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
...@@ -3614,7 +3723,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3614,7 +3723,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->speed_tolerance_limit = 63; data->speed_tolerance_limit = 63;
data->temp_label = nct6776_temp_label; data->temp_label = nct6776_temp_label;
data->temp_label_num = ARRAY_SIZE(nct6776_temp_label); data->temp_mask = NCT6776_TEMP_MASK;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
...@@ -3686,7 +3795,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3686,7 +3795,7 @@ static int nct6775_probe(struct platform_device *pdev)
data->speed_tolerance_limit = 63; data->speed_tolerance_limit = 63;
data->temp_label = nct6779_temp_label; data->temp_label = nct6779_temp_label;
data->temp_label_num = NCT6779_NUM_LABELS; data->temp_mask = NCT6779_TEMP_MASK;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
...@@ -3746,6 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3746,6 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
data->in_num = 15; data->in_num = 15;
data->pwm_num = 6; data->pwm_num = 6;
data->auto_pwm_num = 4; data->auto_pwm_num = 4;
...@@ -3767,15 +3877,21 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3767,15 +3877,21 @@ static int nct6775_probe(struct platform_device *pdev)
default: default:
case nct6791: case nct6791:
data->temp_label = nct6779_temp_label; data->temp_label = nct6779_temp_label;
data->temp_mask = NCT6791_TEMP_MASK;
break; break;
case nct6792: case nct6792:
data->temp_label = nct6792_temp_label; data->temp_label = nct6792_temp_label;
data->temp_mask = NCT6792_TEMP_MASK;
break; break;
case nct6793: case nct6793:
data->temp_label = nct6793_temp_label; data->temp_label = nct6793_temp_label;
data->temp_mask = NCT6793_TEMP_MASK;
break;
case nct6795:
data->temp_label = nct6795_temp_label;
data->temp_mask = NCT6795_TEMP_MASK;
break; break;
} }
data->temp_label_num = NCT6791_NUM_LABELS;
data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_CONFIG = NCT6775_REG_CONFIG;
data->REG_VBAT = NCT6775_REG_VBAT; data->REG_VBAT = NCT6775_REG_VBAT;
...@@ -3843,7 +3959,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3843,7 +3959,7 @@ static int nct6775_probe(struct platform_device *pdev)
default: default:
return -ENODEV; return -ENODEV;
} }
data->have_in = (1 << data->in_num) - 1; data->have_in = BIT(data->in_num) - 1;
data->have_temp = 0; data->have_temp = 0;
/* /*
...@@ -3861,10 +3977,10 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3861,10 +3977,10 @@ static int nct6775_probe(struct platform_device *pdev)
continue; continue;
src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
if (!src || (mask & (1 << src))) if (!src || (mask & BIT(src)))
available |= 1 << i; available |= BIT(i);
mask |= 1 << src; mask |= BIT(src);
} }
/* /*
...@@ -3881,23 +3997,22 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3881,23 +3997,22 @@ static int nct6775_probe(struct platform_device *pdev)
continue; continue;
src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f;
if (!src || (mask & (1 << src))) if (!src || (mask & BIT(src)))
continue; continue;
if (src >= data->temp_label_num || if (!(data->temp_mask & BIT(src))) {
!strlen(data->temp_label[src])) {
dev_info(dev, dev_info(dev,
"Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]); src, i, data->REG_TEMP_SOURCE[i], reg_temp[i]);
continue; continue;
} }
mask |= 1 << src; mask |= BIT(src);
/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
if (src <= data->temp_fixed_num) { if (src <= data->temp_fixed_num) {
data->have_temp |= 1 << (src - 1); data->have_temp |= BIT(src - 1);
data->have_temp_fixed |= 1 << (src - 1); data->have_temp_fixed |= BIT(src - 1);
data->reg_temp[0][src - 1] = reg_temp[i]; data->reg_temp[0][src - 1] = reg_temp[i];
data->reg_temp[1][src - 1] = reg_temp_over[i]; data->reg_temp[1][src - 1] = reg_temp_over[i];
data->reg_temp[2][src - 1] = reg_temp_hyst[i]; data->reg_temp[2][src - 1] = reg_temp_hyst[i];
...@@ -3917,7 +4032,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3917,7 +4032,7 @@ static int nct6775_probe(struct platform_device *pdev)
continue; continue;
/* Use dynamic index for other sources */ /* Use dynamic index for other sources */
data->have_temp |= 1 << s; data->have_temp |= BIT(s);
data->reg_temp[0][s] = reg_temp[i]; data->reg_temp[0][s] = reg_temp[i];
data->reg_temp[1][s] = reg_temp_over[i]; data->reg_temp[1][s] = reg_temp_over[i];
data->reg_temp[2][s] = reg_temp_hyst[i]; data->reg_temp[2][s] = reg_temp_hyst[i];
...@@ -3945,8 +4060,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3945,8 +4060,7 @@ static int nct6775_probe(struct platform_device *pdev)
if (!src) if (!src)
continue; continue;
if (src >= data->temp_label_num || if (!(data->temp_mask & BIT(src))) {
!strlen(data->temp_label[src])) {
dev_info(dev, dev_info(dev,
"Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n",
src, i, data->REG_TEMP_SEL[i], src, i, data->REG_TEMP_SEL[i],
...@@ -3960,17 +4074,17 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3960,17 +4074,17 @@ static int nct6775_probe(struct platform_device *pdev)
* are no duplicates. * are no duplicates.
*/ */
if (src != TEMP_SOURCE_VIRTUAL) { if (src != TEMP_SOURCE_VIRTUAL) {
if (mask & (1 << src)) if (mask & BIT(src))
continue; continue;
mask |= 1 << src; mask |= BIT(src);
} }
/* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */
if (src <= data->temp_fixed_num) { if (src <= data->temp_fixed_num) {
if (data->have_temp & (1 << (src - 1))) if (data->have_temp & BIT(src - 1))
continue; continue;
data->have_temp |= 1 << (src - 1); data->have_temp |= BIT(src - 1);
data->have_temp_fixed |= 1 << (src - 1); data->have_temp_fixed |= BIT(src - 1);
data->reg_temp[0][src - 1] = reg_temp_mon[i]; data->reg_temp[0][src - 1] = reg_temp_mon[i];
data->temp_src[src - 1] = src; data->temp_src[src - 1] = src;
continue; continue;
...@@ -3980,7 +4094,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3980,7 +4094,7 @@ static int nct6775_probe(struct platform_device *pdev)
continue; continue;
/* Use dynamic index for other sources */ /* Use dynamic index for other sources */
data->have_temp |= 1 << s; data->have_temp |= BIT(s);
data->reg_temp[0][s] = reg_temp_mon[i]; data->reg_temp[0][s] = reg_temp_mon[i];
data->temp_src[s] = src; data->temp_src[s] = src;
s++; s++;
...@@ -3993,16 +4107,18 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -3993,16 +4107,18 @@ static int nct6775_probe(struct platform_device *pdev)
* The temperature is already monitored if the respective bit in <mask> * The temperature is already monitored if the respective bit in <mask>
* is set. * is set.
*/ */
for (i = 0; i < data->temp_label_num - 1; i++) { for (i = 0; i < 32; i++) {
if (!(data->temp_mask & BIT(i + 1)))
continue;
if (!reg_temp_alternate[i]) if (!reg_temp_alternate[i])
continue; continue;
if (mask & (1 << (i + 1))) if (mask & BIT(i + 1))
continue; continue;
if (i < data->temp_fixed_num) { if (i < data->temp_fixed_num) {
if (data->have_temp & (1 << i)) if (data->have_temp & BIT(i))
continue; continue;
data->have_temp |= 1 << i; data->have_temp |= BIT(i);
data->have_temp_fixed |= 1 << i; data->have_temp_fixed |= BIT(i);
data->reg_temp[0][i] = reg_temp_alternate[i]; data->reg_temp[0][i] = reg_temp_alternate[i];
if (i < num_reg_temp) { if (i < num_reg_temp) {
data->reg_temp[1][i] = reg_temp_over[i]; data->reg_temp[1][i] = reg_temp_over[i];
...@@ -4015,7 +4131,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4015,7 +4131,7 @@ static int nct6775_probe(struct platform_device *pdev)
if (s >= NUM_TEMP) /* Abort if no more space */ if (s >= NUM_TEMP) /* Abort if no more space */
break; break;
data->have_temp |= 1 << s; data->have_temp |= BIT(s);
data->reg_temp[0][s] = reg_temp_alternate[i]; data->reg_temp[0][s] = reg_temp_alternate[i];
data->temp_src[s] = i + 1; data->temp_src[s] = i + 1;
s++; s++;
...@@ -4042,6 +4158,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4042,6 +4158,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
break; break;
} }
...@@ -4075,6 +4192,7 @@ static int nct6775_probe(struct platform_device *pdev) ...@@ -4075,6 +4192,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6791: case nct6791:
case nct6792: case nct6792:
case nct6793: case nct6793:
case nct6795:
tmp |= 0x7e; tmp |= 0x7e;
break; break;
} }
...@@ -4173,14 +4291,14 @@ static int __maybe_unused nct6775_resume(struct device *dev) ...@@ -4173,14 +4291,14 @@ static int __maybe_unused nct6775_resume(struct device *dev)
superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable); superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable);
if (data->kind == nct6791 || data->kind == nct6792 || if (data->kind == nct6791 || data->kind == nct6792 ||
data->kind == nct6793) data->kind == nct6793 || data->kind == nct6795)
nct6791_enable_io_mapping(sioreg); nct6791_enable_io_mapping(sioreg);
superio_exit(sioreg); superio_exit(sioreg);
/* Restore limits */ /* Restore limits */
for (i = 0; i < data->in_num; i++) { for (i = 0; i < data->in_num; i++) {
if (!(data->have_in & (1 << i))) if (!(data->have_in & BIT(i)))
continue; continue;
nct6775_write_value(data, data->REG_IN_MINMAX[0][i], nct6775_write_value(data, data->REG_IN_MINMAX[0][i],
...@@ -4190,7 +4308,7 @@ static int __maybe_unused nct6775_resume(struct device *dev) ...@@ -4190,7 +4308,7 @@ static int __maybe_unused nct6775_resume(struct device *dev)
} }
for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) { for (i = 0; i < ARRAY_SIZE(data->fan_min); i++) {
if (!(data->has_fan_min & (1 << i))) if (!(data->has_fan_min & BIT(i)))
continue; continue;
nct6775_write_value(data, data->REG_FAN_MIN[i], nct6775_write_value(data, data->REG_FAN_MIN[i],
...@@ -4198,7 +4316,7 @@ static int __maybe_unused nct6775_resume(struct device *dev) ...@@ -4198,7 +4316,7 @@ static int __maybe_unused nct6775_resume(struct device *dev)
} }
for (i = 0; i < NUM_TEMP; i++) { for (i = 0; i < NUM_TEMP; i++) {
if (!(data->have_temp & (1 << i))) if (!(data->have_temp & BIT(i)))
continue; continue;
for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++) for (j = 1; j < ARRAY_SIZE(data->reg_temp); j++)
...@@ -4270,6 +4388,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) ...@@ -4270,6 +4388,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6793_ID: case SIO_NCT6793_ID:
sio_data->kind = nct6793; sio_data->kind = nct6793;
break; break;
case SIO_NCT6795_ID:
sio_data->kind = nct6795;
break;
default: default:
if (val != 0xffff) if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val); pr_debug("unsupported chip ID: 0x%04x\n", val);
...@@ -4296,7 +4417,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data) ...@@ -4296,7 +4417,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
} }
if (sio_data->kind == nct6791 || sio_data->kind == nct6792 || if (sio_data->kind == nct6791 || sio_data->kind == nct6792 ||
sio_data->kind == nct6793) sio_data->kind == nct6793 || sio_data->kind == nct6795)
nct6791_enable_io_mapping(sioaddr); nct6791_enable_io_mapping(sioaddr);
superio_exit(sioaddr); superio_exit(sioaddr);
......
...@@ -37,6 +37,16 @@ config SENSORS_ADM1275 ...@@ -37,6 +37,16 @@ config SENSORS_ADM1275
This driver can also be built as a module. If so, the module will This driver can also be built as a module. If so, the module will
be called adm1275. be called adm1275.
config SENSORS_IR35221
tristate "Infineon IR35221"
default n
help
If you say yes here you get hardware monitoring support for the
Infineon IR35221 controller.
This driver can also be built as a module. If so, the module will
be called ir35521.
config SENSORS_LM25066 config SENSORS_LM25066
tristate "National Semiconductor LM25066 and compatibles" tristate "National Semiconductor LM25066 and compatibles"
default n default n
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_IR35221) += ir35221.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
......
/*
* Hardware monitoring driver for IR35221
*
* Copyright (C) IBM Corporation 2017.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include "pmbus.h"
#define IR35221_MFR_VIN_PEAK 0xc5
#define IR35221_MFR_VOUT_PEAK 0xc6
#define IR35221_MFR_IOUT_PEAK 0xc7
#define IR35221_MFR_TEMP_PEAK 0xc8
#define IR35221_MFR_VIN_VALLEY 0xc9
#define IR35221_MFR_VOUT_VALLEY 0xca
#define IR35221_MFR_IOUT_VALLEY 0xcb
#define IR35221_MFR_TEMP_VALLEY 0xcc
static long ir35221_reg2data(int data, enum pmbus_sensor_classes class)
{
s16 exponent;
s32 mantissa;
long val;
/* We only modify LINEAR11 formats */
exponent = ((s16)data) >> 11;
mantissa = ((s16)((data & 0x7ff) << 5)) >> 5;
val = mantissa * 1000L;
/* scale result to micro-units for power sensors */
if (class == PSC_POWER)
val = val * 1000L;
if (exponent >= 0)
val <<= exponent;
else
val >>= -exponent;
return val;
}
#define MAX_MANTISSA (1023 * 1000)
#define MIN_MANTISSA (511 * 1000)
static u16 ir35221_data2reg(long val, enum pmbus_sensor_classes class)
{
s16 exponent = 0, mantissa;
bool negative = false;
if (val == 0)
return 0;
if (val < 0) {
negative = true;
val = -val;
}
/* Power is in uW. Convert to mW before converting. */
if (class == PSC_POWER)
val = DIV_ROUND_CLOSEST(val, 1000L);
/* Reduce large mantissa until it fits into 10 bit */
while (val >= MAX_MANTISSA && exponent < 15) {
exponent++;
val >>= 1;
}
/* Increase small mantissa to improve precision */
while (val < MIN_MANTISSA && exponent > -15) {
exponent--;
val <<= 1;
}
/* Convert mantissa from milli-units to units */
mantissa = DIV_ROUND_CLOSEST(val, 1000);
/* Ensure that resulting number is within range */
if (mantissa > 0x3ff)
mantissa = 0x3ff;
/* restore sign */
if (negative)
mantissa = -mantissa;
/* Convert to 5 bit exponent, 11 bit mantissa */
return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800);
}
static u16 ir35221_scale_result(s16 data, int shift,
enum pmbus_sensor_classes class)
{
long val;
val = ir35221_reg2data(data, class);
if (shift < 0)
val >>= -shift;
else
val <<= shift;
return ir35221_data2reg(val, class);
}
static int ir35221_read_word_data(struct i2c_client *client, int page, int reg)
{
int ret;
switch (reg) {
case PMBUS_IOUT_OC_FAULT_LIMIT:
case PMBUS_IOUT_OC_WARN_LIMIT:
ret = pmbus_read_word_data(client, page, reg);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, 1, PSC_CURRENT_OUT);
break;
case PMBUS_VIN_OV_FAULT_LIMIT:
case PMBUS_VIN_OV_WARN_LIMIT:
case PMBUS_VIN_UV_WARN_LIMIT:
ret = pmbus_read_word_data(client, page, reg);
ret = ir35221_scale_result(ret, -4, PSC_VOLTAGE_IN);
break;
case PMBUS_IIN_OC_WARN_LIMIT:
ret = pmbus_read_word_data(client, page, reg);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
break;
case PMBUS_READ_VIN:
ret = pmbus_read_word_data(client, page, PMBUS_READ_VIN);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
break;
case PMBUS_READ_IIN:
ret = pmbus_read_word_data(client, page, PMBUS_READ_IIN);
if (ret < 0)
break;
if (page == 0)
ret = ir35221_scale_result(ret, -4, PSC_CURRENT_IN);
else
ret = ir35221_scale_result(ret, -5, PSC_CURRENT_IN);
break;
case PMBUS_READ_POUT:
ret = pmbus_read_word_data(client, page, PMBUS_READ_POUT);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -1, PSC_POWER);
break;
case PMBUS_READ_PIN:
ret = pmbus_read_word_data(client, page, PMBUS_READ_PIN);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -1, PSC_POWER);
break;
case PMBUS_READ_IOUT:
ret = pmbus_read_word_data(client, page, PMBUS_READ_IOUT);
if (ret < 0)
break;
if (page == 0)
ret = ir35221_scale_result(ret, -1, PSC_CURRENT_OUT);
else
ret = ir35221_scale_result(ret, -2, PSC_CURRENT_OUT);
break;
case PMBUS_VIRT_READ_VIN_MAX:
ret = pmbus_read_word_data(client, page, IR35221_MFR_VIN_PEAK);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
break;
case PMBUS_VIRT_READ_VOUT_MAX:
ret = pmbus_read_word_data(client, page, IR35221_MFR_VOUT_PEAK);
break;
case PMBUS_VIRT_READ_IOUT_MAX:
ret = pmbus_read_word_data(client, page, IR35221_MFR_IOUT_PEAK);
if (ret < 0)
break;
if (page == 0)
ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
else
ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
break;
case PMBUS_VIRT_READ_TEMP_MAX:
ret = pmbus_read_word_data(client, page, IR35221_MFR_TEMP_PEAK);
break;
case PMBUS_VIRT_READ_VIN_MIN:
ret = pmbus_read_word_data(client, page,
IR35221_MFR_VIN_VALLEY);
if (ret < 0)
break;
ret = ir35221_scale_result(ret, -5, PSC_VOLTAGE_IN);
break;
case PMBUS_VIRT_READ_VOUT_MIN:
ret = pmbus_read_word_data(client, page,
IR35221_MFR_VOUT_VALLEY);
break;
case PMBUS_VIRT_READ_IOUT_MIN:
ret = pmbus_read_word_data(client, page,
IR35221_MFR_IOUT_VALLEY);
if (ret < 0)
break;
if (page == 0)
ret = ir35221_scale_result(ret, -1, PSC_CURRENT_IN);
else
ret = ir35221_scale_result(ret, -2, PSC_CURRENT_IN);
break;
case PMBUS_VIRT_READ_TEMP_MIN:
ret = pmbus_read_word_data(client, page,
IR35221_MFR_TEMP_VALLEY);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int ir35221_write_word_data(struct i2c_client *client, int page, int reg,
u16 word)
{
int ret;
u16 val;
switch (reg) {
case PMBUS_IOUT_OC_FAULT_LIMIT:
case PMBUS_IOUT_OC_WARN_LIMIT:
val = ir35221_scale_result(word, -1, PSC_CURRENT_OUT);
ret = pmbus_write_word_data(client, page, reg, val);
break;
case PMBUS_VIN_OV_FAULT_LIMIT:
case PMBUS_VIN_OV_WARN_LIMIT:
case PMBUS_VIN_UV_WARN_LIMIT:
val = ir35221_scale_result(word, 4, PSC_VOLTAGE_IN);
ret = pmbus_write_word_data(client, page, reg, val);
break;
case PMBUS_IIN_OC_WARN_LIMIT:
val = ir35221_scale_result(word, 1, PSC_CURRENT_IN);
ret = pmbus_write_word_data(client, page, reg, val);
break;
default:
ret = -ENODATA;
break;
}
return ret;
}
static int ir35221_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pmbus_driver_info *info;
u8 buf[I2C_SMBUS_BLOCK_MAX];
int ret;
if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_READ_BYTE_DATA
| I2C_FUNC_SMBUS_READ_WORD_DATA
| I2C_FUNC_SMBUS_READ_BLOCK_DATA))
return -ENODEV;
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf);
if (ret < 0) {
dev_err(&client->dev, "Failed to read PMBUS_MFR_ID\n");
return ret;
}
if (ret != 2 || strncmp(buf, "RI", strlen("RI"))) {
dev_err(&client->dev, "MFR_ID unrecognised\n");
return -ENODEV;
}
ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, buf);
if (ret < 0) {
dev_err(&client->dev, "Failed to read PMBUS_MFR_MODEL\n");
return ret;
}
if (ret != 2 || !(buf[0] == 0x6c && buf[1] == 0x00)) {
dev_err(&client->dev, "MFR_MODEL unrecognised\n");
return -ENODEV;
}
info = devm_kzalloc(&client->dev, sizeof(struct pmbus_driver_info),
GFP_KERNEL);
if (!info)
return -ENOMEM;
info->write_word_data = ir35221_write_word_data;
info->read_word_data = ir35221_read_word_data;
info->pages = 2;
info->format[PSC_VOLTAGE_IN] = linear;
info->format[PSC_VOLTAGE_OUT] = linear;
info->format[PSC_CURRENT_IN] = linear;
info->format[PSC_CURRENT_OUT] = linear;
info->format[PSC_POWER] = linear;
info->format[PSC_TEMPERATURE] = linear;
info->func[0] = PMBUS_HAVE_VIN
| PMBUS_HAVE_VOUT | PMBUS_HAVE_IIN
| PMBUS_HAVE_IOUT | PMBUS_HAVE_PIN
| PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_STATUS_TEMP;
info->func[1] = info->func[0];
return pmbus_do_probe(client, id, info);
}
static const struct i2c_device_id ir35221_id[] = {
{"ir35221", 0},
{}
};
MODULE_DEVICE_TABLE(i2c, ir35221_id);
static struct i2c_driver ir35221_driver = {
.driver = {
.name = "ir35221",
},
.probe = ir35221_probe,
.remove = pmbus_do_remove,
.id_table = ir35221_id,
};
module_i2c_driver(ir35221_driver);
MODULE_AUTHOR("Samuel Mendoza-Jonas <sam@mendozajonas.com");
MODULE_DESCRIPTION("PMBus driver for IR35221");
MODULE_LICENSE("GPL");
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/pmbus.h> #include <linux/pmbus.h>
#include "pmbus.h" #include "pmbus.h"
/* /*
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h> #include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/i2c/pmbus.h> #include <linux/pmbus.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include "pmbus.h" #include "pmbus.h"
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/pmbus.h> #include <linux/pmbus.h>
#include "pmbus.h" #include "pmbus.h"
enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 };
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/pmbus.h> #include <linux/pmbus.h>
#include "pmbus.h" #include "pmbus.h"
#define UCD9200_PHASE_INFO 0xd2 #define UCD9200_PHASE_INFO 0xd2
......
...@@ -40,31 +40,22 @@ struct pwm_fan_ctx { ...@@ -40,31 +40,22 @@ struct pwm_fan_ctx {
static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm)
{ {
struct pwm_args pargs; unsigned long period;
unsigned long duty;
int ret = 0; int ret = 0;
struct pwm_state state = { };
pwm_get_args(ctx->pwm, &pargs);
mutex_lock(&ctx->lock); mutex_lock(&ctx->lock);
if (ctx->pwm_value == pwm) if (ctx->pwm_value == pwm)
goto exit_set_pwm_err; goto exit_set_pwm_err;
duty = DIV_ROUND_UP(pwm * (pargs.period - 1), MAX_PWM); pwm_init_state(ctx->pwm, &state);
ret = pwm_config(ctx->pwm, duty, pargs.period); period = ctx->pwm->args.period;
if (ret) state.duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM);
goto exit_set_pwm_err; state.enabled = pwm ? true : false;
if (pwm == 0)
pwm_disable(ctx->pwm);
if (ctx->pwm_value == 0) {
ret = pwm_enable(ctx->pwm);
if (ret)
goto exit_set_pwm_err;
}
ctx->pwm_value = pwm; ret = pwm_apply_state(ctx->pwm, &state);
if (!ret)
ctx->pwm_value = pwm;
exit_set_pwm_err: exit_set_pwm_err:
mutex_unlock(&ctx->lock); mutex_unlock(&ctx->lock);
return ret; return ret;
...@@ -218,10 +209,9 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -218,10 +209,9 @@ static int pwm_fan_probe(struct platform_device *pdev)
{ {
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
struct pwm_fan_ctx *ctx; struct pwm_fan_ctx *ctx;
struct pwm_args pargs;
struct device *hwmon; struct device *hwmon;
int duty_cycle;
int ret; int ret;
struct pwm_state state = { };
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
...@@ -237,28 +227,16 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -237,28 +227,16 @@ static int pwm_fan_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
/*
* FIXME: pwm_apply_args() should be removed when switching to the
* atomic PWM API.
*/
pwm_apply_args(ctx->pwm);
/* Set duty cycle to maximum allowed */
pwm_get_args(ctx->pwm, &pargs);
duty_cycle = pargs.period - 1;
ctx->pwm_value = MAX_PWM; ctx->pwm_value = MAX_PWM;
ret = pwm_config(ctx->pwm, duty_cycle, pargs.period); /* Set duty cycle to maximum allowed and enable PWM output */
if (ret) { pwm_init_state(ctx->pwm, &state);
dev_err(&pdev->dev, "Failed to configure PWM\n"); state.duty_cycle = ctx->pwm->args.period - 1;
return ret; state.enabled = true;
}
/* Enbale PWM output */ ret = pwm_apply_state(ctx->pwm, &state);
ret = pwm_enable(ctx->pwm);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to enable PWM\n"); dev_err(&pdev->dev, "Failed to configure PWM\n");
return ret; return ret;
} }
...@@ -266,8 +244,8 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -266,8 +244,8 @@ static int pwm_fan_probe(struct platform_device *pdev)
ctx, pwm_fan_groups); ctx, pwm_fan_groups);
if (IS_ERR(hwmon)) { if (IS_ERR(hwmon)) {
dev_err(&pdev->dev, "Failed to register hwmon device\n"); dev_err(&pdev->dev, "Failed to register hwmon device\n");
pwm_disable(ctx->pwm); ret = PTR_ERR(hwmon);
return PTR_ERR(hwmon); goto err_pwm_disable;
} }
ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
...@@ -282,14 +260,20 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -282,14 +260,20 @@ static int pwm_fan_probe(struct platform_device *pdev)
if (IS_ERR(cdev)) { if (IS_ERR(cdev)) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Failed to register pwm-fan as cooling device"); "Failed to register pwm-fan as cooling device");
pwm_disable(ctx->pwm); ret = PTR_ERR(cdev);
return PTR_ERR(cdev); goto err_pwm_disable;
} }
ctx->cdev = cdev; ctx->cdev = cdev;
thermal_cdev_update(cdev); thermal_cdev_update(cdev);
} }
return 0; return 0;
err_pwm_disable:
state.enabled = false;
pwm_apply_state(ctx->pwm, &state);
return ret;
} }
static int pwm_fan_remove(struct platform_device *pdev) static int pwm_fan_remove(struct platform_device *pdev)
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/scpi_protocol.h> #include <linux/scpi_protocol.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
#include <linux/thermal.h> #include <linux/thermal.h>
struct sensor_data { struct sensor_data {
unsigned int scale;
struct scpi_sensor_info info; struct scpi_sensor_info info;
struct device_attribute dev_attr_input; struct device_attribute dev_attr_input;
struct device_attribute dev_attr_label; struct device_attribute dev_attr_label;
...@@ -44,6 +46,30 @@ struct scpi_sensors { ...@@ -44,6 +46,30 @@ struct scpi_sensors {
const struct attribute_group *groups[2]; const struct attribute_group *groups[2];
}; };
static const u32 gxbb_scpi_scale[] = {
[TEMPERATURE] = 1, /* (celsius) */
[VOLTAGE] = 1000, /* (millivolts) */
[CURRENT] = 1000, /* (milliamperes) */
[POWER] = 1000000, /* (microwatts) */
[ENERGY] = 1000000, /* (microjoules) */
};
static const u32 scpi_scale[] = {
[TEMPERATURE] = 1000, /* (millicelsius) */
[VOLTAGE] = 1000, /* (millivolts) */
[CURRENT] = 1000, /* (milliamperes) */
[POWER] = 1000000, /* (microwatts) */
[ENERGY] = 1000000, /* (microjoules) */
};
static void scpi_scale_reading(u64 *value, struct sensor_data *sensor)
{
if (scpi_scale[sensor->info.class] != sensor->scale) {
*value *= scpi_scale[sensor->info.class];
do_div(*value, sensor->scale);
}
}
static int scpi_read_temp(void *dev, int *temp) static int scpi_read_temp(void *dev, int *temp)
{ {
struct scpi_thermal_zone *zone = dev; struct scpi_thermal_zone *zone = dev;
...@@ -57,6 +83,8 @@ static int scpi_read_temp(void *dev, int *temp) ...@@ -57,6 +83,8 @@ static int scpi_read_temp(void *dev, int *temp)
if (ret) if (ret)
return ret; return ret;
scpi_scale_reading(&value, sensor);
*temp = value; *temp = value;
return 0; return 0;
} }
...@@ -77,6 +105,8 @@ scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf) ...@@ -77,6 +105,8 @@ scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
if (ret) if (ret)
return ret; return ret;
scpi_scale_reading(&value, sensor);
return sprintf(buf, "%llu\n", value); return sprintf(buf, "%llu\n", value);
} }
...@@ -94,14 +124,23 @@ static struct thermal_zone_of_device_ops scpi_sensor_ops = { ...@@ -94,14 +124,23 @@ static struct thermal_zone_of_device_ops scpi_sensor_ops = {
.get_temp = scpi_read_temp, .get_temp = scpi_read_temp,
}; };
static const struct of_device_id scpi_of_match[] = {
{.compatible = "arm,scpi-sensors", .data = &scpi_scale},
{.compatible = "amlogic,meson-gxbb-scpi-sensors", .data = &gxbb_scpi_scale},
{},
};
MODULE_DEVICE_TABLE(of, scpi_of_match);
static int scpi_hwmon_probe(struct platform_device *pdev) static int scpi_hwmon_probe(struct platform_device *pdev)
{ {
u16 nr_sensors, i; u16 nr_sensors, i;
const u32 *scale;
int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0; int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0;
int num_energy = 0; int num_energy = 0;
struct scpi_ops *scpi_ops; struct scpi_ops *scpi_ops;
struct device *hwdev, *dev = &pdev->dev; struct device *hwdev, *dev = &pdev->dev;
struct scpi_sensors *scpi_sensors; struct scpi_sensors *scpi_sensors;
const struct of_device_id *of_id;
int idx, ret; int idx, ret;
scpi_ops = get_scpi_ops(); scpi_ops = get_scpi_ops();
...@@ -131,6 +170,13 @@ static int scpi_hwmon_probe(struct platform_device *pdev) ...@@ -131,6 +170,13 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
scpi_sensors->scpi_ops = scpi_ops; scpi_sensors->scpi_ops = scpi_ops;
of_id = of_match_device(scpi_of_match, &pdev->dev);
if (!of_id) {
dev_err(&pdev->dev, "Unable to initialize scpi-hwmon data\n");
return -ENODEV;
}
scale = of_id->data;
for (i = 0, idx = 0; i < nr_sensors; i++) { for (i = 0, idx = 0; i < nr_sensors; i++) {
struct sensor_data *sensor = &scpi_sensors->data[idx]; struct sensor_data *sensor = &scpi_sensors->data[idx];
...@@ -178,6 +224,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) ...@@ -178,6 +224,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
continue; continue;
} }
sensor->scale = scale[sensor->info.class];
sensor->dev_attr_input.attr.mode = S_IRUGO; sensor->dev_attr_input.attr.mode = S_IRUGO;
sensor->dev_attr_input.show = scpi_show_sensor; sensor->dev_attr_input.show = scpi_show_sensor;
sensor->dev_attr_input.attr.name = sensor->input; sensor->dev_attr_input.attr.name = sensor->input;
...@@ -247,12 +295,6 @@ static int scpi_hwmon_probe(struct platform_device *pdev) ...@@ -247,12 +295,6 @@ static int scpi_hwmon_probe(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id scpi_of_match[] = {
{.compatible = "arm,scpi-sensors"},
{},
};
MODULE_DEVICE_TABLE(of, scpi_of_match);
static struct platform_driver scpi_hwmon_platdrv = { static struct platform_driver scpi_hwmon_platdrv = {
.driver = { .driver = {
.name = "scpi-hwmon", .name = "scpi-hwmon",
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/i2c/ads1015.h> #include <linux/platform_data/ads1015.h>
#include <linux/iio/iio.h> #include <linux/iio/iio.h>
#include <linux/iio/types.h> #include <linux/iio/types.h>
......
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