X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=it87.c;h=ce689ae7698debe468a41f9f0402655db35d07b4;hb=ea3105845e1c30689b8b71c854fae719642b7a5a;hp=74ac8e39a67224359d56f27158a0b0868547425d;hpb=cc3bd8d16338c958a69b1a1fc9039a9c8319ef63;p=groeck-it87 diff --git a/it87.c b/it87.c index 74ac8e3..ce689ae 100644 --- a/it87.c +++ b/it87.c @@ -10,7 +10,9 @@ * This driver supports only the Environment Controller in the IT8705F and * similar parts. The other devices are supported by different drivers. * - * Supports: IT8705F Super I/O chip w/LPC interface + * Supports: IT8603E Super I/O chip w/LPC interface + * IT8623E Super I/O chip w/LPC interface + * IT8705F Super I/O chip w/LPC interface * IT8712F Super I/O chip w/LPC interface * IT8716F Super I/O chip w/LPC interface * IT8718F Super I/O chip w/LPC interface @@ -27,7 +29,7 @@ * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron - * Copyright (C) 2005-2010 Jean Delvare + * Copyright (C) 2005-2010 Jean Delvare * * 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 @@ -61,18 +63,12 @@ #include #include #include - -#ifndef kstrtol -#define kstrtol strict_strtol -#endif -#ifndef kstrtoul -#define kstrtoul strict_strtoul -#endif +#include "compat.h" #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8781, it8782, it8783 }; + it8772, it8781, it8782, it8783, it8603 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -124,10 +120,8 @@ static inline int superio_enter(void) /* * Try to reserve REG and REG + 1 for exclusive access. */ -#ifdef request_muxed_region if (!request_muxed_region(REG, 2, DRVNAME)) return -EBUSY; -#endif outb(0x87, REG); outb(0x01, REG); @@ -140,9 +134,7 @@ static inline void superio_exit(void) { outb(0x02, REG); outb(0x02, VAL); -#ifdef request_muxed_region release_region(REG, 2); -#endif } /* Logical device 4 registers */ @@ -159,6 +151,8 @@ static inline void superio_exit(void) #define IT8781F_DEVID 0x8781 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 +#define IT8603E_DEVID 0x8603 +#define IT8623E_DEVID 0x8623 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -220,6 +214,8 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; +static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 }; + #define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_CTL 0x14 #define IT87_REG_PWM(nr) (0x15 + (nr)) @@ -235,6 +231,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_VIN_ENABLE 0x50 #define IT87_REG_TEMP_ENABLE 0x51 +#define IT87_REG_TEMP_EXTRA 0x55 #define IT87_REG_BEEP_ENABLE 0x5c #define IT87_REG_CHIPID 0x58 @@ -242,6 +239,124 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; #define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i)) #define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i)) +struct it87_devices { + const char *name; + u16 features; + u8 peci_mask; + u8 old_peci_mask; +}; + +#define FEAT_12MV_ADC (1 << 0) +#define FEAT_NEWER_AUTOPWM (1 << 1) +#define FEAT_OLD_AUTOPWM (1 << 2) +#define FEAT_16BIT_FANS (1 << 3) +#define FEAT_TEMP_OFFSET (1 << 4) +#define FEAT_TEMP_PECI (1 << 5) +#define FEAT_TEMP_OLD_PECI (1 << 6) +#define FEAT_FAN16_CONFIG (1 << 7) /* Need to enable 16-bit fans */ +#define FEAT_FIVE_FANS (1 << 8) /* Supports five fans */ + +static const struct it87_devices it87_devices[] = { + [it87] = { + .name = "it87", + .features = FEAT_OLD_AUTOPWM | FEAT_FAN16_CONFIG, + /* may need to overwrite */ + }, + [it8712] = { + .name = "it8712", + .features = FEAT_OLD_AUTOPWM | FEAT_FAN16_CONFIG, + /* may need to overwrite */ + }, + [it8716] = { + .name = "it8716", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, + }, + [it8718] = { + .name = "it8718", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, + .old_peci_mask = 0x4, + }, + [it8720] = { + .name = "it8720", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, + .old_peci_mask = 0x4, + }, + [it8721] = { + .name = "it8721", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI + | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS, + .peci_mask = 0x05, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, + [it8728] = { + .name = "it8728", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS, + .peci_mask = 0x07, + }, + [it8771] = { + .name = "it8771", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + /* PECI: guesswork */ + /* 12mV ADC (OHM) */ + /* 16 bit fans (OHM) */ + /* three fans, always 16 bit (guesswork) */ + .peci_mask = 0x07, + }, + [it8772] = { + .name = "it8772", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + /* PECI (coreboot) */ + /* 12mV ADC (HWSensors4, OHM) */ + /* 16 bit fans (HWSensors4, OHM) */ + /* three fans, always 16 bit (datasheet) */ + .peci_mask = 0x07, + }, + [it8781] = { + .name = "it8781", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, + .old_peci_mask = 0x4, + }, + [it8782] = { + .name = "it8782", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, + .old_peci_mask = 0x4, + }, + [it8783] = { + .name = "it8783", + .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET + | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG, + .old_peci_mask = 0x4, + }, + [it8603] = { + .name = "it8603", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI, + .peci_mask = 0x07, + }, +}; + +#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS) +#define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC) +#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM) +#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM) +#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET) +#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \ + ((data)->peci_mask & (1 << nr))) +#define has_temp_old_peci(data, nr) \ + (((data)->features & FEAT_TEMP_OLD_PECI) && \ + ((data)->old_peci_mask & (1 << nr))) +#define has_fan16_config(data) (has_16bit_fans(data) && \ + ((data)->features & FEAT_FAN16_CONFIG)) +#define has_five_fans(data) ((data)->features & FEAT_FIVE_FANS) struct it87_sio_data { enum chips type; @@ -251,9 +366,11 @@ struct it87_sio_data { u8 beep_pin; u8 internal; /* Internal sensors can be labeled */ /* Features skipped based on config or DMI */ + u16 skip_in; u8 skip_vid; u8 skip_fan; u8 skip_pwm; + u8 skip_temp; }; /* @@ -263,7 +380,9 @@ struct it87_sio_data { struct it87_data { struct device *hwmon_dev; enum chips type; - u8 revision; + u16 features; + u8 peci_mask; + u8 old_peci_mask; unsigned short addr; const char *name; @@ -272,16 +391,13 @@ struct it87_data { unsigned long last_updated; /* In jiffies */ u16 in_scaled; /* Internal voltage sensors are scaled */ - u8 in[9]; /* Register value */ - u8 in_max[8]; /* Register value */ - u8 in_min[8]; /* Register value */ + u8 in[10][3]; /* [nr][0]=in, [1]=min, [2]=max */ u8 has_fan; /* Bitfield, fans enabled */ - u16 fan[5]; /* Register values, possibly combined */ - u16 fan_min[5]; /* Register values, possibly combined */ - s8 temp[3]; /* Register value */ - s8 temp_high[3]; /* Register value */ - s8 temp_low[3]; /* Register value */ - u8 sensor; /* Register value */ + u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */ + u8 has_temp; /* Bitfield, temp sensors enabled */ + s8 temp[3][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */ + u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */ + u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */ u8 fan_div[3]; /* Register encoding, shifted right */ u8 vid; /* Register encoding, combined */ u8 vrm; @@ -309,80 +425,38 @@ struct it87_data { s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ }; -static inline int has_12mv_adc(const struct it87_data *data) +static int adc_lsb(const struct it87_data *data, int nr) { - /* - * IT8721F and later have a 12 mV ADC, also with internal scaling - * on selected inputs. - */ - return data->type == it8721 - || data->type == it8728 - || data->type == it8771 - || data->type == it8772; -} - -static inline int has_newer_autopwm(const struct it87_data *data) -{ - /* - * IT8721F and later have separate registers for the temperature - * mapping and the manual duty cycle. - * [ Assume that also applies to IT8771 / IT8772 ] - */ - return data->type == it8721 - || data->type == it8728 - || data->type == it8771 - || data->type == it8772; + int lsb = has_12mv_adc(data) ? 12 : 16; + if (data->in_scaled & (1 << nr)) + lsb <<= 1; + return lsb; } static u8 in_to_reg(const struct it87_data *data, int nr, long val) { - long lsb; - - if (has_12mv_adc(data)) { - if (data->in_scaled & (1 << nr)) - lsb = 24; - else - lsb = 12; - } else { - if (data->in_scaled & (1 << nr)) - lsb = 32; - else - lsb = 16; - } - - val = DIV_ROUND_CLOSEST(val, lsb); - return SENSORS_LIMIT(val, 0, 255); + val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr)); + return clamp_val(val, 0, 255); } static int in_from_reg(const struct it87_data *data, int nr, int val) { - if (has_12mv_adc(data)) { - if (data->in_scaled & (1 << nr)) - return val * 24; - else - return val * 12; - } else { - if (data->in_scaled & (1 << nr)) - return val * 32; - else - return val * 16; - } + return val * adc_lsb(data, nr); } static inline u8 FAN_TO_REG(long rpm, int div) { if (rpm == 0) return 255; - rpm = SENSORS_LIMIT(rpm, 1, 1000000); - return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, - 254); + rpm = clamp_val(rpm, 1, 1000000); + return clamp_val((1350000 + rpm * div / 2) / (rpm * div), 1, 254); } static inline u16 FAN16_TO_REG(long rpm) { if (rpm == 0) return 0xffff; - return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe); + return clamp_val((1350000 + rpm) / (rpm * 2), 1, 0xfffe); } #define FAN_FROM_REG(val, div) ((val) == 0 ? -1 : (val) == 255 ? 0 : \ @@ -391,8 +465,8 @@ static inline u16 FAN16_TO_REG(long rpm) #define FAN16_FROM_REG(val) ((val) == 0 ? -1 : (val) == 0xffff ? 0 : \ 1350000 / ((val) * 2)) -#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val) < 0 ? (((val) - 500) / 1000) : \ - ((val) + 500) / 1000), -128, 127)) +#define TEMP_TO_REG(val) (clamp_val(((val) < 0 ? (((val) - 500) / 1000) : \ + ((val) + 500) / 1000), -128, 127)) #define TEMP_FROM_REG(val) ((val) * 1000) static u8 pwm_to_reg(const struct it87_data *data, long val) @@ -432,40 +506,8 @@ static const unsigned int pwm_freq[8] = { 750000 / 128, }; -static inline int has_16bit_fans(const struct it87_data *data) -{ - /* - * IT8705F Datasheet 0.4.1, 3h == Version G. - * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. - * These are the first revisions with 16-bit tachometer support. - */ - return (data->type == it87 && data->revision >= 0x03) - || (data->type == it8712 && data->revision >= 0x08) - || data->type == it8716 - || data->type == it8718 - || data->type == it8720 - || data->type == it8721 - || data->type == it8728 - || data->type == it8771 - || data->type == it8772 - || data->type == it8781 - || data->type == it8782 - || data->type == it8783; -} - -static inline int has_old_autopwm(const struct it87_data *data) -{ - /* - * The old automatic fan speed control interface is implemented - * by IT8705F chips up to revision F and IT8712F chips up to - * revision G. - */ - return (data->type == it87 && data->revision < 0x03) - || (data->type == it8712 && data->revision < 0x08); -} - static int it87_probe(struct platform_device *pdev); -static int __devexit it87_remove(struct platform_device *pdev); +static int it87_remove(struct platform_device *pdev); static int it87_read_value(struct it87_data *data, u8 reg); static void it87_write_value(struct it87_data *data, u8 reg, u8 value); @@ -476,48 +518,29 @@ static void it87_init_device(struct platform_device *pdev); static struct platform_driver it87_driver = { .driver = { - .owner = THIS_MODULE, .name = DRVNAME, }, .probe = it87_probe, - .remove = __devexit_p(it87_remove), + .remove = it87_remove, }; static ssize_t show_in(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr])); -} - -static ssize_t show_in_min(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr])); + return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index])); } -static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t set_in(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr])); -} - -static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); unsigned long val; @@ -526,159 +549,168 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - data->in_min[nr] = in_to_reg(data, nr, val); - it87_write_value(data, IT87_REG_VIN_MIN(nr), - data->in_min[nr]); + data->in[nr][index] = in_to_reg(data, nr, val); + it87_write_value(data, + index == 1 ? IT87_REG_VIN_MIN(nr) + : IT87_REG_VIN_MAX(nr), + data->in[nr][index]); mutex_unlock(&data->update_lock); return count; } -static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = dev_get_drvdata(dev); - unsigned long val; - - if (kstrtoul(buf, 10, &val) < 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->in_max[nr] = in_to_reg(data, nr, val); - it87_write_value(data, IT87_REG_VIN_MAX(nr), - data->in_max[nr]); - mutex_unlock(&data->update_lock); - return count; -} - -#define show_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ - show_in, NULL, offset); - -#define limit_in_offset(offset) \ -static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ - show_in_min, set_in_min, offset); \ -static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ - show_in_max, set_in_max, offset); - -show_in_offset(0); -limit_in_offset(0); -show_in_offset(1); -limit_in_offset(1); -show_in_offset(2); -limit_in_offset(2); -show_in_offset(3); -limit_in_offset(3); -show_in_offset(4); -limit_in_offset(4); -show_in_offset(5); -limit_in_offset(5); -show_in_offset(6); -limit_in_offset(6); -show_in_offset(7); -limit_in_offset(7); -show_in_offset(8); +static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in, + 0, 1); +static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in, + 0, 2); + +static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in, + 1, 1); +static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in, + 1, 2); + +static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in, + 2, 1); +static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in, + 2, 2); + +static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in, + 3, 1); +static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in, + 3, 2); + +static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in, + 4, 1); +static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in, + 4, 2); + +static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0); +static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in, + 5, 1); +static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in, + 5, 2); + +static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0); +static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in, + 6, 1); +static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in, + 6, 2); + +static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0); +static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in, + 7, 1); +static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in, + 7, 2); + +static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0); +static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0); /* 3 temperatures */ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])); -} -static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])); + return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index])); } -static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); -} -static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t set_temp(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); long val; + u8 reg, regval; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; mutex_lock(&data->update_lock); - data->temp_high[nr] = TEMP_TO_REG(val); - it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]); - mutex_unlock(&data->update_lock); - return count; -} -static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - - struct it87_data *data = dev_get_drvdata(dev); - long val; - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; + switch (index) { + default: + case 1: + reg = IT87_REG_TEMP_LOW(nr); + break; + case 2: + reg = IT87_REG_TEMP_HIGH(nr); + break; + case 3: + regval = it87_read_value(data, IT87_REG_BEEP_ENABLE); + if (!(regval & 0x80)) { + regval |= 0x80; + it87_write_value(data, IT87_REG_BEEP_ENABLE, regval); + } + data->valid = 0; + reg = IT87_REG_TEMP_OFFSET[nr]; + break; + } - mutex_lock(&data->update_lock); - data->temp_low[nr] = TEMP_TO_REG(val); - it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]); + data->temp[nr][index] = TEMP_TO_REG(val); + it87_write_value(data, reg, data->temp[nr][index]); mutex_unlock(&data->update_lock); return count; } -#define show_temp_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ - show_temp, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ - show_temp_max, set_temp_max, offset - 1); \ -static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ - show_temp_min, set_temp_min, offset - 1); - -show_temp_offset(1); -show_temp_offset(2); -show_temp_offset(3); - -static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, - char *buf) + +static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, 1); +static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 0, 2); +static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 0, 3); +static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, 1); +static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 1, 2); +static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 1, 3); +static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, 1); +static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp, + 2, 2); +static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp, + set_temp, 2, 3); + +static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr, + char *buf) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct it87_data *data = it87_update_device(dev); u8 reg = data->sensor; /* In case value is updated while used */ + u8 extra = data->extra; + if ((has_temp_peci(data, nr) && (reg >> 6 == nr + 1)) + || (has_temp_old_peci(data, nr) && (extra & 0x80))) + return sprintf(buf, "6\n"); /* Intel PECI */ if (reg & (1 << nr)) return sprintf(buf, "3\n"); /* thermal diode */ if (reg & (8 << nr)) return sprintf(buf, "4\n"); /* thermistor */ return sprintf(buf, "0\n"); /* disabled */ } -static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); int nr = sensor_attr->index; struct it87_data *data = dev_get_drvdata(dev); long val; - u8 reg; + u8 reg, extra; if (kstrtol(buf, 10, &val) < 0) return -EINVAL; @@ -686,33 +718,45 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, reg = it87_read_value(data, IT87_REG_TEMP_ENABLE); reg &= ~(1 << nr); reg &= ~(8 << nr); + if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6)) + reg &= 0x3f; + extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); + if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6)) + extra &= 0x7f; if (val == 2) { /* backwards compatibility */ - dev_warn(dev, "Sensor type 2 is deprecated, please use 4 " - "instead\n"); + dev_warn(dev, + "Sensor type 2 is deprecated, please use 4 instead\n"); val = 4; } - /* 3 = thermal diode; 4 = thermistor; 0 = disabled */ + /* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */ if (val == 3) reg |= 1 << nr; else if (val == 4) reg |= 8 << nr; + else if (has_temp_peci(data, nr) && val == 6) + reg |= (nr + 1) << 6; + else if (has_temp_old_peci(data, nr) && val == 6) + extra |= 0x80; else if (val != 0) return -EINVAL; mutex_lock(&data->update_lock); data->sensor = reg; + data->extra = extra; it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor); + if (has_temp_old_peci(data, nr)) + it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra); data->valid = 0; /* Force cache refresh */ mutex_unlock(&data->update_lock); return count; } -#define show_sensor_offset(offset) \ -static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ - show_sensor, set_sensor, offset - 1); -show_sensor_offset(1); -show_sensor_offset(2); -show_sensor_offset(3); +static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 0); +static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 1); +static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type, + set_temp_type, 2); /* 3 Fans */ @@ -720,7 +764,7 @@ static int pwm_mode(const struct it87_data *data, int nr) { int ctrl = data->fan_main_ctrl & (1 << nr); - if (ctrl == 0) /* Full speed */ + if (ctrl == 0 && data->type != it8603) /* Full speed */ return 0; if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ return 2; @@ -729,25 +773,21 @@ static int pwm_mode(const struct it87_data *data, int nr) } static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) + char *buf) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; + int speed; struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], - DIV_FROM_REG(data->fan_div[nr]))); -} -static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], - DIV_FROM_REG(data->fan_div[nr]))); + speed = has_16bit_fans(data) ? + FAN16_FROM_REG(data->fan[nr][index]) : + FAN_FROM_REG(data->fan[nr][index], + DIV_FROM_REG(data->fan_div[nr])); + return sprintf(buf, "%d\n", speed); } + static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, char *buf) { @@ -784,11 +824,13 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", pwm_freq[index]); } -static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) + +static ssize_t set_fan(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; + struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); + int nr = sattr->nr; + int index = sattr->index; struct it87_data *data = dev_get_drvdata(dev); long val; @@ -798,24 +840,36 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); - reg = it87_read_value(data, IT87_REG_FAN_DIV); - switch (nr) { - case 0: - data->fan_div[nr] = reg & 0x07; - break; - case 1: - data->fan_div[nr] = (reg >> 3) & 0x07; - break; - case 2: - data->fan_div[nr] = (reg & 0x40) ? 3 : 1; - break; + + if (has_16bit_fans(data)) { + data->fan[nr][index] = FAN16_TO_REG(val); + it87_write_value(data, IT87_REG_FAN_MIN[nr], + data->fan[nr][index] & 0xff); + it87_write_value(data, IT87_REG_FANX_MIN[nr], + data->fan[nr][index] >> 8); + } else { + reg = it87_read_value(data, IT87_REG_FAN_DIV); + switch (nr) { + case 0: + data->fan_div[nr] = reg & 0x07; + break; + case 1: + data->fan_div[nr] = (reg >> 3) & 0x07; + break; + case 2: + data->fan_div[nr] = (reg & 0x40) ? 3 : 1; + break; + } + data->fan[nr][index] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(data, IT87_REG_FAN_MIN[nr], + data->fan[nr][index]); } - data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); mutex_unlock(&data->update_lock); return count; } + static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -834,7 +888,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, old = it87_read_value(data, IT87_REG_FAN_DIV); /* Save fan min limit */ - min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); + min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr])); switch (nr) { case 0: @@ -855,8 +909,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, it87_write_value(data, IT87_REG_FAN_DIV, val); /* Restore fan min limit */ - data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); - it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]); + data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); + it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]); mutex_unlock(&data->update_lock); return count; @@ -880,8 +934,8 @@ static int check_trip_points(struct device *dev, int nr) } if (err) { - dev_err(dev, "Inconsistent trip points, not switching to " - "automatic mode\n"); + dev_err(dev, + "Inconsistent trip points, not switching to automatic mode\n"); dev_err(dev, "Adjust the trip points and try again\n"); } return err; @@ -905,6 +959,10 @@ static ssize_t set_pwm_enable(struct device *dev, return -EINVAL; } + /* IT8603E does not have on/off mode */ + if (val == 0 && data->type == it8603) + return -EINVAL; + mutex_lock(&data->update_lock); if (val == 0) { @@ -924,10 +982,13 @@ static ssize_t set_pwm_enable(struct device *dev, else /* Automatic mode */ data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); - /* set SmartGuardian mode */ - data->fan_main_ctrl |= (1 << nr); - it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, - data->fan_main_ctrl); + + if (data->type != it8603) { + /* set SmartGuardian mode */ + data->fan_main_ctrl |= (1 << nr); + it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, + data->fan_main_ctrl); + } } mutex_unlock(&data->update_lock); @@ -1129,118 +1190,106 @@ static ssize_t set_auto_temp(struct device *dev, return count; } -#define show_fan_offset(offset) \ -static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan, NULL, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan_min, set_fan_min, offset - 1); \ -static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ - show_fan_div, set_fan_div, offset - 1); - -show_fan_offset(1); -show_fan_offset(2); -show_fan_offset(3); - -#define show_pwm_offset(offset) \ -static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ - show_pwm_enable, set_pwm_enable, offset - 1); \ -static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ - show_pwm, set_pwm, offset - 1); \ -static DEVICE_ATTR(pwm##offset##_freq, \ - (offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \ - show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \ -static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \ - S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \ - offset - 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 0); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm, \ - S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ - offset - 1, 2); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm, \ - S_IRUGO, show_auto_pwm, NULL, offset - 1, 3); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 1); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 0); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 2); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 3); \ -static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp, \ - S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ - offset - 1, 4); - -show_pwm_offset(1); -show_pwm_offset(2); -show_pwm_offset(3); - -/* A different set of callbacks for 16-bit fans */ -static ssize_t show_fan16(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr])); -} - -static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = it87_update_device(dev); - return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr])); -} - -static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); - int nr = sensor_attr->index; - struct it87_data *data = dev_get_drvdata(dev); - long val; - - if (kstrtol(buf, 10, &val) < 0) - return -EINVAL; - - mutex_lock(&data->update_lock); - data->fan_min[nr] = FAN16_TO_REG(val); - it87_write_value(data, IT87_REG_FAN_MIN[nr], - data->fan_min[nr] & 0xff); - it87_write_value(data, IT87_REG_FANX_MIN[nr], - data->fan_min[nr] >> 8); - mutex_unlock(&data->update_lock); - return count; -} - -/* - * We want to use the same sysfs file names as 8-bit fans, but we need - * different variable names, so we have to use SENSOR_ATTR instead of - * SENSOR_DEVICE_ATTR. - */ -#define show_fan16_offset(offset) \ -static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \ - = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \ - show_fan16, NULL, offset - 1); \ -static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \ - = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ - show_fan16_min, set_fan16_min, offset - 1) - -show_fan16_offset(1); -show_fan16_offset(2); -show_fan16_offset(3); -show_fan16_offset(4); -show_fan16_offset(5); +static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0); +static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 0, 1); +static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 0); + +static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0); +static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 1, 1); +static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 1); + +static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0); +static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 2, 1); +static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div, + set_fan_div, 2); + +static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0); +static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 3, 1); + +static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0); +static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan, + 4, 1); + +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0); +static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq); +static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 0, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 0, 3); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 1); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 0); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 2); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 3); +static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 0, 4); + +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 1); +static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1); +static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL); +static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 1, 2); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 1, 3); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 1); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 0); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 2); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 3); +static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 1, 4); + +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, + show_pwm_enable, set_pwm_enable, 2); +static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2); +static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL); +static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR, + show_pwm_temp_map, set_pwm_temp_map, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR, + show_auto_pwm, set_auto_pwm, 2, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO, + show_auto_pwm, NULL, 2, 3); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 1); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 0); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 2); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 3); +static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR, + show_auto_temp, set_auto_temp, 2, 4); /* Alarms */ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, @@ -1403,6 +1452,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2); +/* special AVCC3 IT8603E in9 */ +static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0); static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf) @@ -1412,57 +1463,113 @@ static ssize_t show_name(struct device *dev, struct device_attribute } static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static struct attribute *it87_attributes[] = { +static struct attribute *it87_attributes_in[10][5] = { +{ &sensor_dev_attr_in0_input.dev_attr.attr, - &sensor_dev_attr_in1_input.dev_attr.attr, - &sensor_dev_attr_in2_input.dev_attr.attr, - &sensor_dev_attr_in3_input.dev_attr.attr, - &sensor_dev_attr_in4_input.dev_attr.attr, - &sensor_dev_attr_in5_input.dev_attr.attr, - &sensor_dev_attr_in6_input.dev_attr.attr, - &sensor_dev_attr_in7_input.dev_attr.attr, - &sensor_dev_attr_in8_input.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr, - &sensor_dev_attr_in1_min.dev_attr.attr, - &sensor_dev_attr_in2_min.dev_attr.attr, - &sensor_dev_attr_in3_min.dev_attr.attr, - &sensor_dev_attr_in4_min.dev_attr.attr, - &sensor_dev_attr_in5_min.dev_attr.attr, - &sensor_dev_attr_in6_min.dev_attr.attr, - &sensor_dev_attr_in7_min.dev_attr.attr, &sensor_dev_attr_in0_max.dev_attr.attr, - &sensor_dev_attr_in1_max.dev_attr.attr, - &sensor_dev_attr_in2_max.dev_attr.attr, - &sensor_dev_attr_in3_max.dev_attr.attr, - &sensor_dev_attr_in4_max.dev_attr.attr, - &sensor_dev_attr_in5_max.dev_attr.attr, - &sensor_dev_attr_in6_max.dev_attr.attr, - &sensor_dev_attr_in7_max.dev_attr.attr, &sensor_dev_attr_in0_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, &sensor_dev_attr_in1_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, &sensor_dev_attr_in2_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, &sensor_dev_attr_in3_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, &sensor_dev_attr_in4_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, &sensor_dev_attr_in5_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, &sensor_dev_attr_in6_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, &sensor_dev_attr_in7_alarm.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in8_input.dev_attr.attr, + NULL +}, { + &sensor_dev_attr_in9_input.dev_attr.attr, + NULL +} }; + +static const struct attribute_group it87_group_in[10] = { + { .attrs = it87_attributes_in[0] }, + { .attrs = it87_attributes_in[1] }, + { .attrs = it87_attributes_in[2] }, + { .attrs = it87_attributes_in[3] }, + { .attrs = it87_attributes_in[4] }, + { .attrs = it87_attributes_in[5] }, + { .attrs = it87_attributes_in[6] }, + { .attrs = it87_attributes_in[7] }, + { .attrs = it87_attributes_in[8] }, + { .attrs = it87_attributes_in[9] }, +}; +static struct attribute *it87_attributes_temp[3][6] = { +{ &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp2_input.dev_attr.attr, - &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp2_max.dev_attr.attr, - &sensor_dev_attr_temp3_max.dev_attr.attr, &sensor_dev_attr_temp1_min.dev_attr.attr, - &sensor_dev_attr_temp2_min.dev_attr.attr, - &sensor_dev_attr_temp3_min.dev_attr.attr, &sensor_dev_attr_temp1_type.dev_attr.attr, - &sensor_dev_attr_temp2_type.dev_attr.attr, - &sensor_dev_attr_temp3_type.dev_attr.attr, &sensor_dev_attr_temp1_alarm.dev_attr.attr, + NULL +} , { + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp2_min.dev_attr.attr, + &sensor_dev_attr_temp2_type.dev_attr.attr, &sensor_dev_attr_temp2_alarm.dev_attr.attr, + NULL +} , { + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp3_min.dev_attr.attr, + &sensor_dev_attr_temp3_type.dev_attr.attr, &sensor_dev_attr_temp3_alarm.dev_attr.attr, + NULL +} }; + +static const struct attribute_group it87_group_temp[3] = { + { .attrs = it87_attributes_temp[0] }, + { .attrs = it87_attributes_temp[1] }, + { .attrs = it87_attributes_temp[2] }, +}; +static struct attribute *it87_attributes_temp_offset[] = { + &sensor_dev_attr_temp1_offset.dev_attr.attr, + &sensor_dev_attr_temp2_offset.dev_attr.attr, + &sensor_dev_attr_temp3_offset.dev_attr.attr, +}; + +static struct attribute *it87_attributes[] = { &dev_attr_alarms.attr, &sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &dev_attr_name.attr, @@ -1473,7 +1580,7 @@ static const struct attribute_group it87_group = { .attrs = it87_attributes, }; -static struct attribute *it87_attributes_beep[] = { +static struct attribute *it87_attributes_in_beep[] = { &sensor_dev_attr_in0_beep.dev_attr.attr, &sensor_dev_attr_in1_beep.dev_attr.attr, &sensor_dev_attr_in2_beep.dev_attr.attr, @@ -1482,84 +1589,57 @@ static struct attribute *it87_attributes_beep[] = { &sensor_dev_attr_in5_beep.dev_attr.attr, &sensor_dev_attr_in6_beep.dev_attr.attr, &sensor_dev_attr_in7_beep.dev_attr.attr, + NULL, + NULL, +}; +static struct attribute *it87_attributes_temp_beep[] = { &sensor_dev_attr_temp1_beep.dev_attr.attr, &sensor_dev_attr_temp2_beep.dev_attr.attr, &sensor_dev_attr_temp3_beep.dev_attr.attr, - NULL -}; - -static const struct attribute_group it87_group_beep = { - .attrs = it87_attributes_beep, }; -static struct attribute *it87_attributes_fan16[5][3+1] = { { - &sensor_dev_attr_fan1_input16.dev_attr.attr, - &sensor_dev_attr_fan1_min16.dev_attr.attr, +static struct attribute *it87_attributes_fan[5][3+1] = { { + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan1_min.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan2_input16.dev_attr.attr, - &sensor_dev_attr_fan2_min16.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan3_input16.dev_attr.attr, - &sensor_dev_attr_fan3_min16.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan4_input16.dev_attr.attr, - &sensor_dev_attr_fan4_min16.dev_attr.attr, + &sensor_dev_attr_fan4_input.dev_attr.attr, + &sensor_dev_attr_fan4_min.dev_attr.attr, &sensor_dev_attr_fan4_alarm.dev_attr.attr, NULL }, { - &sensor_dev_attr_fan5_input16.dev_attr.attr, - &sensor_dev_attr_fan5_min16.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan5_min.dev_attr.attr, &sensor_dev_attr_fan5_alarm.dev_attr.attr, NULL } }; -static const struct attribute_group it87_group_fan16[5] = { - { .attrs = it87_attributes_fan16[0] }, - { .attrs = it87_attributes_fan16[1] }, - { .attrs = it87_attributes_fan16[2] }, - { .attrs = it87_attributes_fan16[3] }, - { .attrs = it87_attributes_fan16[4] }, +static const struct attribute_group it87_group_fan[5] = { + { .attrs = it87_attributes_fan[0] }, + { .attrs = it87_attributes_fan[1] }, + { .attrs = it87_attributes_fan[2] }, + { .attrs = it87_attributes_fan[3] }, + { .attrs = it87_attributes_fan[4] }, }; -static struct attribute *it87_attributes_fan[3][4+1] = { { - &sensor_dev_attr_fan1_input.dev_attr.attr, - &sensor_dev_attr_fan1_min.dev_attr.attr, +static const struct attribute *it87_attributes_fan_div[] = { &sensor_dev_attr_fan1_div.dev_attr.attr, - &sensor_dev_attr_fan1_alarm.dev_attr.attr, - NULL -}, { - &sensor_dev_attr_fan2_input.dev_attr.attr, - &sensor_dev_attr_fan2_min.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr, - &sensor_dev_attr_fan2_alarm.dev_attr.attr, - NULL -}, { - &sensor_dev_attr_fan3_input.dev_attr.attr, - &sensor_dev_attr_fan3_min.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr, - &sensor_dev_attr_fan3_alarm.dev_attr.attr, - NULL -} }; - -static const struct attribute_group it87_group_fan[3] = { - { .attrs = it87_attributes_fan[0] }, - { .attrs = it87_attributes_fan[1] }, - { .attrs = it87_attributes_fan[2] }, }; -static const struct attribute_group * -it87_get_fan_group(const struct it87_data *data) -{ - return has_16bit_fans(data) ? it87_group_fan16 : it87_group_fan; -} - static struct attribute *it87_attributes_pwm[3][4+1] = { { &sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr, @@ -1649,6 +1729,7 @@ static struct attribute *it87_attributes_label[] = { &sensor_dev_attr_in3_label.dev_attr.attr, &sensor_dev_attr_in7_label.dev_attr.attr, &sensor_dev_attr_in8_label.dev_attr.attr, + &sensor_dev_attr_in9_label.dev_attr.attr, NULL }; @@ -1709,6 +1790,10 @@ static int __init it87_find(unsigned short *address, case IT8783E_DEVID: sio_data->type = it8783; break; + case IT8603E_DEVID: + case IT8623E_DEVID: + sio_data->type = it8603; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1730,11 +1815,16 @@ static int __init it87_find(unsigned short *address, err = 0; sio_data->revision = superio_inb(DEVREV) & 0x0f; - pr_info("Found IT%04xF chip at 0x%x, revision %d\n", - chip_type, *address, sio_data->revision); + pr_info("Found IT%04x%c chip at 0x%x, revision %d\n", chip_type, + chip_type == 0x8771 || chip_type == 0x8772 || + chip_type == 0x8603 ? 'E' : 'F', *address, + sio_data->revision); /* in8 (Vbat) is always internal */ sio_data->internal = (1 << 2); + /* Only the IT8603E has in9 */ + if (sio_data->type != it8603) + sio_data->skip_in |= (1 << 9); /* Read GPIO config and VID value from LDN 7 (GPIO) */ if (sio_data->type == it87) { @@ -1744,9 +1834,8 @@ static int __init it87_find(unsigned short *address, /* The IT8705F has a different LD number for GPIO */ superio_select(5); sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; - } else if (sio_data->type == it8781 || sio_data->type == it8782 || - sio_data->type == it8783) { - int reg25, reg27, reg2A, reg2C, regEF; + } else if (sio_data->type == it8783) { + int reg25, reg27, reg2a, reg2c, regef; sio_data->skip_vid = 1; /* No VID */ @@ -1754,15 +1843,15 @@ static int __init it87_find(unsigned short *address, reg25 = superio_inb(IT87_SIO_GPIO1_REG); reg27 = superio_inb(IT87_SIO_GPIO3_REG); - reg2A = superio_inb(IT87_SIO_PINX1_REG); - reg2C = superio_inb(IT87_SIO_PINX2_REG); - regEF = superio_inb(IT87_SIO_SPI_REG); + reg2a = superio_inb(IT87_SIO_PINX1_REG); + reg2c = superio_inb(IT87_SIO_PINX2_REG); + regef = superio_inb(IT87_SIO_SPI_REG); /* Check if fan3 is there or not */ - if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2))) + if ((reg27 & (1 << 0)) || !(reg2c & (1 << 2))) sio_data->skip_fan |= (1 << 2); if ((reg25 & (1 << 4)) - || (!(reg2A & (1 << 1)) && (regEF & (1 << 0)))) + || (!(reg2a & (1 << 1)) && (regef & (1 << 0)))) sio_data->skip_pwm |= (1 << 2); /* Check if fan2 is there or not */ @@ -1772,44 +1861,92 @@ static int __init it87_find(unsigned short *address, sio_data->skip_pwm |= (1 << 1); /* VIN5 */ - if ((reg27 & (1 << 0)) || (reg2C & (1 << 2))) - ; /* No VIN5 */ + if ((reg27 & (1 << 0)) || (reg2c & (1 << 2))) + sio_data->skip_in |= (1 << 5); /* No VIN5 */ /* VIN6 */ - if ((reg27 & (1 << 1)) || (reg2C & (1 << 2))) - ; /* No VIN6 */ + if (reg27 & (1 << 1)) + sio_data->skip_in |= (1 << 6); /* No VIN6 */ - /* VIN7 */ - if ((reg27 & (1 << 2)) || (reg2C & (1 << 2))) { + /* + * VIN7 + * Does not depend on bit 2 of Reg2C, contrary to datasheet. + */ + if (reg27 & (1 << 2)) { /* - * If the external VIN7 pin is disabled, route it to the - * internal VCCH5V if that is not already done. + * The data sheet is a bit unclear regarding the + * internal voltage divider for VCCH5V. It says + * "This bit enables and switches VIN7 (pin 91) to the + * internal voltage divider for VCCH5V". + * This is different to other chips, where the internal + * voltage divider would connect VIN7 to an internal + * voltage source. Maybe that is the case here as well. + * + * Since we don't know for sure, re-route it if that is + * not the case, and ask the user to report if the + * resulting voltage is sane. */ - if (!(reg2C & (1 << 1))) { - reg2C |= (1 << 1); - superio_outb(IT87_SIO_PINX2_REG, reg2C); - pr_notice("Routing internal VCCH to in7\n"); + if (!(reg2c & (1 << 1))) { + reg2c |= (1 << 1); + superio_outb(IT87_SIO_PINX2_REG, reg2c); + pr_notice("Routing internal VCCH5V to in7.\n"); } + pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n"); + pr_notice("Please report if it displays a reasonable voltage.\n"); } - if (reg2C & (1 << 0)) + if (reg2c & (1 << 0)) sio_data->internal |= (1 << 0); - if (reg2C & (1 << 1)) + if (reg2c & (1 << 1)) sio_data->internal |= (1 << 1); sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8603) { + int reg27, reg29; + sio_data->skip_vid = 1; /* No VID */ + superio_select(GPIO); + + reg27 = superio_inb(IT87_SIO_GPIO3_REG); + + /* Check if fan3 is there or not */ + if (reg27 & (1 << 6)) + sio_data->skip_pwm |= (1 << 2); + if (reg27 & (1 << 7)) + sio_data->skip_fan |= (1 << 2); + + /* Check if fan2 is there or not */ + reg29 = superio_inb(IT87_SIO_GPIO5_REG); + if (reg29 & (1 << 1)) + sio_data->skip_pwm |= (1 << 1); + if (reg29 & (1 << 2)) + sio_data->skip_fan |= (1 << 1); + + sio_data->skip_in |= (1 << 5); /* No VIN5 */ + sio_data->skip_in |= (1 << 6); /* No VIN6 */ + + /* no fan4 */ + sio_data->skip_pwm |= (1 << 3); + sio_data->skip_fan |= (1 << 3); + + sio_data->internal |= (1 << 1); /* in7 is VSB */ + sio_data->internal |= (1 << 3); /* in9 is AVCC */ + + sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; } else { int reg; + bool uart6; superio_select(GPIO); reg = superio_inb(IT87_SIO_GPIO3_REG); - if (sio_data->type == it8721 || sio_data->type == it8728 - || sio_data->type == it8771 || sio_data->type == it8772) { + if (sio_data->type == it8721 || sio_data->type == it8728 || + sio_data->type == it8771 || sio_data->type == it8772 || + sio_data->type == it8781 || sio_data->type == it8782) { /* - * The IT8721F/IT8758E don't have VID pins at all, - * not sure about the IT8728F, IT8771E, IT8772E. + * IT8721F/IT8758E, IT8728F, IT8772F, IT8781F, and + * IT8782F don't have VID pins at all, not sure about + * the IT8771F. */ sio_data->skip_vid = 1; } else { @@ -1838,6 +1975,9 @@ static int __init it87_find(unsigned short *address, sio_data->vid_value = superio_inb(IT87_SIO_VID_REG); reg = superio_inb(IT87_SIO_PINX2_REG); + + uart6 = sio_data->type == it8782 && (reg & (1 << 2)); + /* * The IT8720F has no VIN7 pin, so VCCH should always be * routed internally to VIN7 with an internal divider. @@ -1847,8 +1987,12 @@ static int __init it87_find(unsigned short *address, * configured, even though the IT8720F datasheet claims * that the internal routing of VCCH to VIN7 is the default * setting. So we force the internal routing in this case. + * + * On IT8782F, VIN7 is multiplexed with one of the UART6 pins. + * If UART6 is enabled, re-route VIN7 to the internal divider + * if that is not already the case. */ - if (sio_data->type == it8720 && !(reg & (1 << 1))) { + if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) { reg |= (1 << 1); superio_outb(IT87_SIO_PINX2_REG, reg); pr_notice("Routing internal VCCH to in7\n"); @@ -1856,10 +2000,25 @@ static int __init it87_find(unsigned short *address, if (reg & (1 << 0)) sio_data->internal |= (1 << 0); if ((reg & (1 << 1)) || sio_data->type == it8721 || - sio_data->type == it8728 || sio_data->type == it8771 || - sio_data->type == it8772 ) + sio_data->type == it8728 || + sio_data->type == it8771 || + sio_data->type == it8772) sio_data->internal |= (1 << 1); + /* + * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7. + * While VIN7 can be routed to the internal voltage divider, + * VIN5 and VIN6 are not available if UART6 is enabled. + * + * Also, temp3 is not available if UART6 is enabled and TEMPIN3 + * is the temperature source. Since we can not read the + * temperature source here, skip_temp is preliminary. + */ + if (uart6) { + sio_data->skip_in |= (1 << 5) | (1 << 6); + sio_data->skip_temp |= (1 << 2); + } + sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f; } if (sio_data->beep_pin) @@ -1892,20 +2051,39 @@ exit: static void it87_remove_files(struct device *dev) { struct it87_data *data = platform_get_drvdata(pdev); - struct it87_sio_data *sio_data = dev->platform_data; - const struct attribute_group *fan_group = it87_get_fan_group(data); + struct it87_sio_data *sio_data = dev_get_platdata(dev); int i; sysfs_remove_group(&dev->kobj, &it87_group); - if (sio_data->beep_pin) - sysfs_remove_group(&dev->kobj, &it87_group_beep); + for (i = 0; i < 10; i++) { + if (sio_data->skip_in & (1 << i)) + continue; + sysfs_remove_group(&dev->kobj, &it87_group_in[i]); + if (it87_attributes_in_beep[i]) + sysfs_remove_file(&dev->kobj, + it87_attributes_in_beep[i]); + } + for (i = 0; i < 3; i++) { + if (!(data->has_temp & (1 << i))) + continue; + sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); + if (has_temp_offset(data)) + sysfs_remove_file(&dev->kobj, + it87_attributes_temp_offset[i]); + if (sio_data->beep_pin) + sysfs_remove_file(&dev->kobj, + it87_attributes_temp_beep[i]); + } for (i = 0; i < 5; i++) { if (!(data->has_fan & (1 << i))) continue; - sysfs_remove_group(&dev->kobj, &fan_group[i]); + sysfs_remove_group(&dev->kobj, &it87_group_fan[i]); if (sio_data->beep_pin) sysfs_remove_file(&dev->kobj, it87_attributes_fan_beep[i]); + if (i < 3 && !has_16bit_fans(data)) + sysfs_remove_file(&dev->kobj, + it87_attributes_fan_div[i]); } for (i = 0; i < 3; i++) { if (sio_data->skip_pwm & (1 << 0)) @@ -1920,57 +2098,61 @@ static void it87_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &it87_group_label); } -static int __devinit it87_probe(struct platform_device *pdev) +static int it87_probe(struct platform_device *pdev) { struct it87_data *data; struct resource *res; struct device *dev = &pdev->dev; - struct it87_sio_data *sio_data = dev->platform_data; - const struct attribute_group *fan_group; + struct it87_sio_data *sio_data = dev_get_platdata(dev); int err = 0, i; int enable_pwm_interface; int fan_beep_need_rw; - static const char * const names[] = { - "it87", - "it8712", - "it8716", - "it8718", - "it8720", - "it8721", - "it8728", - "it8771", - "it8772", - "it8781", - "it8782", - "it8783", - }; res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) { + if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, + DRVNAME)) { dev_err(dev, "Failed to request region 0x%lx-0x%lx\n", (unsigned long)res->start, (unsigned long)(res->start + IT87_EC_EXTENT - 1)); - err = -EBUSY; - goto ERROR0; + return -EBUSY; } - data = kzalloc(sizeof(struct it87_data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto ERROR1; - } + data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL); + if (!data) + return -ENOMEM; data->addr = res->start; data->type = sio_data->type; - data->revision = sio_data->revision; - data->name = names[sio_data->type]; + data->features = it87_devices[sio_data->type].features; + data->peci_mask = it87_devices[sio_data->type].peci_mask; + data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask; + data->name = it87_devices[sio_data->type].name; + /* + * IT8705F Datasheet 0.4.1, 3h == Version G. + * IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J. + * These are the first revisions with 16-bit tachometer support. + */ + switch (data->type) { + case it87: + if (sio_data->revision >= 0x03) { + data->features &= ~FEAT_OLD_AUTOPWM; + data->features |= FEAT_16BIT_FANS; + } + break; + case it8712: + if (sio_data->revision >= 0x08) { + data->features &= ~FEAT_OLD_AUTOPWM; + data->features |= FEAT_16BIT_FANS | FEAT_FIVE_FANS; + } + break; + default: + break; + } /* Now, we do the remaining detection. */ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) - || it87_read_value(data, IT87_REG_CHIPID) != 0x90) { - err = -ENODEV; - goto ERROR2; - } + || it87_read_value(data, IT87_REG_CHIPID) != 0x90) + return -ENODEV; platform_set_drvdata(pdev, data); @@ -1987,6 +2169,8 @@ static int __devinit it87_probe(struct platform_device *pdev) data->in_scaled |= (1 << 7); /* in7 is VSB */ if (sio_data->internal & (1 << 2)) data->in_scaled |= (1 << 8); /* in8 is Vbat */ + if (sio_data->internal & (1 << 3)) + data->in_scaled |= (1 << 9); /* in9 is AVCC */ } else if (sio_data->type == it8781 || sio_data->type == it8782 || sio_data->type == it8783) { if (sio_data->internal & (1 << 0)) @@ -1995,35 +2179,76 @@ static int __devinit it87_probe(struct platform_device *pdev) data->in_scaled |= (1 << 7); /* in7 is VCCH5V */ } + data->has_temp = 0x07; + if (sio_data->skip_temp & (1 << 2)) { + if (sio_data->type == it8782 + && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80)) + data->has_temp &= ~(1 << 2); + } + /* Initialize the IT87 chip */ it87_init_device(pdev); /* Register sysfs hooks */ err = sysfs_create_group(&dev->kobj, &it87_group); if (err) - goto ERROR2; + return err; + + for (i = 0; i < 10; i++) { + if (sio_data->skip_in & (1 << i)) + continue; + err = sysfs_create_group(&dev->kobj, &it87_group_in[i]); + if (err) + goto error; + if (sio_data->beep_pin && it87_attributes_in_beep[i]) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_in_beep[i]); + if (err) + goto error; + } + } - if (sio_data->beep_pin) { - err = sysfs_create_group(&dev->kobj, &it87_group_beep); + for (i = 0; i < 3; i++) { + if (!(data->has_temp & (1 << i))) + continue; + err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); if (err) - goto ERROR4; + goto error; + if (has_temp_offset(data)) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_temp_offset[i]); + if (err) + goto error; + } + if (sio_data->beep_pin) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_temp_beep[i]); + if (err) + goto error; + } } /* Do not create fan files for disabled fans */ - fan_group = it87_get_fan_group(data); fan_beep_need_rw = 1; for (i = 0; i < 5; i++) { if (!(data->has_fan & (1 << i))) continue; - err = sysfs_create_group(&dev->kobj, &fan_group[i]); + err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]); if (err) - goto ERROR4; + goto error; + + if (i < 3 && !has_16bit_fans(data)) { + err = sysfs_create_file(&dev->kobj, + it87_attributes_fan_div[i]); + if (err) + goto error; + } if (sio_data->beep_pin) { err = sysfs_create_file(&dev->kobj, it87_attributes_fan_beep[i]); if (err) - goto ERROR4; + goto error; if (!fan_beep_need_rw) continue; @@ -2048,14 +2273,14 @@ static int __devinit it87_probe(struct platform_device *pdev) err = sysfs_create_group(&dev->kobj, &it87_group_pwm[i]); if (err) - goto ERROR4; + goto error; if (!has_old_autopwm(data)) continue; err = sysfs_create_group(&dev->kobj, &it87_group_autopwm[i]); if (err) - goto ERROR4; + goto error; } } @@ -2065,49 +2290,39 @@ static int __devinit it87_probe(struct platform_device *pdev) data->vid = sio_data->vid_value; err = sysfs_create_group(&dev->kobj, &it87_group_vid); if (err) - goto ERROR4; + goto error; } /* Export labels for internal sensors */ - for (i = 0; i < 3; i++) { + for (i = 0; i < 4; i++) { if (!(sio_data->internal & (1 << i))) continue; err = sysfs_create_file(&dev->kobj, it87_attributes_label[i]); if (err) - goto ERROR4; + goto error; } data->hwmon_dev = hwmon_device_register(dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); - goto ERROR4; + goto error; } return 0; -ERROR4: +error: it87_remove_files(dev); -ERROR2: - platform_set_drvdata(pdev, NULL); - kfree(data); -ERROR1: - release_region(res->start, IT87_EC_EXTENT); -ERROR0: return err; } -static int __devexit it87_remove(struct platform_device *pdev) +static int it87_remove(struct platform_device *pdev) { struct it87_data *data = platform_get_drvdata(pdev); hwmon_device_unregister(data->hwmon_dev); it87_remove_files(&pdev->dev); - release_region(data->addr, IT87_EC_EXTENT); - platform_set_drvdata(pdev, NULL); - kfree(data); - return 0; } @@ -2134,7 +2349,7 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value) } /* Return 1 if and only if the PWM interface is safe to use */ -static int __devinit it87_check_pwm(struct device *dev) +static int it87_check_pwm(struct device *dev) { struct it87_data *data = dev_get_drvdata(dev); /* @@ -2164,8 +2379,8 @@ static int __devinit it87_check_pwm(struct device *dev) * PWM interface). */ if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { - dev_info(dev, "Reconfiguring PWM to " - "active high polarity\n"); + dev_info(dev, + "Reconfiguring PWM to active high polarity\n"); it87_write_value(data, IT87_REG_FAN_CTL, tmp | 0x87); for (i = 0; i < 3; i++) @@ -2175,25 +2390,25 @@ static int __devinit it87_check_pwm(struct device *dev) return 1; } - dev_info(dev, "PWM configuration is " - "too broken to be fixed\n"); + dev_info(dev, + "PWM configuration is too broken to be fixed\n"); } - dev_info(dev, "Detected broken BIOS " - "defaults, disabling PWM interface\n"); + dev_info(dev, + "Detected broken BIOS defaults, disabling PWM interface\n"); return 0; } else if (fix_pwm_polarity) { - dev_info(dev, "PWM configuration looks " - "sane, won't touch\n"); + dev_info(dev, + "PWM configuration looks sane, won't touch\n"); } return 1; } /* Called when we have found a new IT87. */ -static void __devinit it87_init_device(struct platform_device *pdev) +static void it87_init_device(struct platform_device *pdev) { - struct it87_sio_data *sio_data = pdev->dev.platform_data; + struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev); struct it87_data *data = platform_get_drvdata(pdev); int tmp, i; u8 mask; @@ -2260,8 +2475,8 @@ static void __devinit it87_init_device(struct platform_device *pdev) } data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; - /* Set tachometers to 16-bit mode if needed */ - if (has_16bit_fans(data)) { + /* Set tachometers to 16-bit mode if needed. */ + if (has_fan16_config(data)) { tmp = it87_read_value(data, IT87_REG_FAN_16BIT); if (~tmp & 0x07 & data->has_fan) { dev_dbg(&pdev->dev, @@ -2269,14 +2484,15 @@ static void __devinit it87_init_device(struct platform_device *pdev) it87_write_value(data, IT87_REG_FAN_16BIT, tmp | 0x07); } - /* IT8705F and IT8783E/F only support three fans. */ - if (data->type != it87 && data->type != it8781 - && data->type != it8782 && data->type != it8783) { - if (tmp & (1 << 4)) - data->has_fan |= (1 << 3); /* fan4 enabled */ - if (tmp & (1 << 5)) - data->has_fan |= (1 << 4); /* fan5 enabled */ - } + } + + /* Check for additional fans */ + if (has_five_fans(data)) { + tmp = it87_read_value(data, IT87_REG_FAN_16BIT); + if (tmp & (1 << 4)) + data->has_fan |= (1 << 3); /* fan4 enabled */ + if (tmp & (1 << 5)) + data->has_fan |= (1 << 4); /* fan5 enabled */ } /* Fan input pins may be used for alternative functions */ @@ -2284,7 +2500,7 @@ static void __devinit it87_init_device(struct platform_device *pdev) /* Start monitoring */ it87_write_value(data, IT87_REG_CONFIG, - (it87_read_value(data, IT87_REG_CONFIG) & 0x36) + (it87_read_value(data, IT87_REG_CONFIG) & 0x3e) | (update_vbat ? 0x41 : 0x01)); } @@ -2332,40 +2548,48 @@ static struct it87_data *it87_update_device(struct device *dev) it87_read_value(data, IT87_REG_CONFIG) | 0x40); } for (i = 0; i <= 7; i++) { - data->in[i] = + data->in[i][0] = it87_read_value(data, IT87_REG_VIN(i)); - data->in_min[i] = + data->in[i][1] = it87_read_value(data, IT87_REG_VIN_MIN(i)); - data->in_max[i] = + data->in[i][2] = it87_read_value(data, IT87_REG_VIN_MAX(i)); } /* in8 (battery) has no limit registers */ - data->in[8] = it87_read_value(data, IT87_REG_VIN(8)); + data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8)); + if (data->type == it8603) + data->in[9][0] = it87_read_value(data, 0x2f); for (i = 0; i < 5; i++) { /* Skip disabled fans */ if (!(data->has_fan & (1 << i))) continue; - data->fan_min[i] = + data->fan[i][1] = it87_read_value(data, IT87_REG_FAN_MIN[i]); - data->fan[i] = it87_read_value(data, + data->fan[i][0] = it87_read_value(data, IT87_REG_FAN[i]); /* Add high byte if in 16-bit mode */ if (has_16bit_fans(data)) { - data->fan[i] |= it87_read_value(data, + data->fan[i][0] |= it87_read_value(data, IT87_REG_FANX[i]) << 8; - data->fan_min[i] |= it87_read_value(data, + data->fan[i][1] |= it87_read_value(data, IT87_REG_FANX_MIN[i]) << 8; } } for (i = 0; i < 3; i++) { - data->temp[i] = + if (!(data->has_temp & (1 << i))) + continue; + data->temp[i][0] = it87_read_value(data, IT87_REG_TEMP(i)); - data->temp_high[i] = - it87_read_value(data, IT87_REG_TEMP_HIGH(i)); - data->temp_low[i] = + data->temp[i][1] = it87_read_value(data, IT87_REG_TEMP_LOW(i)); + data->temp[i][2] = + it87_read_value(data, IT87_REG_TEMP_HIGH(i)); + if (has_temp_offset(data)) + data->temp[i][3] = + it87_read_value(data, + IT87_REG_TEMP_OFFSET[i]); } /* Newer chips don't have clock dividers */ @@ -2389,6 +2613,7 @@ static struct it87_data *it87_update_device(struct device *dev) it87_update_pwm_ctrl(data, i); data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); + data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA); /* * The IT8705F does not have VID capability. * The IT8718F and later don't use IT87_REG_VID for the @@ -2490,8 +2715,7 @@ static void __exit sm_it87_exit(void) } -MODULE_AUTHOR("Chris Gauthron, " - "Jean Delvare "); +MODULE_AUTHOR("Chris Gauthron, Jean Delvare "); MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); module_param(update_vbat, bool, 0); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");