* IT8726F Super I/O chip w/LPC interface
* IT8728F Super I/O chip w/LPC interface
* IT8758E Super I/O chip w/LPC interface
+ * IT8771E Super I/O chip w/LPC interface
+ * IT8772E Super I/O chip w/LPC interface
* IT8782F Super I/O chip w/LPC interface
* IT8783E/F Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
#define DRVNAME "it87"
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
- it8783 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
+ it8772, it8782, it8783 };
static unsigned short force_id;
module_param(force_id, ushort, 0);
#define IT8721F_DEVID 0x8721
#define IT8726F_DEVID 0x8726
#define IT8728F_DEVID 0x8728
+#define IT8771E_DEVID 0x8771
+#define IT8772E_DEVID 0x8772
#define IT8782F_DEVID 0x8782
#define IT8783E_DEVID 0x8783
#define IT87_ACT_REG 0x30
struct it87_devices {
const char *name;
u16 features;
- u16 peci_mask;
+ u8 peci_mask;
+ u8 old_peci_mask;
};
#define FEAT_12MV_ADC (1 << 0)
#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)
static const struct it87_devices it87_devices[] = {
[it87] = {
},
[it8718] = {
.name = "it8718",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
+ .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ | FEAT_TEMP_OLD_PECI,
+ .old_peci_mask = 0x4,
},
[it8720] = {
.name = "it8720",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
+ .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ | FEAT_TEMP_OLD_PECI,
+ .old_peci_mask = 0x4,
},
[it8721] = {
.name = "it8721",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI,
.peci_mask = 0x05,
+ .old_peci_mask = 0x02, /* Actually reports PCH */
},
[it8728] = {
.name = "it8728",
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
.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) */
+ .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) */
+ .peci_mask = 0x07,
+ },
[it8782] = {
.name = "it8782",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
+ .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ | FEAT_TEMP_OLD_PECI,
+ .old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
+ .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ | FEAT_TEMP_OLD_PECI,
+ .old_peci_mask = 0x4,
},
};
#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)))
struct it87_sio_data {
enum chips type;
struct device *hwmon_dev;
enum chips type;
u16 features;
- u16 peci_mask;
+ u8 peci_mask;
+ u8 old_peci_mask;
unsigned short addr;
const char *name;
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 */
+ 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;
static u8 in_to_reg(const struct it87_data *data, int nr, long val)
{
val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
- return SENSORS_LIMIT(val, 0, 255);
+ return clamp_val(val, 0, 255);
}
static int in_from_reg(const struct it87_data *data, int nr, int val)
{
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 : \
#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)
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))
+ 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 */
struct it87_data *data = dev_get_drvdata(dev);
long val;
- u8 reg;
+ u8 reg, extra;
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
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");
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;
case IT8728F_DEVID:
sio_data->type = it8728;
break;
+ case IT8771E_DEVID:
+ sio_data->type = it8771;
+ break;
+ case IT8772E_DEVID:
+ sio_data->type = it8772;
+ break;
case IT8782F_DEVID:
sio_data->type = it8782;
break;
reg = superio_inb(IT87_SIO_GPIO3_REG);
if (sio_data->type == it8721 || sio_data->type == it8728 ||
+ sio_data->type == it8771 || sio_data->type == it8772 ||
sio_data->type == it8782) {
/*
* IT8721F/IT8758E, and IT8782F don't have VID pins
- * at all, not sure about the IT8728F.
+ * at all, not sure about the IT8728F and compatibles.
*/
sio_data->skip_vid = 1;
} else {
if (reg & (1 << 0))
sio_data->internal |= (1 << 0);
if ((reg & (1 << 1)) || sio_data->type == it8721 ||
- sio_data->type == it8728)
+ sio_data->type == it8728 ||
+ sio_data->type == it8771 ||
+ sio_data->type == it8772)
sio_data->internal |= (1 << 1);
/*
data->type = 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.
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