diff --git a/patch/config-mitac-ly1200.patch b/patch/config-mitac-ly1200.patch new file mode 100644 index 000000000000..8352ef5f3b6a --- /dev/null +++ b/patch/config-mitac-ly1200.patch @@ -0,0 +1,23 @@ +From: "Eddy.Weng" +- Use SENSORS_MAX31790 to access MAX31790 + CONFIG_SENSORS_MAX31790=m + +--- + debian/build/build_amd64_none_amd64/.config | 1 ++ + 1 file changed, 1 insertions(+) + +diff --git a/debian/build/build_amd64_none_amd64/.config b/debian/build/build_amd64_none_amd64/.config +index 6b6aea9..417c419 100644 +--- a/debian/build/build_amd64_none_amd64/.config ++++ b/debian/build/build_amd64_none_amd64/.config +@@ -3451,6 +3451,7 @@ CONFIG_SENSORS_MAX16065=m + CONFIG_SENSORS_MAX1619=m + CONFIG_SENSORS_MAX1668=m + # CONFIG_SENSORS_MAX197 is not set ++CONFIG_SENSORS_MAX31790=m + CONFIG_SENSORS_MAX6639=m + CONFIG_SENSORS_MAX6642=m + CONFIG_SENSORS_MAX6650=m +-- +2.1.4 + diff --git a/patch/driver-hwmon-max31790.patch b/patch/driver-hwmon-max31790.patch new file mode 100644 index 000000000000..5d9b26f08211 --- /dev/null +++ b/patch/driver-hwmon-max31790.patch @@ -0,0 +1,795 @@ +From: "Eddy.Weng" + +Patch fan control driver max31790 + +Patch fan control driver max31790.c from linux v4.8 +--- + drivers/hwmon/Kconfig | 9 + + drivers/hwmon/Makefile | 1 + + drivers/hwmon/max31790.c | 742 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 752 insertions(+) + create mode 100644 drivers/hwmon/max31790.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index ca38e05..c3b47c9 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -753,6 +753,15 @@ config SENSORS_MAX197 + This driver can also be built as a module. If so, the module + will be called max197. + ++config SENSORS_MAX31790 ++ tristate "Maxim MAX31790 and compatibles" ++ help ++ If you say yes here you get support for the MAX31790 ++ sensor chips. ++ ++ This driver can also be built as a module. If so, the module ++ will be called max31790. ++ + config SENSORS_MAX6639 + tristate "Maxim MAX6639 sensor chip" + depends on I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 8837a7b..1e251ca 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -108,6 +108,7 @@ obj-$(CONFIG_SENSORS_MAX16065) += max16065.o + obj-$(CONFIG_SENSORS_MAX1619) += max1619.o + obj-$(CONFIG_SENSORS_MAX1668) += max1668.o + obj-$(CONFIG_SENSORS_MAX197) += max197.o ++obj-$(CONFIG_SENSORS_MAX31790) += max31790.o + obj-$(CONFIG_SENSORS_MAX6639) += max6639.o + obj-$(CONFIG_SENSORS_MAX6642) += max6642.o + obj-$(CONFIG_SENSORS_MAX6650) += max6650.o +diff --git a/drivers/hwmon/max31790.c b/drivers/hwmon/max31790.c +new file mode 100644 +index 0000000..0182ebd +--- /dev/null ++++ b/drivers/hwmon/max31790.c +@@ -0,0 +1,742 @@ ++/* ++ * max31790.c - Part of lm_sensors, Linux kernel modules for hardware ++ * monitoring. ++ * ++ * (C) 2015 by Il Han ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* MAX31790 registers */ ++#define MAX31790_REG_GLOBAL_CONFIG 0x00 ++#define MAX31790_REG_FAN_CONFIG(ch) (0x02 + (ch)) ++#define MAX31790_REG_FAN_DYNAMICS(ch) (0x08 + (ch)) ++#define MAX31790_REG_FAN_FAULT_STATUS2 0x10 ++#define MAX31790_REG_FAN_FAULT_STATUS1 0x11 ++#define MAX31790_REG_FAN_FAULT_MASK2 0x12 ++#define MAX31790_REG_FAN_FAULT_MASK1 0x13 ++#define MAX31790_REG_TACH_COUNT(ch) (0x18 + (ch) * 2) ++#define MAX31790_REG_PWM_DUTY_CYCLE(ch) (0x30 + (ch) * 2) ++#define MAX31790_REG_PWMOUT(ch) (0x40 + (ch) * 2) ++#define MAX31790_REG_TARGET_COUNT(ch) (0x50 + (ch) * 2) ++ ++/* Fan Config register bits */ ++#define MAX31790_FAN_CFG_RPM_MODE 0x80 ++#define MAX31790_FAN_CFG_TACH_INPUT_EN 0x08 ++#define MAX31790_FAN_CFG_TACH_INPUT 0x01 ++ ++/* Fan Dynamics register bits */ ++#define MAX31790_FAN_DYN_SR_SHIFT 5 ++#define MAX31790_FAN_DYN_SR_MASK 0xE0 ++#define SR_FROM_REG(reg) (((reg) & MAX31790_FAN_DYN_SR_MASK) \ ++ >> MAX31790_FAN_DYN_SR_SHIFT) ++ ++#define FAN_RPM_MIN 120 ++#define FAN_RPM_MAX 7864320 ++ ++#define RPM_FROM_REG(reg, sr) (((reg) >> 4) ? \ ++ ((60 * (sr) * 8192) / ((reg) >> 4)) : \ ++ FAN_RPM_MAX) ++#define RPM_TO_REG(rpm, sr) ((60 * (sr) * 8192) / ((rpm) * 2)) ++ ++#define NR_CHANNEL 6 ++ ++/* ++ * Client data (each client gets its own) ++ */ ++struct max31790_data { ++ struct i2c_client *client; ++ struct mutex update_lock; ++ bool valid; /* zero until following fields are valid */ ++ unsigned long last_updated; /* in jiffies */ ++ ++ /* register values */ ++ u8 fan_config[NR_CHANNEL]; ++ u8 fan_dynamics[NR_CHANNEL]; ++ u16 fault_status; ++ u16 fault_mask; ++ u16 tach[NR_CHANNEL * 2]; ++ u16 pwm[NR_CHANNEL]; ++ u16 target_count[NR_CHANNEL]; ++}; ++ ++static struct max31790_data *max31790_update_device(struct device *dev) ++{ ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ struct max31790_data *ret = data; ++ int i; ++ int rv; ++ ++ mutex_lock(&data->update_lock); ++ ++ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS1); ++ if (rv < 0) ++ goto abort; ++ data->fault_status = rv & 0x3F; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_STATUS2); ++ if (rv < 0) ++ goto abort; ++ data->fault_status |= (rv & 0x3F) << 6; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_MASK1); ++ if (rv < 0) ++ goto abort; ++ data->fault_mask = rv & 0x3F; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_FAULT_MASK2); ++ if (rv < 0) ++ goto abort; ++ data->fault_mask |= (rv & 0x3F) << 6; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[i] = rv; ++ ++ if (data->fan_config[i] ++ & MAX31790_FAN_CFG_TACH_INPUT) { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TACH_COUNT(NR_CHANNEL ++ + i)); ++ if (rv < 0) ++ goto abort; ++ data->tach[NR_CHANNEL + i] = rv; ++ } else { ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_PWMOUT(i)); ++ if (rv < 0) ++ goto abort; ++ data->pwm[i] = rv; ++ ++ rv = i2c_smbus_read_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(i)); ++ if (rv < 0) ++ goto abort; ++ data->target_count[i] = rv; ++ } ++ } ++ ++ data->last_updated = jiffies; ++ data->valid = true; ++ } ++ goto done; ++ ++abort: ++ data->valid = false; ++ ret = ERR_PTR(rv); ++ ++done: ++ mutex_unlock(&data->update_lock); ++ ++ return ret; ++} ++ ++static const u8 tach_period[8] = { 1, 2, 4, 8, 16, 32, 32, 32 }; ++ ++static u8 get_tach_period(u8 fan_dynamics) ++{ ++ return tach_period[SR_FROM_REG(fan_dynamics)]; ++} ++ ++static u8 bits_for_tach_period(int rpm) ++{ ++ u8 bits; ++ ++ if (rpm < 500) ++ bits = 0x0; ++ else if (rpm < 1000) ++ bits = 0x1; ++ else if (rpm < 2000) ++ bits = 0x2; ++ else if (rpm < 4000) ++ bits = 0x3; ++ else if (rpm < 8000) ++ bits = 0x4; ++ else ++ bits = 0x5; ++ ++ return bits; ++} ++ ++static ssize_t get_fan(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int sr, rpm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ sr = get_tach_period(data->fan_dynamics[attr->index]); ++ rpm = RPM_FROM_REG(data->tach[attr->index], sr); ++ ++ return sprintf(buf, "%d\n", rpm); ++} ++ ++static ssize_t get_fan_target(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int sr, rpm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ sr = get_tach_period(data->fan_dynamics[attr->index]); ++ rpm = RPM_FROM_REG(data->target_count[attr->index], sr); ++ ++ return sprintf(buf, "%d\n", rpm); ++} ++ ++static ssize_t set_fan_target(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ u8 bits; ++ int sr; ++ int target_count; ++ unsigned long rpm; ++ int err; ++ ++ err = kstrtoul(buf, 10, &rpm); ++ if (err) ++ return err; ++ ++ mutex_lock(&data->update_lock); ++ ++ rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX); ++ bits = bits_for_tach_period(rpm); ++ data->fan_dynamics[attr->index] = ++ ((data->fan_dynamics[attr->index] ++ & ~MAX31790_FAN_DYN_SR_MASK) ++ | (bits << MAX31790_FAN_DYN_SR_SHIFT)); ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(attr->index), ++ data->fan_dynamics[attr->index]); ++ ++ if (err < 0) { ++ mutex_unlock(&data->update_lock); ++ return err; ++ } ++ ++ sr = get_tach_period(data->fan_dynamics[attr->index]); ++ target_count = RPM_TO_REG(rpm, sr); ++ target_count = clamp_val(target_count, 0x1, 0x7FF); ++ ++ data->target_count[attr->index] = target_count << 5; ++ ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_TARGET_COUNT(attr->index), ++ data->target_count[attr->index]); ++ ++ mutex_unlock(&data->update_lock); ++ ++ if (err < 0) ++ return err; ++ ++ return count; ++} ++ ++static ssize_t get_pwm(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int pwm; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ pwm = data->pwm[attr->index] >> 8; ++ ++ return sprintf(buf, "%d\n", pwm); ++} ++ ++static ssize_t set_pwm(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ unsigned long pwm; ++ int err; ++ ++ err = kstrtoul(buf, 10, &pwm); ++ if (err) ++ return err; ++ ++ if (pwm > 255) ++ return -EINVAL; ++ ++ mutex_lock(&data->update_lock); ++ ++ data->pwm[attr->index] = pwm << 8; ++ err = i2c_smbus_write_word_swapped(client, ++ MAX31790_REG_PWMOUT(attr->index), ++ data->pwm[attr->index]); ++ ++ mutex_unlock(&data->update_lock); ++ ++ if (err < 0) ++ return err; ++ ++ return count; ++} ++ ++static ssize_t get_pwm_enable(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int mode; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ if (data->fan_config[attr->index] & MAX31790_FAN_CFG_RPM_MODE) ++ mode = 2; ++ else if (data->fan_config[attr->index] & MAX31790_FAN_CFG_TACH_INPUT_EN) ++ mode = 1; ++ else ++ mode = 0; ++ ++ return sprintf(buf, "%d\n", mode); ++} ++ ++static ssize_t set_pwm_enable(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ unsigned long mode; ++ int err; ++ ++ err = kstrtoul(buf, 10, &mode); ++ if (err) ++ return err; ++ ++ switch (mode) { ++ case 0: ++ data->fan_config[attr->index] = ++ data->fan_config[attr->index] ++ & ~(MAX31790_FAN_CFG_TACH_INPUT_EN ++ | MAX31790_FAN_CFG_RPM_MODE); ++ break; ++ case 1: ++ data->fan_config[attr->index] = ++ (data->fan_config[attr->index] ++ | MAX31790_FAN_CFG_TACH_INPUT_EN) ++ & ~MAX31790_FAN_CFG_RPM_MODE; ++ break; ++ case 2: ++ data->fan_config[attr->index] = ++ data->fan_config[attr->index] ++ | MAX31790_FAN_CFG_TACH_INPUT_EN ++ | MAX31790_FAN_CFG_RPM_MODE; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ mutex_lock(&data->update_lock); ++ ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(attr->index), ++ data->fan_config[attr->index]); ++ ++ mutex_unlock(&data->update_lock); ++ ++ if (err < 0) ++ return err; ++ ++ return count; ++} ++ ++static ssize_t get_fan_fault(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int fault; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ fault = !!(data->fault_status & (1 << attr->index)); ++ ++ return sprintf(buf, "%d\n", fault); ++} ++ ++static ssize_t get_fan_fault_mask(struct device *dev, ++ struct device_attribute *devattr, char *buf) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = max31790_update_device(dev); ++ int mask; ++ ++ if (IS_ERR(data)) ++ return PTR_ERR(data); ++ ++ mask = !!(data->fault_mask & (1 << attr->index)); ++ ++ return sprintf(buf, "%d\n", mask); ++} ++ ++static ssize_t set_fan_fault_mask(struct device *dev, ++ struct device_attribute *devattr, ++ const char *buf, size_t count) ++{ ++ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct i2c_client *client = data->client; ++ unsigned long val, mask; ++ unsigned int index = attr->index; ++ u16 fault_mask = 0; ++ int err; ++ ++ /* if the value is illegal, return error */ ++ err = kstrtoul(buf, 10, &val); ++ if (err) ++ return err; ++ ++ mutex_lock(&data->update_lock); ++ ++ /* read setting from database */ ++ fault_mask = data->fault_mask; ++ mask = !!(fault_mask & (1 << index)); ++ ++ /* skip this action for setting fault mask ++ * when target value is the same with register ++ */ ++ if (mask == val) { ++ mutex_unlock(&data->update_lock); ++ goto quit; ++ } ++ ++ /* change setting */ ++ if (val == 1) ++ fault_mask |= (1 << index); ++ else ++ fault_mask &= ~(1 << index); ++ ++ /* write to database */ ++ data->fault_mask = fault_mask; ++ ++ if ( index <= 6 ) { ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_FAULT_MASK1, ++ (data->fault_mask & 0x3F)); ++ } ++ else { ++ err = i2c_smbus_write_byte_data(client, ++ MAX31790_REG_FAN_FAULT_MASK2, ++ ((data->fault_mask >> 6) & 0x3F)); ++ } ++ mutex_unlock(&data->update_lock); ++ ++ if (err < 0) ++ return err; ++ ++quit: ++ return count; ++} ++ ++static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); ++static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); ++static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3); ++static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, get_fan, NULL, 4); ++static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, get_fan, NULL, 5); ++ ++static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_fault, NULL, 0); ++static SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, get_fan_fault, NULL, 1); ++static SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, get_fan_fault, NULL, 2); ++static SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, get_fan_fault, NULL, 3); ++static SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, get_fan_fault, NULL, 4); ++static SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, get_fan_fault, NULL, 5); ++ ++static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, get_fan, NULL, 6); ++static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, get_fan, NULL, 7); ++static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, get_fan, NULL, 8); ++static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, get_fan, NULL, 9); ++static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, get_fan, NULL, 10); ++static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, get_fan, NULL, 11); ++ ++static SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, get_fan_fault, NULL, 6); ++static SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, get_fan_fault, NULL, 7); ++static SENSOR_DEVICE_ATTR(fan9_fault, S_IRUGO, get_fan_fault, NULL, 8); ++static SENSOR_DEVICE_ATTR(fan10_fault, S_IRUGO, get_fan_fault, NULL, 9); ++static SENSOR_DEVICE_ATTR(fan11_fault, S_IRUGO, get_fan_fault, NULL, 10); ++static SENSOR_DEVICE_ATTR(fan12_fault, S_IRUGO, get_fan_fault, NULL, 11); ++ ++static SENSOR_DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 0); ++static SENSOR_DEVICE_ATTR(fan2_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 1); ++static SENSOR_DEVICE_ATTR(fan3_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 2); ++static SENSOR_DEVICE_ATTR(fan4_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 3); ++static SENSOR_DEVICE_ATTR(fan5_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 4); ++static SENSOR_DEVICE_ATTR(fan6_target, S_IWUSR | S_IRUGO, ++ get_fan_target, set_fan_target, 5); ++ ++static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 0); ++static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 1); ++static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 2); ++static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 3); ++static SENSOR_DEVICE_ATTR(pwm5, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 4); ++static SENSOR_DEVICE_ATTR(pwm6, S_IWUSR | S_IRUGO, get_pwm, set_pwm, 5); ++ ++static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 0); ++static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 1); ++static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 2); ++static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 3); ++static SENSOR_DEVICE_ATTR(pwm5_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 4); ++static SENSOR_DEVICE_ATTR(pwm6_enable, S_IWUSR | S_IRUGO, ++ get_pwm_enable, set_pwm_enable, 5); ++ ++static SENSOR_DEVICE_ATTR(fan1_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 0); ++static SENSOR_DEVICE_ATTR(fan2_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 1); ++static SENSOR_DEVICE_ATTR(fan3_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 2); ++static SENSOR_DEVICE_ATTR(fan4_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 3); ++static SENSOR_DEVICE_ATTR(fan5_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 4); ++static SENSOR_DEVICE_ATTR(fan6_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 5); ++ ++static SENSOR_DEVICE_ATTR(fan7_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 6); ++static SENSOR_DEVICE_ATTR(fan8_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 7); ++static SENSOR_DEVICE_ATTR(fan9_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 8); ++static SENSOR_DEVICE_ATTR(fan10_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 9); ++static SENSOR_DEVICE_ATTR(fan11_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 10); ++static SENSOR_DEVICE_ATTR(fan12_fault_mask, S_IWUSR | S_IRUGO, ++ get_fan_fault_mask, set_fan_fault_mask, 11); ++ ++static struct attribute *max31790_attrs[] = { ++ &sensor_dev_attr_fan1_input.dev_attr.attr, ++ &sensor_dev_attr_fan2_input.dev_attr.attr, ++ &sensor_dev_attr_fan3_input.dev_attr.attr, ++ &sensor_dev_attr_fan4_input.dev_attr.attr, ++ &sensor_dev_attr_fan5_input.dev_attr.attr, ++ &sensor_dev_attr_fan6_input.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_fault.dev_attr.attr, ++ &sensor_dev_attr_fan2_fault.dev_attr.attr, ++ &sensor_dev_attr_fan3_fault.dev_attr.attr, ++ &sensor_dev_attr_fan4_fault.dev_attr.attr, ++ &sensor_dev_attr_fan5_fault.dev_attr.attr, ++ &sensor_dev_attr_fan6_fault.dev_attr.attr, ++ ++ &sensor_dev_attr_fan7_input.dev_attr.attr, ++ &sensor_dev_attr_fan8_input.dev_attr.attr, ++ &sensor_dev_attr_fan9_input.dev_attr.attr, ++ &sensor_dev_attr_fan10_input.dev_attr.attr, ++ &sensor_dev_attr_fan11_input.dev_attr.attr, ++ &sensor_dev_attr_fan12_input.dev_attr.attr, ++ ++ &sensor_dev_attr_fan7_fault.dev_attr.attr, ++ &sensor_dev_attr_fan8_fault.dev_attr.attr, ++ &sensor_dev_attr_fan9_fault.dev_attr.attr, ++ &sensor_dev_attr_fan10_fault.dev_attr.attr, ++ &sensor_dev_attr_fan11_fault.dev_attr.attr, ++ &sensor_dev_attr_fan12_fault.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_target.dev_attr.attr, ++ &sensor_dev_attr_fan2_target.dev_attr.attr, ++ &sensor_dev_attr_fan3_target.dev_attr.attr, ++ &sensor_dev_attr_fan4_target.dev_attr.attr, ++ &sensor_dev_attr_fan5_target.dev_attr.attr, ++ &sensor_dev_attr_fan6_target.dev_attr.attr, ++ ++ &sensor_dev_attr_pwm1.dev_attr.attr, ++ &sensor_dev_attr_pwm2.dev_attr.attr, ++ &sensor_dev_attr_pwm3.dev_attr.attr, ++ &sensor_dev_attr_pwm4.dev_attr.attr, ++ &sensor_dev_attr_pwm5.dev_attr.attr, ++ &sensor_dev_attr_pwm6.dev_attr.attr, ++ ++ &sensor_dev_attr_pwm1_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm2_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm3_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm4_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm5_enable.dev_attr.attr, ++ &sensor_dev_attr_pwm6_enable.dev_attr.attr, ++ ++ &sensor_dev_attr_fan1_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan2_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan3_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan4_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan5_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan6_fault_mask.dev_attr.attr, ++ ++ &sensor_dev_attr_fan7_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan8_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan9_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan10_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan11_fault_mask.dev_attr.attr, ++ &sensor_dev_attr_fan12_fault_mask.dev_attr.attr, ++ NULL ++}; ++ ++static umode_t max31790_attrs_visible(struct kobject *kobj, ++ struct attribute *a, int n) ++{ ++ struct device *dev = container_of(kobj, struct device, kobj); ++ struct max31790_data *data = dev_get_drvdata(dev); ++ struct device_attribute *devattr = ++ container_of(a, struct device_attribute, attr); ++ int index = to_sensor_dev_attr(devattr)->index % NR_CHANNEL; ++ u8 fan_config; ++ ++ fan_config = data->fan_config[index]; ++ ++ if (n >= NR_CHANNEL * 7 && n < NR_CHANNEL * 8) { ++ return a->mode; ++ } ++ if (n >= NR_CHANNEL * 8 && n < NR_CHANNEL * 9) { ++ if (!(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0; ++ else ++ return a->mode; ++ } ++ if (n >= NR_CHANNEL * 2 && n < NR_CHANNEL * 4 && ++ !(fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0; ++ if (n >= NR_CHANNEL * 4 && (fan_config & MAX31790_FAN_CFG_TACH_INPUT)) ++ return 0; ++ ++ return a->mode; ++} ++ ++static const struct attribute_group max31790_group = { ++ .attrs = max31790_attrs, ++ .is_visible = max31790_attrs_visible, ++}; ++__ATTRIBUTE_GROUPS(max31790); ++ ++static int max31790_init_client(struct i2c_client *client, ++ struct max31790_data *data) ++{ ++ int i, rv; ++ ++ for (i = 0; i < NR_CHANNEL; i++) { ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_CONFIG(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_config[i] = rv; ++ ++ rv = i2c_smbus_read_byte_data(client, ++ MAX31790_REG_FAN_DYNAMICS(i)); ++ if (rv < 0) ++ return rv; ++ data->fan_dynamics[i] = rv; ++ } ++ ++ return 0; ++} ++ ++static int max31790_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct i2c_adapter *adapter = client->adapter; ++ struct device *dev = &client->dev; ++ struct max31790_data *data; ++ struct device *hwmon_dev; ++ int err; ++ ++ if (!i2c_check_functionality(adapter, ++ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) ++ return -ENODEV; ++ ++ data = devm_kzalloc(dev, sizeof(struct max31790_data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->client = client; ++ mutex_init(&data->update_lock); ++ ++ /* ++ * Initialize the max31790 chip ++ */ ++ err = max31790_init_client(client, data); ++ if (err) ++ return err; ++ ++ hwmon_dev = devm_hwmon_device_register_with_groups(dev, ++ client->name, data, max31790_groups); ++ ++ return PTR_ERR_OR_ZERO(hwmon_dev); ++} ++ ++static const struct i2c_device_id max31790_id[] = { ++ { "max31790", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max31790_id); ++ ++static struct i2c_driver max31790_driver = { ++ .class = I2C_CLASS_HWMON, ++ .probe = max31790_probe, ++ .driver = { ++ .name = "max31790", ++ }, ++ .id_table = max31790_id, ++}; ++ ++module_i2c_driver(max31790_driver); ++ ++MODULE_AUTHOR("Il Han "); ++MODULE_DESCRIPTION("MAX31790 sensor driver"); ++MODULE_LICENSE("GPL"); ++ +-- +2.1.4 + diff --git a/patch/driver-i2c-bus-ismt-i801-support-intel-denverton.patch b/patch/driver-i2c-bus-ismt-i801-support-intel-denverton.patch new file mode 100644 index 000000000000..ec45bc236fa8 --- /dev/null +++ b/patch/driver-i2c-bus-ismt-i801-support-intel-denverton.patch @@ -0,0 +1,86 @@ +From: "Eddy.Weng" + +Patch intel Denverton ID in i2c-i801.c and i2c-ismt.c. + +Patch driver code from Linux Kernel v4.6 +--- + drivers/i2c/busses/i2c-i801.c | 14 ++++++++++++++ + drivers/i2c/busses/i2c-ismt.c | 2 ++ + 2 files changed, 16 insertions(+) + +diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c +index bb7d46b..71ce414 100644 +--- a/drivers/i2c/busses/i2c-i801.c ++++ b/drivers/i2c/busses/i2c-i801.c +@@ -61,6 +61,7 @@ + Coleto Creek (PCH) 0x23b0 32 hard yes yes yes + Wildcat Point-LP (PCH) 0x9ca2 32 hard yes yes yes + BayTrail (SOC) 0x0f12 32 hard yes yes yes ++ DNV (SOC) 0x19df 32 hard yes yes yes + + Features supported by this driver: + Software PEC no +@@ -163,6 +164,7 @@ + + /* Older devices have their ID defined in */ + #define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS 0x0f12 ++#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df + #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 + #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS 0x1d22 + /* Patsburg also has three 'Integrated Device Function' SMBus controllers */ +@@ -736,6 +738,10 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, + /* NB: page 240 of ICH5 datasheet shows that the R/#W + * bit should be cleared here, even when reading */ + outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); ++ if (priv->pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) { ++ outb_p(inb_p(SMBHSTADD(priv)) | (read_write & 0x01), ++ SMBHSTADD(priv)); ++ } + if (read_write == I2C_SMBUS_READ) { + /* NB: page 240 of ICH5 datasheet also shows + * that DATA1 is the cmd field when reading */ +@@ -841,6 +847,7 @@ static const struct pci_device_id i801_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, + { 0, } + }; + +@@ -1143,6 +1150,13 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) + + priv->pci_dev = dev; + switch (dev->device) { ++ case PCI_DEVICE_ID_INTEL_DNV_SMBUS: ++ priv->features |= FEATURE_I2C_BLOCK_READ; ++ priv->features |= FEATURE_IRQ; ++ priv->features |= FEATURE_SMBUS_PEC; ++ priv->features |= FEATURE_BLOCK_BUFFER; ++ break; ++ + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: + case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: +diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c +index d9ee43c..7464501 100644 +--- a/drivers/i2c/busses/i2c-ismt.c ++++ b/drivers/i2c/busses/i2c-ismt.c +@@ -79,6 +79,7 @@ + /* PCI DIDs for the Intel SMBus Message Transport (SMT) Devices */ + #define PCI_DEVICE_ID_INTEL_S1200_SMT0 0x0c59 + #define PCI_DEVICE_ID_INTEL_S1200_SMT1 0x0c5a ++#define PCI_DEVICE_ID_INTEL_DNV_SMT 0x19ac + #define PCI_DEVICE_ID_INTEL_AVOTON_SMT 0x1f15 + + #define ISMT_DESC_ENTRIES 32 /* number of descriptor entries */ +@@ -185,6 +186,7 @@ struct ismt_priv { + static const struct pci_device_id ismt_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) }, + { 0, } + }; +-- +2.1.4 + diff --git a/patch/series b/patch/series index fee5fe13e86c..5965e9c3eb0e 100644 --- a/patch/series +++ b/patch/series @@ -5,6 +5,7 @@ config-mlnx-sn2700.patch config-dell-z9100.patch config-ingrasys-s9100.patch config-arista-7060-cx32s.patch +config-mitac-ly1200.patch driver-at24-fix-odd-length-two-byte-access.patch driver-hwmon-max6620.patch driver-hwmon-max6620-fix-rpm-calc.patch @@ -28,3 +29,5 @@ linux-3.19-mmc-sdhci-pci-enable-sdhci-doesn-t-support-hs200-qui.patch rtnetlink-catch-EOPNOTSUPP-errors.patch bridge-per-port-multicast-broadcast-flood-flags.patch driver-support-tun-config-carrier-enable.patch +driver-i2c-bus-ismt-i801-support-intel-denverton.patch +driver-hwmon-max31790.patch