Commit c145d5c6 authored by Rudolf Marek's avatar Rudolf Marek Committed by Jean Delvare

hwmon: (it87) Add support for the ITE IT8603E

Add support for IT8603E.

This closes bug #57861:
https://bugzilla.kernel.org/show_bug.cgi?id=57861

[JD: Fixes and clean-ups.]
Signed-off-by: default avatarRudolf Marek <r.marek@assembler.cz>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
parent d8ec26d7
...@@ -2,6 +2,10 @@ Kernel driver it87 ...@@ -2,6 +2,10 @@ Kernel driver it87
================== ==================
Supported chips: Supported chips:
* IT8603E
Prefix: 'it8603'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
* IT8705F * IT8705F
Prefix: 'it87' Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports) Addresses scanned: from Super I/O config space (8 I/O ports)
...@@ -90,7 +94,7 @@ motherboard models. ...@@ -90,7 +94,7 @@ motherboard models.
Description Description
----------- -----------
This driver implements support for the IT8705F, IT8712F, IT8716F, This driver implements support for the IT8603E, IT8705F, IT8712F, IT8716F,
IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E,
IT8782F, IT8783E/F, and SiS950 chips. IT8782F, IT8783E/F, and SiS950 chips.
...@@ -129,6 +133,10 @@ to userspace applications. ...@@ -129,6 +133,10 @@ to userspace applications.
The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F, The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F,
until a datasheet becomes available (hopefully.) until a datasheet becomes available (hopefully.)
The IT8603E is a custom design, hardware monitoring part is similar to
IT8728F. It only supports 16-bit fan mode, the full speed mode of the
fan is not supported (value 0 of pwmX_enable).
Temperatures are measured in degrees Celsius. An alarm is triggered once Temperatures are measured in degrees Celsius. An alarm is triggered once
when the Overtemperature Shutdown limit is crossed. when the Overtemperature Shutdown limit is crossed.
...@@ -145,13 +153,16 @@ alarm is triggered if the voltage has crossed a programmable minimum or ...@@ -145,13 +153,16 @@ alarm is triggered if the voltage has crossed a programmable minimum or
maximum limit. Note that minimum in this case always means 'closest to maximum limit. Note that minimum in this case always means 'closest to
zero'; this is important for negative voltage measurements. All voltage zero'; this is important for negative voltage measurements. All voltage
inputs can measure voltages between 0 and 4.08 volts, with a resolution of inputs can measure voltages between 0 and 4.08 volts, with a resolution of
0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery 0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The
voltage in8 does not have limit registers. battery voltage in8 does not have limit registers.
On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are On the IT8603E, IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs
internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F), are internal and scaled inside the chip:
in8 and optionally in3). The driver handles this transparently so user-space * in3 (optional)
doesn't have to care. * in7 (optional for IT8782F and IT8783E/F)
* in8 (always)
* in9 (relevant for IT8603E only)
The driver handles this transparently so user-space doesn't have to care.
The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value: The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
the voltage level your processor should work with. This is hardcoded by the voltage level your processor should work with. This is hardcoded by
......
...@@ -573,8 +573,8 @@ config SENSORS_IT87 ...@@ -573,8 +573,8 @@ config SENSORS_IT87
help help
If you say yes here you get support for ITE IT8705F, IT8712F, If you say yes here you get support for ITE IT8705F, IT8712F,
IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the IT8771E, IT8772E, IT8782F, IT8783E/F and IT8603E sensor chips,
SiS950 clone. and the SiS950 clone.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called it87. will be called it87.
......
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
* This driver supports only the Environment Controller in the IT8705F and * This driver supports only the Environment Controller in the IT8705F and
* similar parts. The other devices are supported by different drivers. * 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
* IT8705F Super I/O chip w/LPC interface
* IT8712F Super I/O chip w/LPC interface * IT8712F Super I/O chip w/LPC interface
* 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
...@@ -64,7 +65,7 @@ ...@@ -64,7 +65,7 @@
#define DRVNAME "it87" #define DRVNAME "it87"
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
it8772, it8782, it8783 }; it8772, it8782, it8783, it8603 };
static unsigned short force_id; static unsigned short force_id;
module_param(force_id, ushort, 0); module_param(force_id, ushort, 0);
...@@ -146,6 +147,7 @@ static inline void superio_exit(void) ...@@ -146,6 +147,7 @@ static inline void superio_exit(void)
#define IT8772E_DEVID 0x8772 #define IT8772E_DEVID 0x8772
#define IT8782F_DEVID 0x8782 #define IT8782F_DEVID 0x8782
#define IT8783E_DEVID 0x8783 #define IT8783E_DEVID 0x8783
#define IT8306E_DEVID 0x8603
#define IT87_ACT_REG 0x30 #define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60 #define IT87_BASE_REG 0x60
...@@ -315,6 +317,12 @@ static const struct it87_devices it87_devices[] = { ...@@ -315,6 +317,12 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OLD_PECI, | FEAT_TEMP_OLD_PECI,
.old_peci_mask = 0x4, .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_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
...@@ -361,7 +369,7 @@ struct it87_data { ...@@ -361,7 +369,7 @@ struct it87_data {
unsigned long last_updated; /* In jiffies */ unsigned long last_updated; /* In jiffies */
u16 in_scaled; /* Internal voltage sensors are scaled */ u16 in_scaled; /* Internal voltage sensors are scaled */
u8 in[9][3]; /* [nr][0]=in, [1]=min, [2]=max */ u8 in[10][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 has_fan; /* Bitfield, fans enabled */ u8 has_fan; /* Bitfield, fans enabled */
u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */ u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */
u8 has_temp; /* Bitfield, temp sensors enabled */ u8 has_temp; /* Bitfield, temp sensors enabled */
...@@ -578,6 +586,7 @@ static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in, ...@@ -578,6 +586,7 @@ static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
7, 2); 7, 2);
static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0); 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 */ /* 3 temperatures */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr, static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
...@@ -734,7 +743,7 @@ static int pwm_mode(const struct it87_data *data, int nr) ...@@ -734,7 +743,7 @@ static int pwm_mode(const struct it87_data *data, int nr)
{ {
int ctrl = data->fan_main_ctrl & (1 << nr); int ctrl = data->fan_main_ctrl & (1 << nr);
if (ctrl == 0) /* Full speed */ if (ctrl == 0 && data->type != it8603) /* Full speed */
return 0; return 0;
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */ if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
return 2; return 2;
...@@ -929,6 +938,10 @@ static ssize_t set_pwm_enable(struct device *dev, ...@@ -929,6 +938,10 @@ static ssize_t set_pwm_enable(struct device *dev,
return -EINVAL; return -EINVAL;
} }
/* IT8603E does not have on/off mode */
if (val == 0 && data->type == it8603)
return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
if (val == 0) { if (val == 0) {
...@@ -948,11 +961,14 @@ static ssize_t set_pwm_enable(struct device *dev, ...@@ -948,11 +961,14 @@ static ssize_t set_pwm_enable(struct device *dev,
else /* Automatic mode */ else /* Automatic mode */
data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]); it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
if (data->type != it8603) {
/* set SmartGuardian mode */ /* set SmartGuardian mode */
data->fan_main_ctrl |= (1 << nr); data->fan_main_ctrl |= (1 << nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
data->fan_main_ctrl); data->fan_main_ctrl);
} }
}
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
...@@ -1415,6 +1431,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, ...@@ -1415,6 +1431,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(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);
static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2); static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
/* special AVCC3 IT8306E in9 */
static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0);
static ssize_t show_name(struct device *dev, struct device_attribute static ssize_t show_name(struct device *dev, struct device_attribute
*devattr, char *buf) *devattr, char *buf)
...@@ -1424,7 +1442,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute ...@@ -1424,7 +1442,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute
} }
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *it87_attributes_in[9][5] = { static struct attribute *it87_attributes_in[10][5] = {
{ {
&sensor_dev_attr_in0_input.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr, &sensor_dev_attr_in0_min.dev_attr.attr,
...@@ -1476,9 +1494,12 @@ static struct attribute *it87_attributes_in[9][5] = { ...@@ -1476,9 +1494,12 @@ static struct attribute *it87_attributes_in[9][5] = {
}, { }, {
&sensor_dev_attr_in8_input.dev_attr.attr, &sensor_dev_attr_in8_input.dev_attr.attr,
NULL NULL
}, {
&sensor_dev_attr_in9_input.dev_attr.attr,
NULL
} }; } };
static const struct attribute_group it87_group_in[9] = { static const struct attribute_group it87_group_in[10] = {
{ .attrs = it87_attributes_in[0] }, { .attrs = it87_attributes_in[0] },
{ .attrs = it87_attributes_in[1] }, { .attrs = it87_attributes_in[1] },
{ .attrs = it87_attributes_in[2] }, { .attrs = it87_attributes_in[2] },
...@@ -1488,6 +1509,7 @@ static const struct attribute_group it87_group_in[9] = { ...@@ -1488,6 +1509,7 @@ static const struct attribute_group it87_group_in[9] = {
{ .attrs = it87_attributes_in[6] }, { .attrs = it87_attributes_in[6] },
{ .attrs = it87_attributes_in[7] }, { .attrs = it87_attributes_in[7] },
{ .attrs = it87_attributes_in[8] }, { .attrs = it87_attributes_in[8] },
{ .attrs = it87_attributes_in[9] },
}; };
static struct attribute *it87_attributes_temp[3][6] = { static struct attribute *it87_attributes_temp[3][6] = {
...@@ -1546,7 +1568,8 @@ static struct attribute *it87_attributes_in_beep[] = { ...@@ -1546,7 +1568,8 @@ static struct attribute *it87_attributes_in_beep[] = {
&sensor_dev_attr_in5_beep.dev_attr.attr, &sensor_dev_attr_in5_beep.dev_attr.attr,
&sensor_dev_attr_in6_beep.dev_attr.attr, &sensor_dev_attr_in6_beep.dev_attr.attr,
&sensor_dev_attr_in7_beep.dev_attr.attr, &sensor_dev_attr_in7_beep.dev_attr.attr,
NULL NULL,
NULL,
}; };
static struct attribute *it87_attributes_temp_beep[] = { static struct attribute *it87_attributes_temp_beep[] = {
...@@ -1685,6 +1708,7 @@ static struct attribute *it87_attributes_label[] = { ...@@ -1685,6 +1708,7 @@ static struct attribute *it87_attributes_label[] = {
&sensor_dev_attr_in3_label.dev_attr.attr, &sensor_dev_attr_in3_label.dev_attr.attr,
&sensor_dev_attr_in7_label.dev_attr.attr, &sensor_dev_attr_in7_label.dev_attr.attr,
&sensor_dev_attr_in8_label.dev_attr.attr, &sensor_dev_attr_in8_label.dev_attr.attr,
&sensor_dev_attr_in9_label.dev_attr.attr,
NULL NULL
}; };
...@@ -1742,6 +1766,9 @@ static int __init it87_find(unsigned short *address, ...@@ -1742,6 +1766,9 @@ static int __init it87_find(unsigned short *address,
case IT8783E_DEVID: case IT8783E_DEVID:
sio_data->type = it8783; sio_data->type = it8783;
break; break;
case IT8306E_DEVID:
sio_data->type = it8603;
break;
case 0xffff: /* No device at all */ case 0xffff: /* No device at all */
goto exit; goto exit;
default: default:
...@@ -1763,11 +1790,15 @@ static int __init it87_find(unsigned short *address, ...@@ -1763,11 +1790,15 @@ static int __init it87_find(unsigned short *address,
err = 0; err = 0;
sio_data->revision = superio_inb(DEVREV) & 0x0f; sio_data->revision = superio_inb(DEVREV) & 0x0f;
pr_info("Found IT%04xF chip at 0x%x, revision %d\n", pr_info("Found IT%04x%c chip at 0x%x, revision %d\n", chip_type,
chip_type, *address, sio_data->revision); chip_type == 0x8603 ? 'E' : 'F', *address,
sio_data->revision);
/* in8 (Vbat) is always internal */ /* in8 (Vbat) is always internal */
sio_data->internal = (1 << 2); 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) */ /* Read GPIO config and VID value from LDN 7 (GPIO) */
if (sio_data->type == it87) { if (sio_data->type == it87) {
...@@ -1844,7 +1875,38 @@ static int __init it87_find(unsigned short *address, ...@@ -1844,7 +1875,38 @@ static int __init it87_find(unsigned short *address,
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;
} 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 { } else {
int reg; int reg;
bool uart6; bool uart6;
...@@ -1966,7 +2028,7 @@ static void it87_remove_files(struct device *dev) ...@@ -1966,7 +2028,7 @@ static void it87_remove_files(struct device *dev)
int i; int i;
sysfs_remove_group(&dev->kobj, &it87_group); sysfs_remove_group(&dev->kobj, &it87_group);
for (i = 0; i < 9; i++) { for (i = 0; i < 10; i++) {
if (sio_data->skip_in & (1 << i)) if (sio_data->skip_in & (1 << i))
continue; continue;
sysfs_remove_group(&dev->kobj, &it87_group_in[i]); sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
...@@ -2080,6 +2142,8 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2080,6 +2142,8 @@ static int it87_probe(struct platform_device *pdev)
data->in_scaled |= (1 << 7); /* in7 is VSB */ data->in_scaled |= (1 << 7); /* in7 is VSB */
if (sio_data->internal & (1 << 2)) if (sio_data->internal & (1 << 2))
data->in_scaled |= (1 << 8); /* in8 is Vbat */ 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 == it8782 || sio_data->type == it8783) { } else if (sio_data->type == it8782 || sio_data->type == it8783) {
if (sio_data->internal & (1 << 0)) if (sio_data->internal & (1 << 0))
data->in_scaled |= (1 << 3); /* in3 is VCC5V */ data->in_scaled |= (1 << 3); /* in3 is VCC5V */
...@@ -2102,7 +2166,7 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2102,7 +2166,7 @@ static int it87_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
for (i = 0; i < 9; i++) { for (i = 0; i < 10; i++) {
if (sio_data->skip_in & (1 << i)) if (sio_data->skip_in & (1 << i))
continue; continue;
err = sysfs_create_group(&dev->kobj, &it87_group_in[i]); err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
...@@ -2202,7 +2266,7 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2202,7 +2266,7 @@ static int it87_probe(struct platform_device *pdev)
} }
/* Export labels for internal sensors */ /* Export labels for internal sensors */
for (i = 0; i < 3; i++) { for (i = 0; i < 4; i++) {
if (!(sio_data->internal & (1 << i))) if (!(sio_data->internal & (1 << i)))
continue; continue;
err = sysfs_create_file(&dev->kobj, err = sysfs_create_file(&dev->kobj,
...@@ -2383,8 +2447,9 @@ static void it87_init_device(struct platform_device *pdev) ...@@ -2383,8 +2447,9 @@ static void it87_init_device(struct platform_device *pdev)
} }
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07; data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
/* Set tachometers to 16-bit mode if needed */ /* Set tachometers to 16-bit mode if needed, IT8603E (and IT8728F?)
if (has_16bit_fans(data)) { * has it by default */
if (has_16bit_fans(data) && data->type != it8603) {
tmp = it87_read_value(data, IT87_REG_FAN_16BIT); tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (~tmp & 0x07 & data->has_fan) { if (~tmp & 0x07 & data->has_fan) {
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
...@@ -2464,6 +2529,8 @@ static struct it87_data *it87_update_device(struct device *dev) ...@@ -2464,6 +2529,8 @@ static struct it87_data *it87_update_device(struct device *dev)
} }
/* in8 (battery) has no limit registers */ /* in8 (battery) has no limit registers */
data->in[8][0] = 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++) { for (i = 0; i < 5; i++) {
/* Skip disabled fans */ /* Skip disabled fans */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment