summaryrefslogtreecommitdiff
path: root/drivers/hwmon/it87.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/it87.c')
-rw-r--r--drivers/hwmon/it87.c195
1 files changed, 143 insertions, 52 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 9997f76b1f4a..66f7ceaa7c3f 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -34,6 +34,7 @@
* IT8786E Super I/O chip w/LPC interface
* IT8790E Super I/O chip w/LPC interface
* IT8792E Super I/O chip w/LPC interface
+ * IT87952E Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
*
* Copyright (C) 2001 Chris Gauthron
@@ -63,15 +64,7 @@
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
it8771, it8772, it8781, it8782, it8783, it8786, it8790,
- it8792, it8603, it8620, it8622, it8628 };
-
-static unsigned short force_id;
-module_param(force_id, ushort, 0);
-MODULE_PARM_DESC(force_id, "Override the detected device ID");
-
-static bool ignore_resource_conflict;
-module_param(ignore_resource_conflict, bool, 0);
-MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
+ it8792, it8603, it8620, it8622, it8628, it87952 };
static struct platform_device *it87_pdev[2];
@@ -87,6 +80,14 @@ static struct platform_device *it87_pdev[2];
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
+static inline void __superio_enter(int ioreg)
+{
+ outb(0x87, ioreg);
+ outb(0x01, ioreg);
+ outb(0x55, ioreg);
+ outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
+}
+
static inline int superio_inb(int ioreg, int reg)
{
outb(reg, ioreg);
@@ -124,17 +125,16 @@ static inline int superio_enter(int ioreg)
if (!request_muxed_region(ioreg, 2, DRVNAME))
return -EBUSY;
- outb(0x87, ioreg);
- outb(0x01, ioreg);
- outb(0x55, ioreg);
- outb(ioreg == REG_4E ? 0xaa : 0x55, ioreg);
+ __superio_enter(ioreg);
return 0;
}
-static inline void superio_exit(int ioreg)
+static inline void superio_exit(int ioreg, bool noexit)
{
- outb(0x02, ioreg);
- outb(0x02, ioreg + 1);
+ if (!noexit) {
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
+ }
release_region(ioreg, 2);
}
@@ -161,6 +161,7 @@ static inline void superio_exit(int ioreg)
#define IT8622E_DEVID 0x8622
#define IT8623E_DEVID 0x8623
#define IT8628E_DEVID 0x8628
+#define IT87952E_DEVID 0x8695
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
@@ -176,6 +177,13 @@ static inline void superio_exit(int ioreg)
#define IT87_SIO_VID_REG 0xfc /* VID value */
#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
+/* Force chip IDs to specified values. Should only be used for testing */
+static unsigned short force_id[2];
+static unsigned int force_id_cnt;
+
+/* ACPI resource conflicts are ignored if this parameter is set to 1 */
+static bool ignore_resource_conflict;
+
/* Update battery voltage after every reading if true */
static bool update_vbat;
@@ -272,7 +280,7 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
struct it87_devices {
const char *name;
- const char * const suffix;
+ const char * const model;
u32 features;
u8 peci_mask;
u8 old_peci_mask;
@@ -297,28 +305,35 @@ struct it87_devices {
#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */
#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */
#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */
+/*
+ * Disabling configuration mode on some chips can result in system
+ * hang-ups and access failures to the Super-IO chip at the
+ * second SIO address. Never exit configuration mode on these
+ * chips to avoid the problem.
+ */
+#define FEAT_CONF_NOEXIT BIT(19) /* Chip should not exit conf mode */
static const struct it87_devices it87_devices[] = {
[it87] = {
.name = "it87",
- .suffix = "F",
+ .model = "IT87F",
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
},
[it8712] = {
.name = "it8712",
- .suffix = "F",
+ .model = "IT8712F",
.features = FEAT_OLD_AUTOPWM | FEAT_VID,
/* may need to overwrite */
},
[it8716] = {
.name = "it8716",
- .suffix = "F",
+ .model = "IT8716F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2,
},
[it8718] = {
.name = "it8718",
- .suffix = "F",
+ .model = "IT8718F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
@@ -326,7 +341,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8720] = {
.name = "it8720",
- .suffix = "F",
+ .model = "IT8720F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2,
@@ -334,7 +349,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8721] = {
.name = "it8721",
- .suffix = "F",
+ .model = "IT8721F",
.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 | FEAT_IN7_INTERNAL
@@ -344,7 +359,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8728] = {
.name = "it8728",
- .suffix = "F",
+ .model = "IT8728F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2,
@@ -352,7 +367,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8732] = {
.name = "it8732",
- .suffix = "F",
+ .model = "IT8732F",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
@@ -361,7 +376,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8771] = {
.name = "it8771",
- .suffix = "E",
+ .model = "IT8771E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -373,7 +388,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8772] = {
.name = "it8772",
- .suffix = "E",
+ .model = "IT8772E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -385,28 +400,28 @@ static const struct it87_devices it87_devices[] = {
},
[it8781] = {
.name = "it8781",
- .suffix = "F",
+ .model = "IT8781F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8782] = {
.name = "it8782",
- .suffix = "F",
+ .model = "IT8782F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
- .suffix = "E/F",
+ .model = "IT8783E/F",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2,
.old_peci_mask = 0x4,
},
[it8786] = {
.name = "it8786",
- .suffix = "E",
+ .model = "IT8786E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2,
@@ -414,24 +429,24 @@ static const struct it87_devices it87_devices[] = {
},
[it8790] = {
.name = "it8790",
- .suffix = "E",
+ .model = "IT8790E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
- | FEAT_PWM_FREQ2,
+ | FEAT_PWM_FREQ2 | FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
},
[it8792] = {
.name = "it8792",
- .suffix = "E",
+ .model = "IT8792E/IT8795E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
- | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL,
+ | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
[it8603] = {
.name = "it8603",
- .suffix = "E",
+ .model = "IT8603E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_AVCC3 | FEAT_PWM_FREQ2,
@@ -439,7 +454,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8620] = {
.name = "it8620",
- .suffix = "E",
+ .model = "IT8620E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
@@ -448,7 +463,7 @@ static const struct it87_devices it87_devices[] = {
},
[it8622] = {
.name = "it8622",
- .suffix = "E",
+ .model = "IT8622E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
@@ -457,13 +472,22 @@ static const struct it87_devices it87_devices[] = {
},
[it8628] = {
.name = "it8628",
- .suffix = "E",
+ .model = "IT8628E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V,
.peci_mask = 0x07,
},
+ [it87952] = {
+ .name = "it87952",
+ .model = "IT87952E",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
+ | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_CONF_NOEXIT,
+ .peci_mask = 0x07,
+ .old_peci_mask = 0x02, /* Actually reports PCH */
+ },
};
#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
@@ -490,6 +514,7 @@ static const struct it87_devices it87_devices[] = {
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
+#define has_conf_noexit(data) ((data)->features & FEAT_CONF_NOEXIT)
struct it87_sio_data {
int sioaddr;
@@ -2397,11 +2422,11 @@ static const struct attribute_group it87_group_auto_pwm = {
/* SuperIO detection - will change isa_address if a chip is found */
static int __init it87_find(int sioaddr, unsigned short *address,
- struct it87_sio_data *sio_data)
+ struct it87_sio_data *sio_data, int chip_cnt)
{
int err;
u16 chip_type;
- const struct it87_devices *config;
+ const struct it87_devices *config = NULL;
err = superio_enter(sioaddr);
if (err)
@@ -2413,8 +2438,12 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (chip_type == 0xffff)
goto exit;
- if (force_id)
- chip_type = force_id;
+ if (force_id_cnt == 1) {
+ /* If only one value given use for all chips */
+ if (force_id[0])
+ chip_type = force_id[0];
+ } else if (force_id[chip_cnt])
+ chip_type = force_id[chip_cnt];
switch (chip_type) {
case IT8705F_DEVID:
@@ -2479,6 +2508,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
case IT8628E_DEVID:
sio_data->type = it8628;
break;
+ case IT87952E_DEVID:
+ sio_data->type = it87952;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -2486,27 +2518,29 @@ static int __init it87_find(int sioaddr, unsigned short *address,
goto exit;
}
+ config = &it87_devices[sio_data->type];
+
superio_select(sioaddr, PME);
if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
- pr_info("Device not activated, skipping\n");
+ pr_info("Device (chip %s ioreg 0x%x) not activated, skipping\n",
+ config->model, sioaddr);
goto exit;
}
*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
if (*address == 0) {
- pr_info("Base address not set, skipping\n");
+ pr_info("Base address not set (chip %s ioreg 0x%x), skipping\n",
+ config->model, sioaddr);
goto exit;
}
err = 0;
sio_data->sioaddr = sioaddr;
sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
- pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
- it87_devices[sio_data->type].suffix,
+ pr_info("Found %s chip at 0x%x, revision %d\n",
+ it87_devices[sio_data->type].model,
*address, sio_data->revision);
- config = &it87_devices[sio_data->type];
-
/* in7 (VSB or VCCH5V) is always internal on some chips */
if (has_in7_internal(config))
sio_data->internal |= BIT(1);
@@ -2824,7 +2858,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
sio_data->skip_pwm |= dmi_data->skip_pwm;
exit:
- superio_exit(sioaddr);
+ superio_exit(sioaddr, config ? has_conf_noexit(config) : false);
return err;
}
@@ -3210,7 +3244,7 @@ static void it87_resume_sio(struct platform_device *pdev)
reg2c);
}
- superio_exit(data->sioaddr);
+ superio_exit(data->sioaddr, has_conf_noexit(data));
}
static int it87_resume(struct device *dev)
@@ -3311,6 +3345,27 @@ static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
}
/*
+ * On various Gigabyte AM4 boards (AB350, AX370), the second Super-IO chip
+ * (IT8792E) needs to be in configuration mode before accessing the first
+ * due to a bug in IT8792E which otherwise results in LPC bus access errors.
+ * This needs to be done before accessing the first Super-IO chip since
+ * the second chip may have been accessed prior to loading this driver.
+ *
+ * The problem is also reported to affect IT8795E, which is used on X299 boards
+ * and has the same chip ID as IT8792E (0x8733). It also appears to affect
+ * systems with IT8790E, which is used on some Z97X-Gaming boards as well as
+ * Z87X-OC.
+ * DMI entries for those systems will be added as they become available and
+ * as the problem is confirmed to affect those boards.
+ */
+static int it87_sio_force(const struct dmi_system_id *dmi_entry)
+{
+ __superio_enter(REG_4E);
+
+ return it87_dmi_cb(dmi_entry);
+};
+
+/*
* On the Shuttle SN68PT, FAN_CTL2 is apparently not
* connected to a fan, but to something else. One user
* has reported instant system power-off when changing
@@ -3332,7 +3387,34 @@ static struct it87_dmi_data nvidia_fn68pt = {
.driver_data = data, \
}
+#define IT87_DMI_MATCH_GBT(name, cb, data) \
+ IT87_DMI_MATCH_VND("Gigabyte Technology Co., Ltd.", name, cb, data)
+
static const struct dmi_system_id it87_dmi_table[] __initconst = {
+ IT87_DMI_MATCH_GBT("AB350", it87_sio_force, NULL),
+ /* ? + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("AX370", it87_sio_force, NULL),
+ /* ? + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("Z97X-Gaming G1", it87_sio_force, NULL),
+ /* ? + IT8790E */
+ IT87_DMI_MATCH_GBT("TRX40 AORUS XTREME", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("Z390 AORUS ULTRA-CF", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("B550 AORUS PRO AC", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS MASTER", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS PRO", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570 AORUS PRO WIFI", it87_sio_force, NULL),
+ /* IT8688E + IT8792E/IT8795E */
+ IT87_DMI_MATCH_GBT("X570S AERO G", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
+ IT87_DMI_MATCH_GBT("Z690 AORUS PRO DDR4", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
+ IT87_DMI_MATCH_GBT("Z690 AORUS PRO", it87_sio_force, NULL),
+ /* IT8689E + IT87952E */
IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
{ }
@@ -3356,7 +3438,7 @@ static int __init sm_it87_init(void)
for (i = 0; i < ARRAY_SIZE(sioaddr); i++) {
memset(&sio_data, 0, sizeof(struct it87_sio_data));
isa_address[i] = 0;
- err = it87_find(sioaddr[i], &isa_address[i], &sio_data);
+ err = it87_find(sioaddr[i], &isa_address[i], &sio_data, i);
if (err || isa_address[i] == 0)
continue;
/*
@@ -3404,11 +3486,20 @@ static void __exit sm_it87_exit(void)
MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
+
+module_param_array(force_id, ushort, &force_id_cnt, 0);
+MODULE_PARM_DESC(force_id, "Override one or more detected device ID(s)");
+
+module_param(ignore_resource_conflict, bool, 0);
+MODULE_PARM_DESC(ignore_resource_conflict, "Ignore ACPI resource conflict");
+
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
+
module_param(fix_pwm_polarity, bool, 0);
MODULE_PARM_DESC(fix_pwm_polarity,
"Force PWM polarity to active high (DANGEROUS)");
+
MODULE_LICENSE("GPL");
module_init(sm_it87_init);