From c145d5c628c8ca02dabbf6829ae19ce525d42796 Mon Sep 17 00:00:00 2001 From: Rudolf Marek Date: Wed, 29 Jan 2014 20:40:08 +0100 Subject: [PATCH] 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: Rudolf Marek Signed-off-by: Jean Delvare --- Documentation/hwmon/it87 | 27 +++++++++---- drivers/hwmon/Kconfig | 4 +- drivers/hwmon/it87.c | 103 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 106 insertions(+), 28 deletions(-) diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index c263740..0f5bba9 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 @@ -2,6 +2,10 @@ Kernel driver it87 ================== Supported chips: + * IT8603E + Prefix: 'it8603' + Addresses scanned: from Super I/O config space (8 I/O ports) + Datasheet: Not publicly available * IT8705F Prefix: 'it87' Addresses scanned: from Super I/O config space (8 I/O ports) @@ -90,7 +94,7 @@ motherboard models. 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, IT8782F, IT8783E/F, and SiS950 chips. @@ -129,6 +133,10 @@ to userspace applications. The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F, 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 when the Overtemperature Shutdown limit is crossed. @@ -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 zero'; this is important for negative voltage measurements. All voltage 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 -voltage in8 does not have limit registers. - -On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are -internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F), -in8 and optionally in3). The driver handles this transparently so user-space -doesn't have to care. +0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The +battery voltage in8 does not have limit registers. + +On the IT8603E, IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs +are internal and scaled inside the chip: +* in3 (optional) +* 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 voltage level your processor should work with. This is hardcoded by diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 52d548f..f6ca3b2 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -573,8 +573,8 @@ config SENSORS_IT87 help If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, - IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the - SiS950 clone. + IT8771E, IT8772E, IT8782F, IT8783E/F and IT8603E sensor chips, + and the SiS950 clone. This driver can also be built as a module. If so, the module will be called it87. diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 29ffa27..b78f711 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -10,7 +10,8 @@ * 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 + * 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 @@ -64,7 +65,7 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771, - it8772, it8782, it8783 }; + it8772, it8782, it8783, it8603 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -146,6 +147,7 @@ static inline void superio_exit(void) #define IT8772E_DEVID 0x8772 #define IT8782F_DEVID 0x8782 #define IT8783E_DEVID 0x8783 +#define IT8306E_DEVID 0x8603 #define IT87_ACT_REG 0x30 #define IT87_BASE_REG 0x60 @@ -315,6 +317,12 @@ static const struct it87_devices it87_devices[] = { | FEAT_TEMP_OLD_PECI, .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) @@ -361,7 +369,7 @@ struct it87_data { unsigned long last_updated; /* In jiffies */ 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 */ u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */ 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, 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, @@ -734,7 +743,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; @@ -929,6 +938,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) { @@ -948,10 +961,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); @@ -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(in7_label, S_IRUGO, show_label, NULL, 1); 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 *devattr, char *buf) @@ -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 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_min.dev_attr.attr, @@ -1476,9 +1494,12 @@ static struct attribute *it87_attributes_in[9][5] = { }, { &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[9] = { +static const struct attribute_group it87_group_in[10] = { { .attrs = it87_attributes_in[0] }, { .attrs = it87_attributes_in[1] }, { .attrs = it87_attributes_in[2] }, @@ -1488,6 +1509,7 @@ static const struct attribute_group it87_group_in[9] = { { .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] = { @@ -1546,7 +1568,8 @@ static struct attribute *it87_attributes_in_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, + NULL, }; static struct attribute *it87_attributes_temp_beep[] = { @@ -1685,6 +1708,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 }; @@ -1742,6 +1766,9 @@ static int __init it87_find(unsigned short *address, case IT8783E_DEVID: sio_data->type = it8783; break; + case IT8306E_DEVID: + sio_data->type = it8603; + break; case 0xffff: /* No device at all */ goto exit; default: @@ -1763,11 +1790,15 @@ 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 == 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) { @@ -1844,7 +1875,38 @@ static int __init it87_find(unsigned short *address, 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; @@ -1966,7 +2028,7 @@ static void it87_remove_files(struct device *dev) int i; 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)) continue; sysfs_remove_group(&dev->kobj, &it87_group_in[i]); @@ -2080,6 +2142,8 @@ static int 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 == it8782 || sio_data->type == it8783) { if (sio_data->internal & (1 << 0)) data->in_scaled |= (1 << 3); /* in3 is VCC5V */ @@ -2102,7 +2166,7 @@ static int it87_probe(struct platform_device *pdev) if (err) return err; - for (i = 0; i < 9; i++) { + for (i = 0; i < 10; i++) { if (sio_data->skip_in & (1 << i)) continue; err = sysfs_create_group(&dev->kobj, &it87_group_in[i]); @@ -2202,7 +2266,7 @@ static int it87_probe(struct platform_device *pdev) } /* 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, @@ -2383,8 +2447,9 @@ static void 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, IT8603E (and IT8728F?) + * has it by default */ + if (has_16bit_fans(data) && data->type != it8603) { tmp = it87_read_value(data, IT87_REG_FAN_16BIT); if (~tmp & 0x07 & data->has_fan) { dev_dbg(&pdev->dev, @@ -2464,6 +2529,8 @@ static struct it87_data *it87_update_device(struct device *dev) } /* in8 (battery) has no limit registers */ 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 */ -- 2.7.4