diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-04 21:48:27 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-04 21:48:27 +0300 |
commit | 24d734a2ba5133f55feb7f7df7530d4f5aa6518f (patch) | |
tree | e20d9cec46cb3f55f6ab0cc23bf13dd3ab3ff76c | |
parent | 17ece345a042347224e50032e959ad3959638b21 (diff) | |
parent | 44b413661b57cbbb7e4c3adf7b087fada42a443e (diff) | |
download | linux-24d734a2ba5133f55feb7f7df7530d4f5aa6518f.tar.xz |
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
...
29 files changed, 1025 insertions, 224 deletions
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015 index 063b80d857b1..02d2a459385f 100644 --- a/Documentation/hwmon/ads1015 +++ b/Documentation/hwmon/ads1015 @@ -40,7 +40,7 @@ By default all inputs are exported. 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: - pga is the programmable gain amplifier (values are full scale) 0: +/- 6.144 V diff --git a/Documentation/hwmon/adt7475 b/Documentation/hwmon/adt7475 index 0502f2b464e1..09d73a10644c 100644 --- a/Documentation/hwmon/adt7475 +++ b/Documentation/hwmon/adt7475 @@ -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 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 ----- diff --git a/Documentation/hwmon/ir35221 b/Documentation/hwmon/ir35221 new file mode 100644 index 000000000000..f7e112752c04 --- /dev/null +++ b/Documentation/hwmon/ir35221 @@ -0,0 +1,87 @@ +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 diff --git a/Documentation/hwmon/ltc4245 b/Documentation/hwmon/ltc4245 index b478b0864965..4ca7a9da09f9 100644 --- a/Documentation/hwmon/ltc4245 +++ b/Documentation/hwmon/ltc4245 @@ -96,7 +96,7 @@ slowly, -EAGAIN will be returned when you read the sysfs attribute containing the sensor reading. 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 The default mode of operation is to sample a single GPIO pin. diff --git a/Documentation/hwmon/pmbus-core b/Documentation/hwmon/pmbus-core index 31e4720fed18..8ed10e9ddfb5 100644 --- a/Documentation/hwmon/pmbus-core +++ b/Documentation/hwmon/pmbus-core @@ -253,7 +253,7 @@ Specifically, it provides the following information. 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. #define PMBUS_SKIP_STATUS_CHECK (1 << 0) diff --git a/MAINTAINERS b/MAINTAINERS index 9a55295e5efc..67ab1aba1fcc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -478,7 +478,7 @@ L: linux-hwmon@vger.kernel.org S: Maintained F: Documentation/hwmon/ads1015 F: drivers/hwmon/ads1015.c -F: include/linux/i2c/ads1015.h +F: include/linux/platform_data/ads1015.h ADT746X FAN DRIVER 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 S: Maintained F: Documentation/hwmon/pmbus F: drivers/hwmon/pmbus/ -F: include/linux/i2c/pmbus.h +F: include/linux/pmbus.h PMC SIERRA MaxRAID DRIVER L: linux-scsi@vger.kernel.org diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index 5140c27d16dd..357b42607164 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -34,7 +34,7 @@ #include <linux/of_device.h> #include <linux/of.h> -#include <linux/i2c/ads1015.h> +#include <linux/platform_data/ads1015.h> /* ADS1015 registers */ enum { diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index c803e3c5fcd4..1baa213a60bd 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -22,6 +22,7 @@ #include <linux/hwmon-vid.h> #include <linux/err.h> #include <linux/jiffies.h> +#include <linux/util_macros.h> /* Indexes for the sysfs hooks */ @@ -78,6 +79,9 @@ #define REG_TEMP_TRANGE_BASE 0x5F +#define REG_ENHANCE_ACOUSTICS1 0x62 +#define REG_ENHANCE_ACOUSTICS2 0x63 + #define REG_PWM_MIN_BASE 0x64 #define REG_TEMP_TMIN_BASE 0x67 @@ -208,6 +212,7 @@ struct adt7475_data { u8 range[3]; u8 pwmctl[3]; u8 pwmchan[3]; + u8 enh_acoustics[2]; u8 vid; u8 vrm; @@ -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); } -/* - * 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, char *buf) { @@ -550,6 +526,88 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr, 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, * and we'll convert it @@ -606,7 +664,7 @@ static ssize_t set_point2(struct device *dev, struct device_attribute *attr, val -= temp; /* 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] |= val << 4; @@ -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); i2c_smbus_write_byte_data(client, reg, 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); @@ -839,7 +934,7 @@ static ssize_t set_pwmctrl(struct device *dev, struct device_attribute *attr, /* List of frequencies for the PWM */ 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, @@ -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 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", - pwmfreq_table[data->range[sattr->index] & 7]); + return sprintf(buf, "%d\n", pwmfreq_table[i]); } 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)) 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); data->range[sattr->index] = adt7475_read(TEMP_TRANGE_REG(sattr->index)); - data->range[sattr->index] &= ~7; + data->range[sattr->index] &= ~0xf; data->range[sattr->index] |= out; 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, THERM, 0); static SENSOR_DEVICE_ATTR_2(temp1_crit_hyst, S_IRUGO | S_IWUSR, show_temp, 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_alarm, S_IRUGO, show_temp, NULL, ALARM, 1); 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, THERM, 1); static SENSOR_DEVICE_ATTR_2(temp2_crit_hyst, S_IRUGO | S_IWUSR, show_temp, 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_alarm, S_IRUGO, show_temp, NULL, ALARM, 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, THERM, 2); static SENSOR_DEVICE_ATTR_2(temp3_crit_hyst, S_IRUGO | S_IWUSR, show_temp, 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_min, S_IRUGO | S_IWUSR, show_tach, set_tach, MIN, 0); @@ -1056,6 +1158,8 @@ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, show_pwm, set_pwm, MIN, 0); static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, 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, 1); 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, set_pwm, MIN, 1); static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, 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, 2); 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, set_pwm, MIN, 2); static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, 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 */ static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit); @@ -1106,6 +1214,7 @@ static struct attribute *adt7475_attrs[] = { &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp1_crit.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_alarm.dev_attr.attr, &sensor_dev_attr_temp2_max.dev_attr.attr, @@ -1115,6 +1224,7 @@ static struct attribute *adt7475_attrs[] = { &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp2_crit.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_fault.dev_attr.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr, @@ -1125,6 +1235,7 @@ static struct attribute *adt7475_attrs[] = { &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr, &sensor_dev_attr_temp3_crit.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_min.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, @@ -1140,12 +1251,14 @@ static struct attribute *adt7475_attrs[] = { &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_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_freq.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_point1_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, NULL, }; @@ -1164,6 +1277,7 @@ static struct attribute *pwm2_attrs[] = { &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_point2_pwm.dev_attr.attr, + &sensor_dev_attr_pwm2_stall_disable.dev_attr.attr, NULL }; diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index 9de13d626c68..ddfe66bdff86 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -146,14 +146,26 @@ #define PWM_MAX 255 +#define BOTH_EDGES 0x02 /* 10b */ + #define M_PWM_DIV_H 0x00 #define M_PWM_DIV_L 0x05 #define M_PWM_PERIOD 0x5F #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 +/* 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 regmap *regmap; unsigned long clk_freq; @@ -163,6 +175,7 @@ struct aspeed_pwm_tacho_data { u8 type_pwm_clock_division_h[3]; u8 type_pwm_clock_division_l[3]; u8 type_fan_tach_clock_division[3]; + u8 type_fan_tach_mode[3]; u16 type_fan_tach_unit[3]; u8 pwm_port_type[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 static int aspeed_get_fan_tach_ch_rpm(struct aspeed_pwm_tacho_data *priv, u8 fan_tach_ch) { - u32 raw_data, tach_div, clk_source, sec, val; - u8 fan_tach_ch_source, type; + u32 raw_data, tach_div, clk_source, msec, usec, val; + 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, 0x1 << fan_tach_ch); @@ -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]; type = priv->pwm_port_type[fan_tach_ch_source]; - sec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type)); - msleep(sec); + msec = (1000 / aspeed_get_fan_tach_ch_measure_period(priv, type)); + 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); - if (!(val & RESULT_STATUS_MASK)) - return -ETIMEDOUT; + /* return -ETIMEDOUT if we didn't get an answer. */ + if (ret) + return ret; raw_data = val & RESULT_VALUE_MASK; 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; if (raw_data == 0) @@ -702,6 +731,7 @@ static void aspeed_create_type(struct aspeed_pwm_tacho_data *priv) aspeed_set_tacho_type_enable(priv->regmap, TYPEM, true); priv->type_fan_tach_clock_division[TYPEM] = M_TACH_CLK_DIV; 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, M_TACH_UNIT, M_TACH_CLK_DIV); } diff --git a/drivers/hwmon/ds620.c b/drivers/hwmon/ds620.c index 0043a4c02b85..57d6958c74b8 100644 --- a/drivers/hwmon/ds620.c +++ b/drivers/hwmon/ds620.c @@ -30,7 +30,7 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/sysfs.h> -#include <linux/i2c/ds620.h> +#include <linux/platform_data/ds620.h> /* * Many DS620 constants specified below diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c index 6d2e6605751c..5ccdd0b52650 100644 --- a/drivers/hwmon/ibmpowernv.c +++ b/drivers/hwmon/ibmpowernv.c @@ -50,22 +50,34 @@ enum sensors { TEMP, POWER_SUPPLY, POWER_INPUT, + CURRENT, MAX_SENSOR_TYPE, }; #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 { - const char *name; - const char *compatible; + const char *name; /* matches property 'sensor-type' */ struct attribute_group group; u32 attr_count; u32 hwmon_index; } sensor_groups[] = { - {"fan", "ibm,opal-sensor-cooling-fan"}, - {"temp", "ibm,opal-sensor-amb-temp"}, - {"in", "ibm,opal-sensor-power-supply"}, - {"power", "ibm,opal-sensor-power"} + { "fan" }, + { "temp" }, + { "in" }, + { "power" }, + { "curr" }, }; struct sensor_data { @@ -239,8 +251,8 @@ static int get_sensor_type(struct device_node *np) enum sensors type; const char *str; - for (type = 0; type < MAX_SENSOR_TYPE; type++) { - if (of_device_is_compatible(np, sensor_groups[type].compatible)) + for (type = 0; type < ARRAY_SIZE(legacy_compatibles); type++) { + if (of_device_is_compatible(np, legacy_compatibles[type])) return type; } @@ -298,10 +310,14 @@ static int populate_attr_groups(struct platform_device *pdev) 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)) 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); @@ -337,6 +353,41 @@ static void create_hwmon_attr(struct sensor_data *sdata, const char *attr_name, 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 * 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) * attribute. They are related to the same * 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); + 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++] = - &sdata[count++].dev_attr.attr; + if (!of_property_read_u32(np, "sensor-data-min", &sensor_id)) { + 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++; } } diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c index 4680d89556ce..082f0a0bd8a0 100644 --- a/drivers/hwmon/ltc4245.c +++ b/drivers/hwmon/ltc4245.c @@ -23,7 +23,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.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) */ enum ltc4245_cmd { diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index dac6d85f2fd9..f98a83c79ff1 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -32,7 +32,7 @@ #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> -#include <linux/i2c/max6639.h> +#include <linux/platform_data/max6639.h> /* Addresses to scan */ static const unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index 2458b406f6aa..c219e43b8f02 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -40,6 +40,8 @@ * nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3 * nct6792d 15 6 6 2+6 0xc910 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 * the number of directly connectable temperature sensors (second value). @@ -58,13 +60,15 @@ #include <linux/err.h> #include <linux/mutex.h> #include <linux/acpi.h> +#include <linux/bitops.h> #include <linux/dmi.h> #include <linux/io.h> #include "lm75.h" #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] */ static const char * const nct6775_device_names[] = { @@ -75,6 +79,7 @@ static const char * const nct6775_device_names[] = { "nct6791", "nct6792", "nct6793", + "nct6795", }; static const char * const nct6775_sio_names[] __initconst = { @@ -85,6 +90,7 @@ static const char * const nct6775_sio_names[] __initconst = { "NCT6791D", "NCT6792D", "NCT6793D", + "NCT6795D", }; static unsigned short force_id; @@ -104,6 +110,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define NCT6775_LD_ACPI 0x0a #define NCT6775_LD_HWM 0x0b #define NCT6775_LD_VID 0x0d +#define NCT6775_LD_12 0x12 #define SIO_REG_LDSEL 0x07 /* Logical device select */ #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ @@ -117,6 +124,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal"); #define SIO_NCT6791_ID 0xc800 #define SIO_NCT6792_ID 0xc910 #define SIO_NCT6793_ID 0xd120 +#define SIO_NCT6795_ID 0xd350 #define SIO_ID_MASK 0xFFF0 enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 }; @@ -360,12 +368,24 @@ static const char *const nct6775_temp_label[] = { "PCH_DIM3_TEMP" }; -static const u16 NCT6775_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6775_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x661, 0x662, 0x664 }; +#define NCT6775_TEMP_MASK 0x001ffffe + +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] - = { 0, 0, 0, 0, 0xa00, 0xa01, 0xa02, 0xa03, 0xa04, 0xa05, 0xa06, - 0xa07 }; +static const u16 NCT6775_REG_TEMP_CRIT[32] = { + [4] = 0xa00, + [5] = 0xa01, + [6] = 0xa02, + [7] = 0xa03, + [8] = 0xa04, + [9] = 0xa05, + [10] = 0xa06, + [11] = 0xa07 +}; /* NCT6776 specific data */ @@ -434,11 +454,18 @@ static const char *const nct6776_temp_label[] = { "BYTE_TEMP" }; -static const u16 NCT6776_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x401, 0x402, 0x404 }; +#define NCT6776_TEMP_MASK 0x007ffffe -static const u16 NCT6776_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; +static const u16 NCT6776_REG_TEMP_ALTERNATE[32] = { + [14] = 0x401, + [15] = 0x402, + [16] = 0x404, +}; + +static const u16 NCT6776_REG_TEMP_CRIT[32] = { + [11] = 0x709, + [12] = 0x70a, +}; /* NCT6779 specific data */ @@ -525,17 +552,19 @@ static const char *const nct6779_temp_label[] = { "Virtual_TEMP" }; -#define NCT6779_NUM_LABELS (ARRAY_SIZE(nct6779_temp_label) - 5) -#define NCT6791_NUM_LABELS ARRAY_SIZE(nct6779_temp_label) +#define NCT6779_TEMP_MASK 0x07ffff7e +#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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x400, 0x401, 0x402, 0x404, 0x405, 0x406, 0x407, 0x408, 0 }; -static const u16 NCT6779_REG_TEMP_CRIT[NCT6791_NUM_LABELS - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x709, 0x70a }; +static const u16 NCT6779_REG_TEMP_CRIT[32] = { + [15] = 0x709, + [16] = 0x70a, +}; /* NCT6791 specific data */ @@ -602,6 +631,8 @@ static const char *const nct6792_temp_label[] = { "Virtual_TEMP" }; +#define NCT6792_TEMP_MASK 0x9fffff7e + static const char *const nct6793_temp_label[] = { "", "SYSTIN", @@ -637,6 +668,45 @@ static const char *const nct6793_temp_label[] = { "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 */ #define NCT6106_REG_VBAT 0x318 @@ -731,11 +801,16 @@ static const s8 NCT6106_BEEP_BITS[] = { 34, -1 /* intrusion0, intrusion1 */ }; -static const u16 NCT6106_REG_TEMP_ALTERNATE[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x51, 0x52, 0x54 }; +static const u16 NCT6106_REG_TEMP_ALTERNATE[32] = { + [14] = 0x51, + [15] = 0x52, + [16] = 0x54, +}; -static const u16 NCT6106_REG_TEMP_CRIT[ARRAY_SIZE(nct6776_temp_label) - 1] - = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x204, 0x205 }; +static const u16 NCT6106_REG_TEMP_CRIT[32] = { + [11] = 0x204, + [12] = 0x205, +}; 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) static inline unsigned int div_from_reg(u8 reg) { - return 1 << reg; + return BIT(reg); } /* @@ -850,7 +925,7 @@ struct nct6775_data { u8 temp_src[NUM_TEMP]; u16 reg_temp_config[NUM_TEMP]; const char * const *temp_label; - int temp_label_num; + u32 temp_mask; u16 REG_CONFIG; u16 REG_VBAT; @@ -1155,6 +1230,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg) case nct6791: case nct6792: case nct6793: + case nct6795: return reg == 0x150 || reg == 0x153 || reg == 0x155 || ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) || reg == 0x402 || @@ -1276,7 +1352,7 @@ static void nct6775_update_fan_div(struct nct6775_data *data) data->fan_div[1] = (i & 0x70) >> 4; i = nct6775_read_value(data, NCT6775_REG_FANDIV2); 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; } @@ -1298,7 +1374,7 @@ static void nct6775_init_fan_div(struct nct6775_data *data) * We'll compute a better divider later on. */ for (i = 0; i < ARRAY_SIZE(data->fan_div); i++) { - if (!(data->has_fan & (1 << i))) + if (!(data->has_fan & BIT(i))) continue; if (data->fan_div[i] == 0) { data->fan_div[i] = 7; @@ -1321,7 +1397,7 @@ static void nct6775_init_fan_common(struct device *dev, * prevents the unnecessary warning when fanX_min is reported as 0. */ 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]); if (!reg) nct6775_write_value(data, data->REG_FAN_MIN[i], @@ -1356,7 +1432,7 @@ static void nct6775_select_fan_div(struct device *dev, div_from_reg(fan_div)); /* 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]; if (fan_div > data->fan_div[nr]) { if (fan_min != 255 && fan_min > 1) @@ -1387,7 +1463,7 @@ static void nct6775_update_pwm(struct device *dev) bool duty_is_dc; for (i = 0; i < data->pwm_num; i++) { - if (!(data->has_pwm & (1 << i))) + if (!(data->has_pwm & BIT(i))) continue; duty_is_dc = data->REG_PWM_MODE[i] && @@ -1457,7 +1533,7 @@ static void nct6775_update_pwm_limits(struct device *dev) u16 reg_t; for (i = 0; i < data->pwm_num; i++) { - if (!(data->has_pwm & (1 << i))) + if (!(data->has_pwm & BIT(i))) continue; for (j = 0; j < ARRAY_SIZE(data->fan_time); j++) { @@ -1507,6 +1583,7 @@ static void nct6775_update_pwm_limits(struct device *dev) case nct6791: case nct6792: case nct6793: + case nct6795: reg = nct6775_read_value(data, data->REG_CRITICAL_PWM_ENABLE[i]); if (reg & data->CRITICAL_PWM_ENABLE_MASK) @@ -1534,7 +1611,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) /* Measured voltages and limits */ for (i = 0; i < data->in_num; i++) { - if (!(data->have_in & (1 << i))) + if (!(data->have_in & BIT(i))) continue; data->in[i][0] = nct6775_read_value(data, @@ -1549,14 +1626,14 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) for (i = 0; i < ARRAY_SIZE(data->rpm); i++) { u16 reg; - if (!(data->has_fan & (1 << i))) + if (!(data->has_fan & BIT(i))) continue; reg = nct6775_read_value(data, data->REG_FAN[i]); data->rpm[i] = data->fan_from_reg(reg, 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->REG_FAN_MIN[i]); data->fan_pulses[i] = @@ -1571,7 +1648,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) /* Measured temperatures and limits */ for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; for (j = 0; j < ARRAY_SIZE(data->reg_temp); j++) { if (data->reg_temp[j][i]) @@ -1580,7 +1657,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev) data->reg_temp[j][i]); } if (i >= NUM_TEMP_FIXED || - !(data->have_temp_fixed & (1 << i))) + !(data->have_temp_fixed & BIT(i))) continue; data->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, struct nct6775_data *data = dev_get_drvdata(dev); int in = index / 5; /* voltage index */ - if (!(data->have_in & (1 << in))) + if (!(data->have_in & BIT(in))) return 0; return attr->mode; @@ -1911,7 +1988,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, * even with the highest divider (128) */ data->fan_min[nr] = 254; - new_div = 7; /* 128 == (1 << 7) */ + new_div = 7; /* 128 == BIT(7) */ dev_warn(dev, "fan%u low limit %lu below minimum %u, set to minimum\n", nr + 1, val, data->fan_from_reg_min(254, 7)); @@ -1921,7 +1998,7 @@ store_fan_min(struct device *dev, struct device_attribute *attr, * even with the lowest divider (1) */ data->fan_min[nr] = 1; - new_div = 0; /* 1 == (1 << 0) */ + new_div = 0; /* 1 == BIT(0) */ dev_warn(dev, "fan%u low limit %lu above maximum %u, set to maximum\n", nr + 1, val, data->fan_from_reg_min(1, 0)); @@ -2008,14 +2085,14 @@ static umode_t nct6775_fan_is_visible(struct kobject *kobj, int fan = index / 6; /* fan index */ int nr = index % 6; /* attribute index */ - if (!(data->has_fan & (1 << fan))) + if (!(data->has_fan & BIT(fan))) return 0; if (nr == 1 && data->ALARM_BITS[FAN_ALARM_BASE + fan] == -1) return 0; if (nr == 2 && data->BEEP_BITS[FAN_ALARM_BASE + fan] == -1) return 0; - if (nr == 4 && !(data->has_fan_min & (1 << fan))) + if (nr == 4 && !(data->has_fan_min & BIT(fan))) return 0; if (nr == 5 && data->kind != nct6775) return 0; @@ -2193,7 +2270,10 @@ static umode_t nct6775_temp_is_visible(struct kobject *kobj, int temp = index / 10; /* temp 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; 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, return 0; /* 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 attr->mode; @@ -2484,7 +2564,7 @@ show_pwm_temp_sel_common(struct nct6775_data *data, char *buf, int src) int i, sel = 0; for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; if (src == data->temp_src[i]) { sel = i + 1; @@ -2520,7 +2600,7 @@ store_pwm_temp_sel(struct device *dev, struct device_attribute *attr, return err; if (val == 0 || val > NUM_TEMP) 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; mutex_lock(&data->update_lock); @@ -2562,7 +2642,7 @@ store_pwm_weight_temp_sel(struct device *dev, struct device_attribute *attr, return err; if (val > NUM_TEMP) return -EINVAL; - if (val && (!(data->have_temp & (1 << (val - 1))) || + if (val && (!(data->have_temp & BIT(val - 1)) || !data->temp_src[val - 1])) return -EINVAL; @@ -2923,6 +3003,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr, case nct6791: case nct6792: case nct6793: + case nct6795: nct6775_write_value(data, data->REG_CRITICAL_PWM[nr], val); reg = nct6775_read_value(data, @@ -2995,7 +3076,7 @@ static umode_t nct6775_pwm_is_visible(struct kobject *kobj, int pwm = index / 36; /* pwm index */ int nr = index % 36; /* attribute index */ - if (!(data->has_pwm & (1 << pwm))) + if (!(data->has_pwm & BIT(pwm))) return 0; if ((nr >= 14 && nr <= 18) || nr == 21) /* weight */ @@ -3246,7 +3327,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) /* Enable temperature sensors if needed */ for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; if (!data->reg_temp_config[i]) continue; @@ -3264,7 +3345,7 @@ static inline void nct6775_init_device(struct nct6775_data *data) diode = nct6775_read_value(data, data->REG_DIODE); for (i = 0; i < data->temp_fixed_num; i++) { - if (!(data->have_temp_fixed & (1 << i))) + if (!(data->have_temp_fixed & BIT(i))) continue; if ((tmp & (data->DIODE_MASK << i))) /* diode */ data->temp_type[i] @@ -3290,8 +3371,8 @@ nct6775_check_fan_inputs(struct nct6775_data *data) if (data->kind == nct6775) { regval = superio_inb(sioreg, 0x2c); - fan3pin = regval & (1 << 6); - pwm3pin = regval & (1 << 7); + fan3pin = regval & BIT(6); + pwm3pin = regval & BIT(7); /* On NCT6775, fan4 shares pins with the fdc interface */ fan4pin = !(superio_inb(sioreg, 0x2A) & 0x80); @@ -3357,28 +3438,57 @@ nct6775_check_fan_inputs(struct nct6775_data *data) pwm4pin = false; pwm5pin = false; pwm6pin = false; - } else { /* NCT6779D, NCT6791D, NCT6792D, or NCT6793D */ - regval = superio_inb(sioreg, 0x1c); + } else { /* NCT6779D, NCT6791D, NCT6792D, NCT6793D, or NCT6795D */ + int regval_1b, regval_2a, regval_eb; - fan3pin = !(regval & (1 << 5)); - fan4pin = !(regval & (1 << 6)); - fan5pin = !(regval & (1 << 7)); + regval = superio_inb(sioreg, 0x1c); - pwm3pin = !(regval & (1 << 0)); - pwm4pin = !(regval & (1 << 1)); - pwm5pin = !(regval & (1 << 2)); + fan3pin = !(regval & BIT(5)); + fan4pin = !(regval & BIT(6)); + 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 || - data->kind == nct6793) { - regval = superio_inb(sioreg, 0x2d); - fan6pin = (regval & (1 << 1)); - pwm6pin = (regval & (1 << 0)); - } else { /* NCT6779D */ + regval = superio_inb(sioreg, 0x2d); + switch (data->kind) { + case nct6791: + case nct6792: + fan6pin = regval & BIT(1); + 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; pwm6pin = false; + break; } + + fan4min = fan4pin; } /* fan 1 and 2 (0x03) are always present */ @@ -3403,16 +3513,15 @@ static void add_temp_sensors(struct nct6775_data *data, const u16 *regp, continue; src = nct6775_read_value(data, regp[i]); src &= 0x1f; - if (!src || (*mask & (1 << src))) + if (!src || (*mask & BIT(src))) continue; - if (src >= data->temp_label_num || - !strlen(data->temp_label[src])) + if (!(data->temp_mask & BIT(src))) continue; index = __ffs(*available); nct6775_write_value(data, data->REG_TEMP_SOURCE[index], src); - *available &= ~(1 << index); - *mask |= 1 << src; + *available &= ~BIT(index); + *mask |= BIT(src); } } @@ -3464,7 +3573,7 @@ static int nct6775_probe(struct platform_device *pdev) data->fan_from_reg_min = fan_from_reg13; 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_DIODE = NCT6106_REG_DIODE; @@ -3542,7 +3651,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 15; 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_VBAT = NCT6775_REG_VBAT; @@ -3614,7 +3723,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 63; 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_VBAT = NCT6775_REG_VBAT; @@ -3686,7 +3795,7 @@ static int nct6775_probe(struct platform_device *pdev) data->speed_tolerance_limit = 63; 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_VBAT = NCT6775_REG_VBAT; @@ -3746,6 +3855,7 @@ static int nct6775_probe(struct platform_device *pdev) case nct6791: case nct6792: case nct6793: + case nct6795: data->in_num = 15; data->pwm_num = 6; data->auto_pwm_num = 4; @@ -3767,15 +3877,21 @@ static int nct6775_probe(struct platform_device *pdev) default: case nct6791: data->temp_label = nct6779_temp_label; + data->temp_mask = NCT6791_TEMP_MASK; break; case nct6792: data->temp_label = nct6792_temp_label; + data->temp_mask = NCT6792_TEMP_MASK; break; case nct6793: 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; } - data->temp_label_num = NCT6791_NUM_LABELS; data->REG_CONFIG = NCT6775_REG_CONFIG; data->REG_VBAT = NCT6775_REG_VBAT; @@ -3843,7 +3959,7 @@ static int nct6775_probe(struct platform_device *pdev) default: return -ENODEV; } - data->have_in = (1 << data->in_num) - 1; + data->have_in = BIT(data->in_num) - 1; data->have_temp = 0; /* @@ -3861,10 +3977,10 @@ static int nct6775_probe(struct platform_device *pdev) continue; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; - if (!src || (mask & (1 << src))) - available |= 1 << i; + if (!src || (mask & BIT(src))) + available |= BIT(i); - mask |= 1 << src; + mask |= BIT(src); } /* @@ -3881,23 +3997,22 @@ static int nct6775_probe(struct platform_device *pdev) continue; src = nct6775_read_value(data, data->REG_TEMP_SOURCE[i]) & 0x1f; - if (!src || (mask & (1 << src))) + if (!src || (mask & BIT(src))) continue; - if (src >= data->temp_label_num || - !strlen(data->temp_label[src])) { + if (!(data->temp_mask & BIT(src))) { dev_info(dev, "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]); continue; } - mask |= 1 << src; + mask |= BIT(src); /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ if (src <= data->temp_fixed_num) { - data->have_temp |= 1 << (src - 1); - data->have_temp_fixed |= 1 << (src - 1); + data->have_temp |= BIT(src - 1); + data->have_temp_fixed |= BIT(src - 1); data->reg_temp[0][src - 1] = reg_temp[i]; data->reg_temp[1][src - 1] = reg_temp_over[i]; data->reg_temp[2][src - 1] = reg_temp_hyst[i]; @@ -3917,7 +4032,7 @@ static int nct6775_probe(struct platform_device *pdev) continue; /* 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[1][s] = reg_temp_over[i]; data->reg_temp[2][s] = reg_temp_hyst[i]; @@ -3945,8 +4060,7 @@ static int nct6775_probe(struct platform_device *pdev) if (!src) continue; - if (src >= data->temp_label_num || - !strlen(data->temp_label[src])) { + if (!(data->temp_mask & BIT(src))) { dev_info(dev, "Invalid temperature source %d at index %d, source register 0x%x, temp register 0x%x\n", src, i, data->REG_TEMP_SEL[i], @@ -3960,17 +4074,17 @@ static int nct6775_probe(struct platform_device *pdev) * are no duplicates. */ if (src != TEMP_SOURCE_VIRTUAL) { - if (mask & (1 << src)) + if (mask & BIT(src)) continue; - mask |= 1 << src; + mask |= BIT(src); } /* Use fixed index for SYSTIN(1), CPUTIN(2), AUXTIN(3) */ if (src <= data->temp_fixed_num) { - if (data->have_temp & (1 << (src - 1))) + if (data->have_temp & BIT(src - 1)) continue; - data->have_temp |= 1 << (src - 1); - data->have_temp_fixed |= 1 << (src - 1); + data->have_temp |= BIT(src - 1); + data->have_temp_fixed |= BIT(src - 1); data->reg_temp[0][src - 1] = reg_temp_mon[i]; data->temp_src[src - 1] = src; continue; @@ -3980,7 +4094,7 @@ static int nct6775_probe(struct platform_device *pdev) continue; /* 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->temp_src[s] = src; s++; @@ -3993,16 +4107,18 @@ static int nct6775_probe(struct platform_device *pdev) * The temperature is already monitored if the respective bit in <mask> * 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]) continue; - if (mask & (1 << (i + 1))) + if (mask & BIT(i + 1)) continue; if (i < data->temp_fixed_num) { - if (data->have_temp & (1 << i)) + if (data->have_temp & BIT(i)) continue; - data->have_temp |= 1 << i; - data->have_temp_fixed |= 1 << i; + data->have_temp |= BIT(i); + data->have_temp_fixed |= BIT(i); data->reg_temp[0][i] = reg_temp_alternate[i]; if (i < num_reg_temp) { data->reg_temp[1][i] = reg_temp_over[i]; @@ -4015,7 +4131,7 @@ static int nct6775_probe(struct platform_device *pdev) if (s >= NUM_TEMP) /* Abort if no more space */ break; - data->have_temp |= 1 << s; + data->have_temp |= BIT(s); data->reg_temp[0][s] = reg_temp_alternate[i]; data->temp_src[s] = i + 1; s++; @@ -4042,6 +4158,7 @@ static int nct6775_probe(struct platform_device *pdev) case nct6791: case nct6792: case nct6793: + case nct6795: break; } @@ -4075,6 +4192,7 @@ static int nct6775_probe(struct platform_device *pdev) case nct6791: case nct6792: case nct6793: + case nct6795: tmp |= 0x7e; break; } @@ -4173,14 +4291,14 @@ static int __maybe_unused nct6775_resume(struct device *dev) superio_outb(sioreg, SIO_REG_ENABLE, data->sio_reg_enable); if (data->kind == nct6791 || data->kind == nct6792 || - data->kind == nct6793) + data->kind == nct6793 || data->kind == nct6795) nct6791_enable_io_mapping(sioreg); superio_exit(sioreg); /* Restore limits */ for (i = 0; i < data->in_num; i++) { - if (!(data->have_in & (1 << i))) + if (!(data->have_in & BIT(i))) continue; nct6775_write_value(data, data->REG_IN_MINMAX[0][i], @@ -4190,7 +4308,7 @@ static int __maybe_unused nct6775_resume(struct device *dev) } 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; nct6775_write_value(data, data->REG_FAN_MIN[i], @@ -4198,7 +4316,7 @@ static int __maybe_unused nct6775_resume(struct device *dev) } for (i = 0; i < NUM_TEMP; i++) { - if (!(data->have_temp & (1 << i))) + if (!(data->have_temp & BIT(i))) continue; 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) case SIO_NCT6793_ID: sio_data->kind = nct6793; break; + case SIO_NCT6795_ID: + sio_data->kind = nct6795; + break; default: if (val != 0xffff) 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) } 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); superio_exit(sioaddr); diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index cad1229b7e17..68d717a3fd59 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig @@ -37,6 +37,16 @@ config SENSORS_ADM1275 This driver can also be built as a module. If so, the module will 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 tristate "National Semiconductor LM25066 and compatibles" default n diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 562132054aaf..75bb7ca619d9 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PMBUS) += pmbus_core.o obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o +obj-$(CONFIG_SENSORS_IR35221) += ir35221.o obj-$(CONFIG_SENSORS_LM25066) += lm25066.o obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o diff --git a/drivers/hwmon/pmbus/ir35221.c b/drivers/hwmon/pmbus/ir35221.c new file mode 100644 index 000000000000..8b906b44484b --- /dev/null +++ b/drivers/hwmon/pmbus/ir35221.c @@ -0,0 +1,337 @@ +/* + * 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"); diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c index 44ca8a94873d..7718e58dbda5 100644 --- a/drivers/hwmon/pmbus/pmbus.c +++ b/drivers/hwmon/pmbus/pmbus.c @@ -25,7 +25,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/i2c.h> -#include <linux/i2c/pmbus.h> +#include <linux/pmbus.h> #include "pmbus.h" /* diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index ba59eaef2e07..f1eff6b6c798 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -28,7 +28,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/jiffies.h> -#include <linux/i2c/pmbus.h> +#include <linux/pmbus.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c index 3518f0c08934..b74dbeca2e8d 100644 --- a/drivers/hwmon/pmbus/ucd9000.c +++ b/drivers/hwmon/pmbus/ucd9000.c @@ -26,7 +26,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/i2c/pmbus.h> +#include <linux/pmbus.h> #include "pmbus.h" enum chips { ucd9000, ucd90120, ucd90124, ucd90160, ucd9090, ucd90910 }; diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c index a8712c5ded4e..3ed94585837a 100644 --- a/drivers/hwmon/pmbus/ucd9200.c +++ b/drivers/hwmon/pmbus/ucd9200.c @@ -25,7 +25,7 @@ #include <linux/err.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/i2c/pmbus.h> +#include <linux/pmbus.h> #include "pmbus.h" #define UCD9200_PHASE_INFO 0xd2 diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index f9af3935b427..70cc0d134f3c 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -40,31 +40,22 @@ struct pwm_fan_ctx { static int __set_pwm(struct pwm_fan_ctx *ctx, unsigned long pwm) { - struct pwm_args pargs; - unsigned long duty; + unsigned long period; int ret = 0; - - pwm_get_args(ctx->pwm, &pargs); + struct pwm_state state = { }; mutex_lock(&ctx->lock); if (ctx->pwm_value == pwm) goto exit_set_pwm_err; - duty = DIV_ROUND_UP(pwm * (pargs.period - 1), MAX_PWM); - ret = pwm_config(ctx->pwm, duty, pargs.period); - if (ret) - goto exit_set_pwm_err; - - if (pwm == 0) - pwm_disable(ctx->pwm); - - if (ctx->pwm_value == 0) { - ret = pwm_enable(ctx->pwm); - if (ret) - goto exit_set_pwm_err; - } + pwm_init_state(ctx->pwm, &state); + period = ctx->pwm->args.period; + state.duty_cycle = DIV_ROUND_UP(pwm * (period - 1), MAX_PWM); + state.enabled = pwm ? true : false; - ctx->pwm_value = pwm; + ret = pwm_apply_state(ctx->pwm, &state); + if (!ret) + ctx->pwm_value = pwm; exit_set_pwm_err: mutex_unlock(&ctx->lock); return ret; @@ -218,10 +209,9 @@ static int pwm_fan_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; struct pwm_fan_ctx *ctx; - struct pwm_args pargs; struct device *hwmon; - int duty_cycle; int ret; + struct pwm_state state = { }; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -237,28 +227,16 @@ static int pwm_fan_probe(struct platform_device *pdev) 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; - ret = pwm_config(ctx->pwm, duty_cycle, pargs.period); - if (ret) { - dev_err(&pdev->dev, "Failed to configure PWM\n"); - return ret; - } + /* Set duty cycle to maximum allowed and enable PWM output */ + pwm_init_state(ctx->pwm, &state); + state.duty_cycle = ctx->pwm->args.period - 1; + state.enabled = true; - /* Enbale PWM output */ - ret = pwm_enable(ctx->pwm); + ret = pwm_apply_state(ctx->pwm, &state); if (ret) { - dev_err(&pdev->dev, "Failed to enable PWM\n"); + dev_err(&pdev->dev, "Failed to configure PWM\n"); return ret; } @@ -266,8 +244,8 @@ static int pwm_fan_probe(struct platform_device *pdev) ctx, pwm_fan_groups); if (IS_ERR(hwmon)) { dev_err(&pdev->dev, "Failed to register hwmon device\n"); - pwm_disable(ctx->pwm); - return PTR_ERR(hwmon); + ret = PTR_ERR(hwmon); + goto err_pwm_disable; } ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); @@ -282,14 +260,20 @@ static int pwm_fan_probe(struct platform_device *pdev) if (IS_ERR(cdev)) { dev_err(&pdev->dev, "Failed to register pwm-fan as cooling device"); - pwm_disable(ctx->pwm); - return PTR_ERR(cdev); + ret = PTR_ERR(cdev); + goto err_pwm_disable; } ctx->cdev = cdev; thermal_cdev_update(cdev); } 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) diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c index 094f948f99ff..a586480a7ca9 100644 --- a/drivers/hwmon/scpi-hwmon.c +++ b/drivers/hwmon/scpi-hwmon.c @@ -16,6 +16,7 @@ #include <linux/hwmon.h> #include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/scpi_protocol.h> #include <linux/slab.h> @@ -23,6 +24,7 @@ #include <linux/thermal.h> struct sensor_data { + unsigned int scale; struct scpi_sensor_info info; struct device_attribute dev_attr_input; struct device_attribute dev_attr_label; @@ -44,6 +46,30 @@ struct scpi_sensors { 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) { struct scpi_thermal_zone *zone = dev; @@ -57,6 +83,8 @@ static int scpi_read_temp(void *dev, int *temp) if (ret) return ret; + scpi_scale_reading(&value, sensor); + *temp = value; return 0; } @@ -77,6 +105,8 @@ scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf) if (ret) return ret; + scpi_scale_reading(&value, sensor); + return sprintf(buf, "%llu\n", value); } @@ -94,14 +124,23 @@ static struct thermal_zone_of_device_ops scpi_sensor_ops = { .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) { u16 nr_sensors, i; + const u32 *scale; int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0; int num_energy = 0; struct scpi_ops *scpi_ops; struct device *hwdev, *dev = &pdev->dev; struct scpi_sensors *scpi_sensors; + const struct of_device_id *of_id; int idx, ret; scpi_ops = get_scpi_ops(); @@ -131,6 +170,13 @@ static int scpi_hwmon_probe(struct platform_device *pdev) 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++) { struct sensor_data *sensor = &scpi_sensors->data[idx]; @@ -178,6 +224,8 @@ static int scpi_hwmon_probe(struct platform_device *pdev) continue; } + sensor->scale = scale[sensor->info.class]; + sensor->dev_attr_input.attr.mode = S_IRUGO; sensor->dev_attr_input.show = scpi_show_sensor; sensor->dev_attr_input.attr.name = sensor->input; @@ -247,12 +295,6 @@ static int scpi_hwmon_probe(struct platform_device *pdev) 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 = { .driver = { .name = "scpi-hwmon", diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index f76d979fb7e8..884b8e461b17 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -23,7 +23,7 @@ #include <linux/mutex.h> #include <linux/delay.h> -#include <linux/i2c/ads1015.h> +#include <linux/platform_data/ads1015.h> #include <linux/iio/iio.h> #include <linux/iio/types.h> diff --git a/include/linux/i2c/ads1015.h b/include/linux/platform_data/ads1015.h index d5aa2a045669..d5aa2a045669 100644 --- a/include/linux/i2c/ads1015.h +++ b/include/linux/platform_data/ads1015.h diff --git a/include/linux/i2c/ds620.h b/include/linux/platform_data/ds620.h index 736bb87ac0fc..736bb87ac0fc 100644 --- a/include/linux/i2c/ds620.h +++ b/include/linux/platform_data/ds620.h diff --git a/include/linux/i2c/ltc4245.h b/include/linux/platform_data/ltc4245.h index 56bda4be0016..56bda4be0016 100644 --- a/include/linux/i2c/ltc4245.h +++ b/include/linux/platform_data/ltc4245.h diff --git a/include/linux/i2c/max6639.h b/include/linux/platform_data/max6639.h index 6011c42034da..6011c42034da 100644 --- a/include/linux/i2c/max6639.h +++ b/include/linux/platform_data/max6639.h diff --git a/include/linux/i2c/pmbus.h b/include/linux/pmbus.h index ee3c2aba2a8e..ee3c2aba2a8e 100644 --- a/include/linux/i2c/pmbus.h +++ b/include/linux/pmbus.h |