|
@@ -15,7 +15,9 @@
|
|
* IT8716F Super I/O chip w/LPC interface
|
|
* IT8716F Super I/O chip w/LPC interface
|
|
* IT8718F Super I/O chip w/LPC interface
|
|
* IT8718F Super I/O chip w/LPC interface
|
|
* IT8720F Super I/O chip w/LPC interface
|
|
* IT8720F Super I/O chip w/LPC interface
|
|
|
|
+ * IT8721F Super I/O chip w/LPC interface
|
|
* IT8726F Super I/O chip w/LPC interface
|
|
* IT8726F Super I/O chip w/LPC interface
|
|
|
|
+ * IT8758E Super I/O chip w/LPC interface
|
|
* Sis950 A clone of the IT8705F
|
|
* Sis950 A clone of the IT8705F
|
|
*
|
|
*
|
|
* Copyright (C) 2001 Chris Gauthron
|
|
* Copyright (C) 2001 Chris Gauthron
|
|
@@ -54,7 +56,7 @@
|
|
|
|
|
|
#define DRVNAME "it87"
|
|
#define DRVNAME "it87"
|
|
|
|
|
|
-enum chips { it87, it8712, it8716, it8718, it8720 };
|
|
|
|
|
|
+enum chips { it87, it8712, it8716, it8718, it8720, it8721 };
|
|
|
|
|
|
static unsigned short force_id;
|
|
static unsigned short force_id;
|
|
module_param(force_id, ushort, 0);
|
|
module_param(force_id, ushort, 0);
|
|
@@ -126,6 +128,7 @@ superio_exit(void)
|
|
#define IT8716F_DEVID 0x8716
|
|
#define IT8716F_DEVID 0x8716
|
|
#define IT8718F_DEVID 0x8718
|
|
#define IT8718F_DEVID 0x8718
|
|
#define IT8720F_DEVID 0x8720
|
|
#define IT8720F_DEVID 0x8720
|
|
|
|
+#define IT8721F_DEVID 0x8721
|
|
#define IT8726F_DEVID 0x8726
|
|
#define IT8726F_DEVID 0x8726
|
|
#define IT87_ACT_REG 0x30
|
|
#define IT87_ACT_REG 0x30
|
|
#define IT87_BASE_REG 0x60
|
|
#define IT87_BASE_REG 0x60
|
|
@@ -229,6 +232,7 @@ struct it87_data {
|
|
char valid; /* !=0 if following fields are valid */
|
|
char valid; /* !=0 if following fields are valid */
|
|
unsigned long last_updated; /* In jiffies */
|
|
unsigned long last_updated; /* In jiffies */
|
|
|
|
|
|
|
|
+ u16 in_scaled; /* Internal voltage sensors are scaled */
|
|
u8 in[9]; /* Register value */
|
|
u8 in[9]; /* Register value */
|
|
u8 in_max[8]; /* Register value */
|
|
u8 in_max[8]; /* Register value */
|
|
u8 in_min[8]; /* Register value */
|
|
u8 in_min[8]; /* Register value */
|
|
@@ -260,8 +264,32 @@ struct it87_data {
|
|
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
|
|
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
|
|
};
|
|
};
|
|
|
|
|
|
-#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8) / 16), 0, 255))
|
|
|
|
-#define IN_FROM_REG(val) ((val) * 16)
|
|
|
|
|
|
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
|
|
|
|
+{
|
|
|
|
+ long lsb;
|
|
|
|
+
|
|
|
|
+ if (data->type == it8721) {
|
|
|
|
+ if (data->in_scaled & (1 << nr))
|
|
|
|
+ lsb = 24;
|
|
|
|
+ else
|
|
|
|
+ lsb = 12;
|
|
|
|
+ } else
|
|
|
|
+ lsb = 16;
|
|
|
|
+
|
|
|
|
+ val = DIV_ROUND_CLOSEST(val, lsb);
|
|
|
|
+ return SENSORS_LIMIT(val, 0, 255);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int in_from_reg(const struct it87_data *data, int nr, int val)
|
|
|
|
+{
|
|
|
|
+ if (data->type == it8721) {
|
|
|
|
+ if (data->in_scaled & (1 << nr))
|
|
|
|
+ return val * 24;
|
|
|
|
+ else
|
|
|
|
+ return val * 12;
|
|
|
|
+ } else
|
|
|
|
+ return val * 16;
|
|
|
|
+}
|
|
|
|
|
|
static inline u8 FAN_TO_REG(long rpm, int div)
|
|
static inline u8 FAN_TO_REG(long rpm, int div)
|
|
{
|
|
{
|
|
@@ -289,8 +317,22 @@ static inline u16 FAN16_TO_REG(long rpm)
|
|
((val) + 500) / 1000), -128, 127))
|
|
((val) + 500) / 1000), -128, 127))
|
|
#define TEMP_FROM_REG(val) ((val) * 1000)
|
|
#define TEMP_FROM_REG(val) ((val) * 1000)
|
|
|
|
|
|
-#define PWM_TO_REG(val) ((val) >> 1)
|
|
|
|
-#define PWM_FROM_REG(val) (((val) & 0x7f) << 1)
|
|
|
|
|
|
+static u8 pwm_to_reg(const struct it87_data *data, long val)
|
|
|
|
+{
|
|
|
|
+ if (data->type == it8721)
|
|
|
|
+ return val;
|
|
|
|
+ else
|
|
|
|
+ return val >> 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int pwm_from_reg(const struct it87_data *data, u8 reg)
|
|
|
|
+{
|
|
|
|
+ if (data->type == it8721)
|
|
|
|
+ return reg;
|
|
|
|
+ else
|
|
|
|
+ return (reg & 0x7f) << 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
static int DIV_TO_REG(int val)
|
|
static int DIV_TO_REG(int val)
|
|
{
|
|
{
|
|
@@ -321,7 +363,8 @@ static inline int has_16bit_fans(const struct it87_data *data)
|
|
|| (data->type == it8712 && data->revision >= 0x08)
|
|
|| (data->type == it8712 && data->revision >= 0x08)
|
|
|| data->type == it8716
|
|
|| data->type == it8716
|
|
|| data->type == it8718
|
|
|| data->type == it8718
|
|
- || data->type == it8720;
|
|
|
|
|
|
+ || data->type == it8720
|
|
|
|
+ || data->type == it8721;
|
|
}
|
|
}
|
|
|
|
|
|
static inline int has_old_autopwm(const struct it87_data *data)
|
|
static inline int has_old_autopwm(const struct it87_data *data)
|
|
@@ -359,7 +402,7 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
|
int nr = sensor_attr->index;
|
|
int nr = sensor_attr->index;
|
|
|
|
|
|
struct it87_data *data = it87_update_device(dev);
|
|
struct it87_data *data = it87_update_device(dev);
|
|
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
|
|
|
|
|
|
+ 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,
|
|
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
|
|
@@ -369,7 +412,7 @@ static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
|
|
int nr = sensor_attr->index;
|
|
int nr = sensor_attr->index;
|
|
|
|
|
|
struct it87_data *data = it87_update_device(dev);
|
|
struct it87_data *data = it87_update_device(dev);
|
|
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
|
|
|
|
|
|
+ return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr]));
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
|
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
|
@@ -379,7 +422,7 @@ static ssize_t show_in_max(struct device *dev, struct device_attribute *attr,
|
|
int nr = sensor_attr->index;
|
|
int nr = sensor_attr->index;
|
|
|
|
|
|
struct it87_data *data = it87_update_device(dev);
|
|
struct it87_data *data = it87_update_device(dev);
|
|
- return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
|
|
|
|
|
|
+ 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,
|
|
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|
@@ -395,7 +438,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
mutex_lock(&data->update_lock);
|
|
- data->in_min[nr] = IN_TO_REG(val);
|
|
|
|
|
|
+ data->in_min[nr] = in_to_reg(data, nr, val);
|
|
it87_write_value(data, IT87_REG_VIN_MIN(nr),
|
|
it87_write_value(data, IT87_REG_VIN_MIN(nr),
|
|
data->in_min[nr]);
|
|
data->in_min[nr]);
|
|
mutex_unlock(&data->update_lock);
|
|
mutex_unlock(&data->update_lock);
|
|
@@ -414,7 +457,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
mutex_lock(&data->update_lock);
|
|
- data->in_max[nr] = IN_TO_REG(val);
|
|
|
|
|
|
+ data->in_max[nr] = in_to_reg(data, nr, val);
|
|
it87_write_value(data, IT87_REG_VIN_MAX(nr),
|
|
it87_write_value(data, IT87_REG_VIN_MAX(nr),
|
|
data->in_max[nr]);
|
|
data->in_max[nr]);
|
|
mutex_unlock(&data->update_lock);
|
|
mutex_unlock(&data->update_lock);
|
|
@@ -644,7 +687,8 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
|
|
int nr = sensor_attr->index;
|
|
int nr = sensor_attr->index;
|
|
|
|
|
|
struct it87_data *data = it87_update_device(dev);
|
|
struct it87_data *data = it87_update_device(dev);
|
|
- return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm_duty[nr]));
|
|
|
|
|
|
+ return sprintf(buf, "%d\n",
|
|
|
|
+ pwm_from_reg(data, data->pwm_duty[nr]));
|
|
}
|
|
}
|
|
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
|
|
static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
|
|
char *buf)
|
|
char *buf)
|
|
@@ -814,7 +858,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
mutex_lock(&data->update_lock);
|
|
- data->pwm_duty[nr] = PWM_TO_REG(val);
|
|
|
|
|
|
+ data->pwm_duty[nr] = pwm_to_reg(data, val);
|
|
/* If we are in manual mode, write the duty cycle immediately;
|
|
/* If we are in manual mode, write the duty cycle immediately;
|
|
* otherwise, just store it for later use. */
|
|
* otherwise, just store it for later use. */
|
|
if (!(data->pwm_ctrl[nr] & 0x80)) {
|
|
if (!(data->pwm_ctrl[nr] & 0x80)) {
|
|
@@ -918,7 +962,8 @@ static ssize_t show_auto_pwm(struct device *dev,
|
|
int nr = sensor_attr->nr;
|
|
int nr = sensor_attr->nr;
|
|
int point = sensor_attr->index;
|
|
int point = sensor_attr->index;
|
|
|
|
|
|
- return sprintf(buf, "%d\n", PWM_FROM_REG(data->auto_pwm[nr][point]));
|
|
|
|
|
|
+ return sprintf(buf, "%d\n",
|
|
|
|
+ pwm_from_reg(data, data->auto_pwm[nr][point]));
|
|
}
|
|
}
|
|
|
|
|
|
static ssize_t set_auto_pwm(struct device *dev,
|
|
static ssize_t set_auto_pwm(struct device *dev,
|
|
@@ -935,7 +980,7 @@ static ssize_t set_auto_pwm(struct device *dev,
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
mutex_lock(&data->update_lock);
|
|
mutex_lock(&data->update_lock);
|
|
- data->auto_pwm[nr][point] = PWM_TO_REG(val);
|
|
|
|
|
|
+ data->auto_pwm[nr][point] = pwm_to_reg(data, val);
|
|
it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
|
|
it87_write_value(data, IT87_REG_AUTO_PWM(nr, point),
|
|
data->auto_pwm[nr][point]);
|
|
data->auto_pwm[nr][point]);
|
|
mutex_unlock(&data->update_lock);
|
|
mutex_unlock(&data->update_lock);
|
|
@@ -1205,9 +1250,16 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
|
|
"5VSB",
|
|
"5VSB",
|
|
"Vbat",
|
|
"Vbat",
|
|
};
|
|
};
|
|
|
|
+ static const char *labels_it8721[] = {
|
|
|
|
+ "+3.3V",
|
|
|
|
+ "3VSB",
|
|
|
|
+ "Vbat",
|
|
|
|
+ };
|
|
|
|
+ struct it87_data *data = dev_get_drvdata(dev);
|
|
int nr = to_sensor_dev_attr(attr)->index;
|
|
int nr = to_sensor_dev_attr(attr)->index;
|
|
|
|
|
|
- return sprintf(buf, "%s\n", labels[nr]);
|
|
|
|
|
|
+ return sprintf(buf, "%s\n", data->type == it8721 ? labels_it8721[nr]
|
|
|
|
+ : labels[nr]);
|
|
}
|
|
}
|
|
static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
|
|
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(in7_label, S_IRUGO, show_label, NULL, 1);
|
|
@@ -1492,6 +1544,9 @@ static int __init it87_find(unsigned short *address,
|
|
case IT8720F_DEVID:
|
|
case IT8720F_DEVID:
|
|
sio_data->type = it8720;
|
|
sio_data->type = it8720;
|
|
break;
|
|
break;
|
|
|
|
+ case IT8721F_DEVID:
|
|
|
|
+ sio_data->type = it8721;
|
|
|
|
+ break;
|
|
case 0xffff: /* No device at all */
|
|
case 0xffff: /* No device at all */
|
|
goto exit;
|
|
goto exit;
|
|
default:
|
|
default:
|
|
@@ -1532,11 +1587,17 @@ static int __init it87_find(unsigned short *address,
|
|
int reg;
|
|
int reg;
|
|
|
|
|
|
superio_select(GPIO);
|
|
superio_select(GPIO);
|
|
- /* We need at least 4 VID pins */
|
|
|
|
|
|
+
|
|
reg = superio_inb(IT87_SIO_GPIO3_REG);
|
|
reg = superio_inb(IT87_SIO_GPIO3_REG);
|
|
- if (reg & 0x0f) {
|
|
|
|
- pr_info("it87: VID is disabled (pins used for GPIO)\n");
|
|
|
|
|
|
+ if (sio_data->type == it8721) {
|
|
|
|
+ /* The IT8721F/IT8758E doesn't have VID pins at all */
|
|
sio_data->skip_vid = 1;
|
|
sio_data->skip_vid = 1;
|
|
|
|
+ } else {
|
|
|
|
+ /* We need at least 4 VID pins */
|
|
|
|
+ if (reg & 0x0f) {
|
|
|
|
+ pr_info("it87: VID is disabled (pins used for GPIO)\n");
|
|
|
|
+ sio_data->skip_vid = 1;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* Check if fan3 is there or not */
|
|
/* Check if fan3 is there or not */
|
|
@@ -1574,7 +1635,7 @@ static int __init it87_find(unsigned short *address,
|
|
}
|
|
}
|
|
if (reg & (1 << 0))
|
|
if (reg & (1 << 0))
|
|
sio_data->internal |= (1 << 0);
|
|
sio_data->internal |= (1 << 0);
|
|
- if (reg & (1 << 1))
|
|
|
|
|
|
+ if ((reg & (1 << 1)) || sio_data->type == it8721)
|
|
sio_data->internal |= (1 << 1);
|
|
sio_data->internal |= (1 << 1);
|
|
|
|
|
|
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
|
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
|
|
@@ -1652,6 +1713,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|
"it8716",
|
|
"it8716",
|
|
"it8718",
|
|
"it8718",
|
|
"it8720",
|
|
"it8720",
|
|
|
|
+ "it8721",
|
|
};
|
|
};
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
|
@@ -1688,6 +1750,16 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|
/* Check PWM configuration */
|
|
/* Check PWM configuration */
|
|
enable_pwm_interface = it87_check_pwm(dev);
|
|
enable_pwm_interface = it87_check_pwm(dev);
|
|
|
|
|
|
|
|
+ /* Starting with IT8721F, we handle scaling of internal voltages */
|
|
|
|
+ if (data->type == it8721) {
|
|
|
|
+ if (sio_data->internal & (1 << 0))
|
|
|
|
+ data->in_scaled |= (1 << 3); /* in3 is AVCC */
|
|
|
|
+ if (sio_data->internal & (1 << 1))
|
|
|
|
+ data->in_scaled |= (1 << 7); /* in7 is VSB */
|
|
|
|
+ if (sio_data->internal & (1 << 2))
|
|
|
|
+ data->in_scaled |= (1 << 8); /* in8 is Vbat */
|
|
|
|
+ }
|
|
|
|
+
|
|
/* Initialize the IT87 chip */
|
|
/* Initialize the IT87 chip */
|
|
it87_init_device(pdev);
|
|
it87_init_device(pdev);
|
|
|
|
|
|
@@ -2053,7 +2125,7 @@ static struct it87_data *it87_update_device(struct device *dev)
|
|
|
|
|
|
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
|
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
|
/* The 8705 does not have VID capability.
|
|
/* The 8705 does not have VID capability.
|
|
- The 8718 and the 8720 don't use IT87_REG_VID for the
|
|
|
|
|
|
+ The 8718 and later don't use IT87_REG_VID for the
|
|
same purpose. */
|
|
same purpose. */
|
|
if (data->type == it8712 || data->type == it8716) {
|
|
if (data->type == it8712 || data->type == it8716) {
|
|
data->vid = it87_read_value(data, IT87_REG_VID);
|
|
data->vid = it87_read_value(data, IT87_REG_VID);
|
|
@@ -2153,7 +2225,7 @@ static void __exit sm_it87_exit(void)
|
|
|
|
|
|
MODULE_AUTHOR("Chris Gauthron, "
|
|
MODULE_AUTHOR("Chris Gauthron, "
|
|
"Jean Delvare <khali@linux-fr.org>");
|
|
"Jean Delvare <khali@linux-fr.org>");
|
|
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F, SiS950 driver");
|
|
|
|
|
|
+MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
|
|
module_param(update_vbat, bool, 0);
|
|
module_param(update_vbat, bool, 0);
|
|
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
|
|
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
|
|
module_param(fix_pwm_polarity, bool, 0);
|
|
module_param(fix_pwm_polarity, bool, 0);
|