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.c1003
1 files changed, 766 insertions, 237 deletions
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 4dfc7238313e..e233aafa8856 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* it87.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring.
@@ -33,20 +34,11 @@
* 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
* Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -72,11 +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");
+ it8792, it8603, it8620, it8622, it8628, it87952 };
static struct platform_device *it87_pdev[2];
@@ -92,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);
@@ -121,7 +117,7 @@ static inline void superio_select(int ioreg, int ldn)
outb(ldn, ioreg + 1);
}
-static inline int superio_enter(int ioreg)
+static inline int superio_enter(int ioreg, bool noentry)
{
/*
* Try to reserve ioreg and ioreg + 1 for exclusive access.
@@ -129,17 +125,17 @@ 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);
+ if (!noentry)
+ __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);
}
@@ -166,8 +162,12 @@ static inline void superio_exit(int ioreg)
#define IT8622E_DEVID 0x8622
#define IT8623E_DEVID 0x8623
#define IT8628E_DEVID 0x8628
-#define IT87_ACT_REG 0x30
-#define IT87_BASE_REG 0x60
+#define IT87952E_DEVID 0x8695
+
+/* Logical device 4 (Environmental Monitor) registers */
+#define IT87_ACT_REG 0x30
+#define IT87_BASE_REG 0x60
+#define IT87_SPECIAL_CFG_REG 0xf3 /* special configuration register */
/* Logical device 7 registers (IT8712F and later) */
#define IT87_SIO_GPIO1_REG 0x25
@@ -181,6 +181,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;
@@ -215,6 +222,10 @@ static bool fix_pwm_polarity;
* Super-I/O configuration space.
*/
#define IT87_REG_VID 0x0a
+
+/* Interface Selection register on other chips */
+#define IT87_REG_IFSEL 0x0a
+
/*
* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
* for fan divisors. Later IT8712F revisions must use 16-bit tachometer
@@ -277,10 +288,12 @@ 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;
+ u8 smbus_bitmap; /* SMBus enable bits in extra config register */
+ u8 ec_special_config;
};
#define FEAT_12MV_ADC BIT(0)
@@ -302,74 +315,89 @@ 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_NOCONF BIT(19) /* Chip conf mode enabled on startup */
+#define FEAT_FOUR_FANS BIT(20) /* Supports four fans */
+#define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */
+#define FEAT_FOUR_TEMP BIT(22)
+#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */
static const struct it87_devices it87_devices[] = {
[it87] = {
.name = "it87",
- .suffix = "F",
- .features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
+ .model = "IT87F",
+ .features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
+ /* may need to overwrite */
},
[it8712] = {
.name = "it8712",
- .suffix = "F",
- .features = FEAT_OLD_AUTOPWM | FEAT_VID,
- /* may need to overwrite */
+ .model = "IT8712F",
+ .features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
+ /* 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,
+ | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
+ | FEAT_FANCTL_ONOFF,
},
[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,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[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,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.old_peci_mask = 0x4,
},
[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
- | FEAT_PWM_FREQ2,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
[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,
+ | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
+ | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[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,
+ | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
+ | FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
[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,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI: guesswork */
/* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */
@@ -378,10 +406,10 @@ 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,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI (coreboot) */
/* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */
@@ -390,53 +418,57 @@ 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,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+ | FEAT_FANCTL_ONOFF,
.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,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+ | FEAT_FANCTL_ONOFF,
.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,
+ | FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
+ | FEAT_FANCTL_ONOFF,
.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,
+ | FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[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_FANCTL_ONOFF | FEAT_NOCONF,
.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_FANCTL_ONOFF
+ | FEAT_NOCONF,
.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,
@@ -444,30 +476,41 @@ 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
- | FEAT_SIX_TEMP | FEAT_VIN3_5V,
+ | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
.peci_mask = 0x07,
},
[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
- | FEAT_AVCC3 | FEAT_VIN3_5V,
+ | FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
.peci_mask = 0x07,
+ .smbus_bitmap = BIT(1) | BIT(2),
},
[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,
+ | FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
+ .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_FANCTL_ONOFF
+ | FEAT_NOCONF,
.peci_mask = 0x07,
+ .old_peci_mask = 0x02, /* Actually reports PCH */
},
};
@@ -483,32 +526,47 @@ static const struct it87_devices it87_devices[] = {
(((data)->features & FEAT_TEMP_OLD_PECI) && \
((data)->old_peci_mask & BIT(nr)))
#define has_fan16_config(data) ((data)->features & FEAT_FAN16_CONFIG)
+#define has_four_fans(data) ((data)->features & (FEAT_FOUR_FANS | \
+ FEAT_FIVE_FANS | \
+ FEAT_SIX_FANS))
#define has_five_fans(data) ((data)->features & (FEAT_FIVE_FANS | \
FEAT_SIX_FANS))
+#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_vid(data) ((data)->features & FEAT_VID)
#define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL)
-#define has_six_fans(data) ((data)->features & FEAT_SIX_FANS)
#define has_avcc3(data) ((data)->features & FEAT_AVCC3)
-#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \
- | FEAT_SIX_PWM))
+#define has_four_pwm(data) ((data)->features & (FEAT_FOUR_PWM | \
+ FEAT_FIVE_PWM | \
+ FEAT_SIX_PWM))
+#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM | \
+ FEAT_SIX_PWM))
#define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM)
#define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2)
+#define has_four_temp(data) ((data)->features & FEAT_FOUR_TEMP)
#define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP)
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
+#define has_noconf(data) ((data)->features & FEAT_NOCONF)
+#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \
+ FEAT_10_9MV_ADC))
+#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
struct it87_sio_data {
+ int sioaddr;
enum chips type;
/* Values read from Super-I/O config space */
u8 revision;
u8 vid_value;
u8 beep_pin;
u8 internal; /* Internal sensors can be labeled */
+ bool need_in7_reroute;
/* Features skipped based on config or DMI */
u16 skip_in;
u8 skip_vid;
u8 skip_fan;
u8 skip_pwm;
u8 skip_temp;
+ u8 smbus_bitmap;
+ u8 ec_special_config;
};
/*
@@ -517,21 +575,26 @@ struct it87_sio_data {
*/
struct it87_data {
const struct attribute_group *groups[7];
+ int sioaddr;
enum chips type;
u32 features;
u8 peci_mask;
u8 old_peci_mask;
+ u8 smbus_bitmap; /* !=0 if SMBus needs to be disabled */
+ u8 ec_special_config; /* EC special config register restore value */
+
unsigned short addr;
const char *name;
struct mutex update_lock;
- char valid; /* !=0 if following fields are valid */
+ bool valid; /* true if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 in_scaled; /* Internal voltage sensors are scaled */
u16 in_internal; /* Bitfield, internal sensors (for labels) */
u16 has_in; /* Bitfield, voltage sensors enabled */
u8 in[NUM_VIN][3]; /* [nr][0]=in, [1]=min, [2]=max */
+ bool need_in7_reroute;
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[NUM_FAN][2]; /* Register values, [nr][0]=fan, [1]=min */
u8 has_temp; /* Bitfield, temp sensors enabled */
@@ -568,6 +631,14 @@ struct it87_data {
s8 auto_temp[NUM_AUTO_PWM][5]; /* [nr][0] is point1_temp_hyst */
};
+/* Board specific settings from DMI matching */
+struct it87_dmi_data {
+ u8 skip_pwm; /* pwm channels to skip for this board */
+};
+
+/* Global for results from DMI matching, if needed */
+static struct it87_dmi_data *dmi_data;
+
static int adc_lsb(const struct it87_data *data, int nr)
{
int lsb;
@@ -667,8 +738,42 @@ static const unsigned int pwm_freq[8] = {
750000,
};
+static int smbus_disable(struct it87_data *data)
+{
+ int err;
+
+ if (data->smbus_bitmap) {
+ err = superio_enter(data->sioaddr, has_noconf(data));
+ if (err)
+ return err;
+ superio_select(data->sioaddr, PME);
+ superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
+ data->ec_special_config & ~data->smbus_bitmap);
+ superio_exit(data->sioaddr, has_noconf(data));
+ }
+ return 0;
+}
+
+static int smbus_enable(struct it87_data *data)
+{
+ int err;
+
+ if (data->smbus_bitmap) {
+ err = superio_enter(data->sioaddr, has_noconf(data));
+ if (err)
+ return err;
+
+ superio_select(data->sioaddr, PME);
+ superio_outb(data->sioaddr, IT87_SPECIAL_CFG_REG,
+ data->ec_special_config);
+ superio_exit(data->sioaddr, has_noconf(data));
+ }
+ return 0;
+}
+
/*
* Must be called with data->update_lock held, except during initialization.
+ * Must be called with SMBus accesses disabled.
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
* would slow down the IT87 access and should not be necessary.
*/
@@ -680,6 +785,7 @@ static int it87_read_value(struct it87_data *data, u8 reg)
/*
* Must be called with data->update_lock held, except during initialization.
+ * Must be called with SMBus accesses disabled.
* We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
* would slow down the IT87 access and should not be necessary.
*/
@@ -739,15 +845,39 @@ static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
}
}
+static int it87_lock(struct it87_data *data)
+{
+ int err;
+
+ mutex_lock(&data->update_lock);
+ err = smbus_disable(data);
+ if (err)
+ mutex_unlock(&data->update_lock);
+ return err;
+}
+
+static void it87_unlock(struct it87_data *data)
+{
+ smbus_enable(data);
+ mutex_unlock(&data->update_lock);
+}
+
static struct it87_data *it87_update_device(struct device *dev)
{
struct it87_data *data = dev_get_drvdata(dev);
+ struct it87_data *ret = data;
+ int err;
int i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2) ||
- !data->valid) {
+ !data->valid) {
+ err = smbus_disable(data);
+ if (err) {
+ ret = ERR_PTR(err);
+ goto unlock;
+ }
if (update_vbat) {
/*
* Cleared after each update, so reenable. Value
@@ -849,12 +979,12 @@ static struct it87_data *it87_update_device(struct device *dev)
data->vid &= 0x3f;
}
data->last_updated = jiffies;
- data->valid = 1;
+ data->valid = true;
+ smbus_enable(data);
}
-
+unlock:
mutex_unlock(&data->update_lock);
-
- return data;
+ return ret;
}
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
@@ -865,6 +995,9 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
int index = sattr->index;
int nr = sattr->nr;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
}
@@ -876,17 +1009,21 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
int index = sattr->index;
int nr = sattr->nr;
unsigned long val;
+ int err;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
data->in[nr][index] = in_to_reg(data, nr, val);
it87_write_value(data,
index == 1 ? IT87_REG_VIN_MIN(nr)
: IT87_REG_VIN_MAX(nr),
data->in[nr][index]);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -953,6 +1090,9 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
int index = sattr->index;
struct it87_data *data = it87_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
}
@@ -965,11 +1105,14 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
long val;
u8 reg, regval;
+ int err;
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
switch (index) {
default:
@@ -985,14 +1128,14 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
regval |= 0x80;
it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
}
- data->valid = 0;
+ data->valid = false;
reg = IT87_REG_TEMP_OFFSET[nr];
break;
}
data->temp[nr][index] = TEMP_TO_REG(val);
it87_write_value(data, reg, data->temp[nr][index]);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1021,23 +1164,66 @@ static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
+static int get_temp_type(struct it87_data *data, int index)
+{
+ /*
+ * 2 is deprecated;
+ * 3 = thermal diode;
+ * 4 = thermistor;
+ * 5 = AMDTSI;
+ * 6 = Intel PECI;
+ * 0 = disabled
+ */
+ u8 reg, extra;
+ int ttype, type = 0;
+
+ /* Detect PECI vs. AMDTSI */
+ ttype = 6;
+ if ((has_temp_peci(data, index)) || data->type == it8721 ||
+ data->type == it8720) {
+ extra = it87_read_value(data, IT87_REG_IFSEL);
+ if ((extra & 0x70) == 0x40)
+ ttype = 5;
+ }
+
+ reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
+
+ /* Per chip special detection */
+ switch (data->type) {
+ case it8622:
+ if (!(reg & 0xc0) && index == 3)
+ type = ttype;
+ break;
+ default:
+ break;
+ }
+
+ if (type || index >= 3)
+ return type;
+
+ extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
+
+ if ((has_temp_peci(data, index) && (reg >> 6 == index + 1)) ||
+ (has_temp_old_peci(data, index) && (extra & 0x80)))
+ type = ttype; /* Intel PECI or AMDTSI */
+ else if (reg & BIT(index))
+ type = 3; /* thermal diode */
+ else if (reg & BIT(index + 3))
+ type = 4; /* thermistor */
+
+ return type;
+}
+
static ssize_t show_temp_type(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
- 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)) ||
- (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 */
- if (reg & (8 << nr))
- return sprintf(buf, "4\n"); /* thermistor */
- return sprintf(buf, "0\n"); /* disabled */
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ return sprintf(buf, "%d\n", get_temp_type(data, sensor_attr->index));
}
static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
@@ -1049,10 +1235,15 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
long val;
u8 reg, extra;
+ int err;
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
+ err = it87_lock(data);
+ if (err)
+ return err;
+
reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
reg &= ~(1 << nr);
reg &= ~(8 << nr);
@@ -1075,17 +1266,19 @@ static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
reg |= (nr + 1) << 6;
else if (has_temp_old_peci(data, nr) && val == 6)
extra |= 0x80;
- else if (val != 0)
- return -EINVAL;
+ else if (val != 0) {
+ count = -EINVAL;
+ goto unlock;
+ }
- 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);
+ data->valid = false; /* Force cache refresh */
+unlock:
+ it87_unlock(data);
return count;
}
@@ -1100,11 +1293,12 @@ static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
static int pwm_mode(const struct it87_data *data, int nr)
{
- if (data->type != it8603 && nr < 3 && !(data->fan_main_ctrl & BIT(nr)))
- return 0; /* Full speed */
+ if (has_fanctl_onoff(data) && nr < 3 &&
+ !(data->fan_main_ctrl & BIT(nr)))
+ return 0; /* Full speed */
if (data->pwm_ctrl[nr] & 0x80)
- return 2; /* Automatic mode */
- if ((data->type == it8603 || nr >= 3) &&
+ return 2; /* Automatic mode */
+ if ((!has_fanctl_onoff(data) || nr >= 3) &&
data->pwm_duty[nr] == pwm_to_reg(data, 0xff))
return 0; /* Full speed */
@@ -1120,6 +1314,9 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
int speed;
struct it87_data *data = it87_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
speed = has_16bit_fans(data) ?
FAN16_FROM_REG(data->fan[nr][index]) :
FAN_FROM_REG(data->fan[nr][index],
@@ -1134,6 +1331,9 @@ static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%lu\n", DIV_FROM_REG(data->fan_div[nr]));
}
@@ -1144,6 +1344,9 @@ static ssize_t show_pwm_enable(struct device *dev,
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n", pwm_mode(data, nr));
}
@@ -1154,6 +1357,9 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n",
pwm_from_reg(data, data->pwm_duty[nr]));
}
@@ -1167,6 +1373,9 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
unsigned int freq;
int index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
if (has_pwm_freq2(data) && nr == 1)
index = (data->extra >> 4) & 0x07;
else
@@ -1186,12 +1395,15 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
long val;
+ int err;
u8 reg;
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
if (has_16bit_fans(data)) {
data->fan[nr][index] = FAN16_TO_REG(val);
@@ -1218,7 +1430,7 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
data->fan[nr][index]);
}
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1229,13 +1441,16 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
unsigned long val;
- int min;
+ int min, err;
u8 old;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
old = it87_read_value(data, IT87_REG_FAN_DIV);
/* Save fan min limit */
@@ -1263,7 +1478,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
data->fan[nr][1] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1304,6 +1519,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
long val;
+ int err;
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 2)
return -EINVAL;
@@ -1314,10 +1530,12 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
if (val == 0) {
- if (nr < 3 && data->type != it8603) {
+ if (nr < 3 && has_fanctl_onoff(data)) {
int tmp;
/* make sure the fan is on when in on/off mode */
tmp = it87_read_value(data, IT87_REG_FAN_CTL);
@@ -1357,7 +1575,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
data->pwm_ctrl[nr] = ctrl;
it87_write_value(data, IT87_REG_PWM[nr], ctrl);
- if (data->type != it8603 && nr < 3) {
+ if (has_fanctl_onoff(data) && nr < 3) {
/* set SmartGuardian mode */
data->fan_main_ctrl |= BIT(nr);
it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
@@ -1365,7 +1583,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
}
}
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1376,11 +1594,15 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
long val;
+ int err;
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
it87_update_pwm_ctrl(data, nr);
if (has_newer_autopwm(data)) {
/*
@@ -1388,8 +1610,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
* is read-only so we can't write the value.
*/
if (data->pwm_ctrl[nr] & 0x80) {
- mutex_unlock(&data->update_lock);
- return -EBUSY;
+ count = -EBUSY;
+ goto unlock;
}
data->pwm_duty[nr] = pwm_to_reg(data, val);
it87_write_value(data, IT87_REG_PWM_DUTY[nr],
@@ -1406,7 +1628,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_ctrl[nr]);
}
}
- mutex_unlock(&data->update_lock);
+unlock:
+ it87_unlock(data);
return count;
}
@@ -1417,6 +1640,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
unsigned long val;
+ int err;
int i;
if (kstrtoul(buf, 10, &val) < 0)
@@ -1431,7 +1655,10 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
break;
}
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
if (nr == 0) {
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
data->fan_ctl |= i << 4;
@@ -1441,7 +1668,7 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute *attr,
data->extra |= i << 4;
it87_write_value(data, IT87_REG_TEMP_EXTRA, data->extra);
}
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1454,6 +1681,9 @@ static ssize_t show_pwm_temp_map(struct device *dev,
int nr = sensor_attr->index;
int map;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
map = data->pwm_temp_map[nr];
if (map >= 3)
map = 0; /* Should never happen */
@@ -1471,6 +1701,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
long val;
+ int err;
u8 reg;
if (kstrtol(buf, 10, &val) < 0)
@@ -1493,7 +1724,10 @@ static ssize_t set_pwm_temp_map(struct device *dev,
return -EINVAL;
}
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
it87_update_pwm_ctrl(data, nr);
data->pwm_temp_map[nr] = reg;
/*
@@ -1505,7 +1739,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
data->pwm_temp_map[nr];
it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
}
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1518,6 +1752,9 @@ static ssize_t show_auto_pwm(struct device *dev, struct device_attribute *attr,
int nr = sensor_attr->nr;
int point = sensor_attr->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n",
pwm_from_reg(data, data->auto_pwm[nr][point]));
}
@@ -1532,18 +1769,22 @@ static ssize_t set_auto_pwm(struct device *dev, struct device_attribute *attr,
int point = sensor_attr->index;
int regaddr;
long val;
+ int err;
if (kstrtol(buf, 10, &val) < 0 || val < 0 || val > 255)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
data->auto_pwm[nr][point] = pwm_to_reg(data, val);
if (has_newer_autopwm(data))
regaddr = IT87_REG_AUTO_TEMP(nr, 3);
else
regaddr = IT87_REG_AUTO_PWM(nr, point);
it87_write_value(data, regaddr, data->auto_pwm[nr][point]);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1554,6 +1795,9 @@ static ssize_t show_auto_pwm_slope(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%d\n", data->auto_pwm[nr][1] & 0x7f);
}
@@ -1565,15 +1809,19 @@ static ssize_t set_auto_pwm_slope(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
unsigned long val;
+ int err;
if (kstrtoul(buf, 10, &val) < 0 || val > 127)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
data->auto_pwm[nr][1] = (data->auto_pwm[nr][1] & 0x80) | val;
it87_write_value(data, IT87_REG_AUTO_TEMP(nr, 4),
data->auto_pwm[nr][1]);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1587,6 +1835,9 @@ static ssize_t show_auto_temp(struct device *dev, struct device_attribute *attr,
int point = sensor_attr->index;
int reg;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
if (has_old_autopwm(data) || point)
reg = data->auto_temp[nr][point];
else
@@ -1605,11 +1856,15 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
int point = sensor_attr->index;
long val;
int reg;
+ int err;
if (kstrtol(buf, 10, &val) < 0 || val < -128000 || val > 127000)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
if (has_newer_autopwm(data) && !point) {
reg = data->auto_temp[nr][1] - TEMP_TO_REG(val);
reg = clamp_val(reg, 0, 0x1f) | (data->auto_temp[nr][0] & 0xe0);
@@ -1622,7 +1877,7 @@ static ssize_t set_auto_temp(struct device *dev, struct device_attribute *attr,
point--;
it87_write_value(data, IT87_REG_AUTO_TEMP(nr, point), reg);
}
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1807,6 +2062,9 @@ static ssize_t alarms_show(struct device *dev, struct device_attribute *attr,
{
struct it87_data *data = it87_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%u\n", data->alarms);
}
static DEVICE_ATTR_RO(alarms);
@@ -1817,6 +2075,9 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
int bitnr = to_sensor_dev_attr(attr)->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
}
@@ -1825,13 +2086,16 @@ static ssize_t clear_intrusion(struct device *dev,
size_t count)
{
struct it87_data *data = dev_get_drvdata(dev);
- int config;
+ int err, config;
long val;
if (kstrtol(buf, 10, &val) < 0 || val != 0)
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
config = it87_read_value(data, IT87_REG_CONFIG);
if (config < 0) {
count = config;
@@ -1839,10 +2103,9 @@ static ssize_t clear_intrusion(struct device *dev,
config |= BIT(5);
it87_write_value(data, IT87_REG_CONFIG, config);
/* Invalidate cache to force re-read */
- data->valid = 0;
+ data->valid = false;
}
- mutex_unlock(&data->update_lock);
-
+ it87_unlock(data);
return count;
}
@@ -1872,6 +2135,9 @@ static ssize_t show_beep(struct device *dev, struct device_attribute *attr,
struct it87_data *data = it87_update_device(dev);
int bitnr = to_sensor_dev_attr(attr)->index;
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%u\n", (data->beeps >> bitnr) & 1);
}
@@ -1881,18 +2147,22 @@ static ssize_t set_beep(struct device *dev, struct device_attribute *attr,
int bitnr = to_sensor_dev_attr(attr)->index;
struct it87_data *data = dev_get_drvdata(dev);
long val;
+ int err;
if (kstrtol(buf, 10, &val) < 0 || (val != 0 && val != 1))
return -EINVAL;
- mutex_lock(&data->update_lock);
+ err = it87_lock(data);
+ if (err)
+ return err;
+
data->beeps = it87_read_value(data, IT87_REG_BEEP_ENABLE);
if (val)
data->beeps |= BIT(bitnr);
else
data->beeps &= ~BIT(bitnr);
it87_write_value(data, IT87_REG_BEEP_ENABLE, data->beeps);
- mutex_unlock(&data->update_lock);
+ it87_unlock(data);
return count;
}
@@ -1945,6 +2215,9 @@ static ssize_t cpu0_vid_show(struct device *dev,
{
struct it87_data *data = it87_update_device(dev);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR_RO(cpu0_vid);
@@ -1970,7 +2243,7 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
if (has_vin3_5v(data) && nr == 0)
label = labels[0];
- else if (has_12mv_adc(data) || has_10_9mv_adc(data))
+ else if (has_scaling(data))
label = labels_it8721[nr];
else
label = labels[nr];
@@ -1986,7 +2259,7 @@ static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3);
static umode_t it87_in_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* voltage index */
int a = index % 5; /* attribute index */
@@ -2070,7 +2343,7 @@ static const struct attribute_group it87_group_in = {
static umode_t it87_temp_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 7; /* temperature index */
int a = index % 7; /* attribute index */
@@ -2083,6 +2356,12 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
if (!(data->has_temp & BIT(i)))
return 0;
+ if (a == 3) {
+ if (get_temp_type(data, i) == 0)
+ return 0;
+ return attr->mode;
+ }
+
if (a == 5 && !has_temp_offset(data))
return 0;
@@ -2131,7 +2410,7 @@ static const struct attribute_group it87_group_temp = {
static umode_t it87_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
if ((index == 2 || index == 3) && !data->has_vid)
@@ -2163,7 +2442,7 @@ static const struct attribute_group it87_group = {
static umode_t it87_fan_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 5; /* fan index */
int a = index % 5; /* attribute index */
@@ -2234,7 +2513,7 @@ static const struct attribute_group it87_group_fan = {
static umode_t it87_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 4; /* pwm index */
int a = index % 4; /* attribute index */
@@ -2295,7 +2574,7 @@ static const struct attribute_group it87_group_pwm = {
static umode_t it87_auto_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev = kobj_to_dev(kobj);
struct it87_data *data = dev_get_drvdata(dev);
int i = index / 11; /* pwm index */
int a = index % 11; /* attribute index */
@@ -2388,21 +2667,60 @@ static const struct attribute_group it87_group_auto_pwm = {
.is_visible = it87_auto_pwm_is_visible,
};
+/*
+ * Original explanation:
+ * 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.
+ *
+ * From other information supplied:
+ * ChipIDs 0x8733, 0x8695 (early ID for IT87952E) and 0x8790 are initialized
+ * and left in configuration mode, and entering and/or exiting configuration
+ * mode is what causes the crash.
+ *
+ * The recommendation is to look up the chipID before doing any mode swap
+ * and then act accordingly.
+ */
/* 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 char *board_vendor, *board_name;
- const struct it87_devices *config;
+ const struct it87_devices *config = NULL;
+ bool enabled = false;
- err = superio_enter(sioaddr);
+ /* First step, lock memory but don't enter configuration mode */
+ err = superio_enter(sioaddr, true);
if (err)
return err;
err = -ENODEV;
- chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID);
+ chip_type = superio_inw(sioaddr, DEVID);
+ /* Check for a valid chip before forcing chip id */
+ if (chip_type == 0xffff) {
+ /* Enter configuration mode */
+ __superio_enter(sioaddr);
+ enabled = true;
+ /* and then try again */
+ chip_type = superio_inw(sioaddr, DEVID);
+ if (chip_type == 0xffff)
+ goto exit;
+ }
+
+ 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:
@@ -2467,6 +2785,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:
@@ -2474,26 +2795,41 @@ static int __init it87_find(int sioaddr, unsigned short *address,
goto exit;
}
+ config = &it87_devices[sio_data->type];
+
+ /*
+ * If previously we didn't enter configuration mode and it isn't a
+ * chip we know is initialised in configuration mode, then enter
+ * configuration mode.
+ *
+ * I don't know if any such chips can exist but be defensive.
+ */
+ if (!enabled && !has_noconf(config)) {
+ __superio_enter(sioaddr);
+ enabled = true;
+ }
+
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);
@@ -2507,8 +2843,10 @@ static int __init it87_find(int sioaddr, unsigned short *address,
else
sio_data->skip_in |= BIT(9);
- if (!has_five_pwm(config))
+ if (!has_four_pwm(config))
sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
+ else if (!has_five_pwm(config))
+ sio_data->skip_pwm |= BIT(4) | BIT(5);
else if (!has_six_pwm(config))
sio_data->skip_pwm |= BIT(5);
@@ -2575,6 +2913,7 @@ static int __init it87_find(int sioaddr, unsigned short *address,
reg2c |= BIT(1);
superio_outb(sioaddr, IT87_SIO_PINX2_REG,
reg2c);
+ sio_data->need_in7_reroute = true;
pr_notice("Routing internal VCCH5V to in7.\n");
}
pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
@@ -2700,6 +3039,34 @@ static int __init it87_find(int sioaddr, unsigned short *address,
sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ } else if (sio_data->type == it8732) {
+ int reg;
+
+ superio_select(sioaddr, GPIO);
+
+ /* Check for pwm2, fan2 */
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
+ if (reg & BIT(1))
+ sio_data->skip_pwm |= BIT(1);
+ if (reg & BIT(2))
+ sio_data->skip_fan |= BIT(1);
+
+ /* Check for pwm3, fan3, fan4 */
+ reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
+ if (reg & BIT(6))
+ sio_data->skip_pwm |= BIT(2);
+ if (reg & BIT(7))
+ sio_data->skip_fan |= BIT(2);
+ if (reg & BIT(5))
+ sio_data->skip_fan |= BIT(3);
+
+ /* Check if AVCC is on VIN3 */
+ reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
+ if (reg & BIT(0))
+ sio_data->internal |= BIT(0);
+
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else {
int reg;
bool uart6;
@@ -2761,13 +3128,13 @@ static int __init it87_find(int sioaddr, unsigned short *address,
uart6 = sio_data->type == it8782 && (reg & BIT(2));
/*
- * The IT8720F has no VIN7 pin, so VCCH should always be
+ * The IT8720F has no VIN7 pin, so VCCH5V should always be
* routed internally to VIN7 with an internal divider.
* Curiously, there still is a configuration bit to control
* this, which means it can be set incorrectly. And even
* more curiously, many boards out there are improperly
* configured, even though the IT8720F datasheet claims
- * that the internal routing of VCCH to VIN7 is the default
+ * that the internal routing of VCCH5V to VIN7 is the default
* setting. So we force the internal routing in this case.
*
* On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
@@ -2777,7 +3144,8 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) {
reg |= BIT(1);
superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
- pr_notice("Routing internal VCCH to in7\n");
+ sio_data->need_in7_reroute = true;
+ pr_notice("Routing internal VCCH5V to in7\n");
}
if (reg & BIT(0))
sio_data->internal |= BIT(0);
@@ -2804,37 +3172,107 @@ static int __init it87_find(int sioaddr, unsigned short *address,
if (sio_data->beep_pin)
pr_info("Beeping is supported\n");
- /* Disable specific features based on DMI strings */
- board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
- board_name = dmi_get_system_info(DMI_BOARD_NAME);
- if (board_vendor && board_name) {
- if (strcmp(board_vendor, "nVIDIA") == 0 &&
- strcmp(board_name, "FN68PT") == 0) {
- /*
- * 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
- * the PWM2 duty cycle, so we disable it.
- * I use the board name string as the trigger in case
- * the same board is ever used in other systems.
- */
- pr_info("Disabling pwm2 due to hardware constraints\n");
- sio_data->skip_pwm = BIT(1);
- }
+ /* Set values based on DMI matches */
+ if (dmi_data)
+ sio_data->skip_pwm |= dmi_data->skip_pwm;
+
+ if (config->smbus_bitmap) {
+ u8 reg;
+
+ superio_select(sioaddr, PME);
+ reg = superio_inb(sioaddr, IT87_SPECIAL_CFG_REG);
+ sio_data->ec_special_config = reg;
+ sio_data->smbus_bitmap = reg & config->smbus_bitmap;
}
exit:
- superio_exit(sioaddr);
+ superio_exit(sioaddr, !enabled);
return err;
}
+/*
+ * Some chips seem to have default value 0xff for all limit
+ * registers. For low voltage limits it makes no sense and triggers
+ * alarms, so change to 0 instead. For high temperature limits, it
+ * means -1 degree C, which surprisingly doesn't trigger an alarm,
+ * but is still confusing, so change to 127 degrees C.
+ */
+static void it87_check_limit_regs(struct it87_data *data)
+{
+ int i, reg;
+
+ for (i = 0; i < NUM_VIN_LIMIT; i++) {
+ reg = it87_read_value(data, IT87_REG_VIN_MIN(i));
+ if (reg == 0xff)
+ it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
+ }
+ for (i = 0; i < NUM_TEMP_LIMIT; i++) {
+ reg = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
+ if (reg == 0xff)
+ it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
+ }
+}
+
+/* Check if voltage monitors are reset manually or by some reason */
+static void it87_check_voltage_monitors_reset(struct it87_data *data)
+{
+ int reg;
+
+ reg = it87_read_value(data, IT87_REG_VIN_ENABLE);
+ if ((reg & 0xff) == 0) {
+ /* Enable all voltage monitors */
+ it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
+ }
+}
+
+/* Check if tachometers are reset manually or by some reason */
+static void it87_check_tachometers_reset(struct platform_device *pdev)
+{
+ struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
+ struct it87_data *data = platform_get_drvdata(pdev);
+ u8 mask, fan_main_ctrl;
+
+ mask = 0x70 & ~(sio_data->skip_fan << 4);
+ fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
+ if ((fan_main_ctrl & mask) == 0) {
+ /* Enable all fan tachometers */
+ fan_main_ctrl |= mask;
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+ fan_main_ctrl);
+ }
+}
+
+/* Set tachometers to 16-bit mode if needed */
+static void it87_check_tachometers_16bit_mode(struct platform_device *pdev)
+{
+ struct it87_data *data = platform_get_drvdata(pdev);
+ int reg;
+
+ if (!has_fan16_config(data))
+ return;
+
+ reg = it87_read_value(data, IT87_REG_FAN_16BIT);
+ if (~reg & 0x07 & data->has_fan) {
+ dev_dbg(&pdev->dev,
+ "Setting fan1-3 to 16-bit mode\n");
+ it87_write_value(data, IT87_REG_FAN_16BIT,
+ reg | 0x07);
+ }
+}
+
+static void it87_start_monitoring(struct it87_data *data)
+{
+ it87_write_value(data, IT87_REG_CONFIG,
+ (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
+ | (update_vbat ? 0x41 : 0x01));
+}
+
/* Called when we have found a new IT87. */
static void it87_init_device(struct platform_device *pdev)
{
struct it87_sio_data *sio_data = dev_get_platdata(&pdev->dev);
struct it87_data *data = platform_get_drvdata(pdev);
int tmp, i;
- u8 mask;
/*
* For each PWM channel:
@@ -2855,23 +3293,7 @@ static void it87_init_device(struct platform_device *pdev)
data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
}
- /*
- * Some chips seem to have default value 0xff for all limit
- * registers. For low voltage limits it makes no sense and triggers
- * alarms, so change to 0 instead. For high temperature limits, it
- * means -1 degree C, which surprisingly doesn't trigger an alarm,
- * but is still confusing, so change to 127 degrees C.
- */
- for (i = 0; i < NUM_VIN_LIMIT; i++) {
- tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
- if (tmp == 0xff)
- it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
- }
- for (i = 0; i < NUM_TEMP_LIMIT; i++) {
- tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
- if (tmp == 0xff)
- it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
- }
+ it87_check_limit_regs(data);
/*
* Temperature channels are not forcibly enabled, as they can be
@@ -2880,45 +3302,24 @@ static void it87_init_device(struct platform_device *pdev)
* run-time through the temp{1-3}_type sysfs accessors if needed.
*/
- /* Check if voltage monitors are reset manually or by some reason */
- tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
- if ((tmp & 0xff) == 0) {
- /* Enable all voltage monitors */
- it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
- }
+ it87_check_voltage_monitors_reset(data);
+
+ it87_check_tachometers_reset(pdev);
- /* Check if tachometers are reset manually or by some reason */
- mask = 0x70 & ~(sio_data->skip_fan << 4);
data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
- if ((data->fan_main_ctrl & mask) == 0) {
- /* Enable all fan tachometers */
- data->fan_main_ctrl |= mask;
- it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
- data->fan_main_ctrl);
- }
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
- tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
-
- /* Set tachometers to 16-bit mode if needed */
- if (has_fan16_config(data)) {
- if (~tmp & 0x07 & data->has_fan) {
- dev_dbg(&pdev->dev,
- "Setting fan1-3 to 16-bit mode\n");
- it87_write_value(data, IT87_REG_FAN_16BIT,
- tmp | 0x07);
- }
- }
+ it87_check_tachometers_16bit_mode(pdev);
/* Check for additional fans */
- if (has_five_fans(data)) {
- if (tmp & BIT(4))
- data->has_fan |= BIT(3); /* fan4 enabled */
- if (tmp & BIT(5))
- data->has_fan |= BIT(4); /* fan5 enabled */
- if (has_six_fans(data) && (tmp & BIT(2)))
- data->has_fan |= BIT(5); /* fan6 enabled */
- }
+ tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
+
+ if (has_four_fans(data) && (tmp & BIT(4)))
+ data->has_fan |= BIT(3); /* fan4 enabled */
+ if (has_five_fans(data) && (tmp & BIT(5)))
+ data->has_fan |= BIT(4); /* fan5 enabled */
+ if (has_six_fans(data) && (tmp & BIT(2)))
+ data->has_fan |= BIT(5); /* fan6 enabled */
/* Fan input pins may be used for alternative functions */
data->has_fan &= ~sio_data->skip_fan;
@@ -2933,10 +3334,7 @@ static void it87_init_device(struct platform_device *pdev)
sio_data->skip_pwm |= BIT(5);
}
- /* Start monitoring */
- it87_write_value(data, IT87_REG_CONFIG,
- (it87_read_value(data, IT87_REG_CONFIG) & 0x3e)
- | (update_vbat ? 0x41 : 0x01));
+ it87_start_monitoring(data);
}
/* Return 1 if and only if the PWM interface is safe to use */
@@ -2986,8 +3384,6 @@ static int it87_check_pwm(struct device *dev)
"PWM configuration is too broken to be fixed\n");
}
- dev_info(dev,
- "Detected broken BIOS defaults, disabling PWM interface\n");
return 0;
} else if (fix_pwm_polarity) {
dev_info(dev,
@@ -3005,6 +3401,7 @@ static int it87_probe(struct platform_device *pdev)
struct it87_sio_data *sio_data = dev_get_platdata(dev);
int enable_pwm_interface;
struct device *hwmon_dev;
+ int err;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
@@ -3020,7 +3417,10 @@ static int it87_probe(struct platform_device *pdev)
return -ENOMEM;
data->addr = res->start;
+ data->sioaddr = sio_data->sioaddr;
data->type = sio_data->type;
+ data->smbus_bitmap = sio_data->smbus_bitmap;
+ data->ec_special_config = sio_data->ec_special_config;
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;
@@ -3047,20 +3447,29 @@ static int it87_probe(struct platform_device *pdev)
break;
}
- /* Now, we do the remaining detection. */
- if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
- it87_read_value(data, IT87_REG_CHIPID) != 0x90)
- return -ENODEV;
-
platform_set_drvdata(pdev, data);
mutex_init(&data->update_lock);
+ err = smbus_disable(data);
+ if (err)
+ return err;
+
+ /* Now, we do the remaining detection. */
+ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) ||
+ it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
+ smbus_enable(data);
+ return -ENODEV;
+ }
+
/* Check PWM configuration */
enable_pwm_interface = it87_check_pwm(dev);
+ if (!enable_pwm_interface)
+ dev_info(dev,
+ "Detected broken BIOS defaults, disabling PWM interface\n");
/* Starting with IT8721F, we handle scaling of internal voltages */
- if (has_12mv_adc(data)) {
+ if (has_scaling(data)) {
if (sio_data->internal & BIT(0))
data->in_scaled |= BIT(3); /* in3 is AVCC */
if (sio_data->internal & BIT(1))
@@ -3085,9 +3494,12 @@ static int it87_probe(struct platform_device *pdev)
}
data->in_internal = sio_data->internal;
+ data->need_in7_reroute = sio_data->need_in7_reroute;
data->has_in = 0x3ff & ~sio_data->skip_in;
- if (has_six_temp(data)) {
+ if (has_four_temp(data)) {
+ data->has_temp |= BIT(3);
+ } else if (has_six_temp(data)) {
u8 reg = it87_read_value(data, IT87_REG_TEMP456_ENABLE);
/* Check for additional temperature sensors */
@@ -3112,6 +3524,8 @@ static int it87_probe(struct platform_device *pdev)
/* Initialize the IT87 chip */
it87_init_device(pdev);
+ smbus_enable(data);
+
if (!sio_data->skip_vid) {
data->has_vid = true;
data->vrm = vid_which_vrm();
@@ -3140,9 +3554,71 @@ static int it87_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
+static void it87_resume_sio(struct platform_device *pdev)
+{
+ struct it87_data *data = dev_get_drvdata(&pdev->dev);
+ int err;
+ int reg2c;
+
+ if (!data->need_in7_reroute)
+ return;
+
+ err = superio_enter(data->sioaddr, has_noconf(data));
+ if (err) {
+ dev_warn(&pdev->dev,
+ "Unable to enter Super I/O to reroute in7 (%d)",
+ err);
+ return;
+ }
+
+ superio_select(data->sioaddr, GPIO);
+
+ reg2c = superio_inb(data->sioaddr, IT87_SIO_PINX2_REG);
+ if (!(reg2c & BIT(1))) {
+ dev_dbg(&pdev->dev,
+ "Routing internal VCCH5V to in7 again");
+
+ reg2c |= BIT(1);
+ superio_outb(data->sioaddr, IT87_SIO_PINX2_REG,
+ reg2c);
+ }
+
+ superio_exit(data->sioaddr, has_noconf(data));
+}
+
+static int it87_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct it87_data *data = dev_get_drvdata(dev);
+
+ it87_resume_sio(pdev);
+
+ it87_lock(data);
+
+ it87_check_pwm(dev);
+ it87_check_limit_regs(data);
+ it87_check_voltage_monitors_reset(data);
+ it87_check_tachometers_reset(pdev);
+ it87_check_tachometers_16bit_mode(pdev);
+
+ it87_start_monitoring(data);
+
+ /* force update */
+ data->valid = false;
+
+ it87_unlock(data);
+
+ it87_update_device(dev);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(it87_dev_pm_ops, NULL, it87_resume);
+
static struct platform_driver it87_driver = {
.driver = {
.name = DRVNAME,
+ .pm = pm_sleep_ptr(&it87_dev_pm_ops),
},
.probe = it87_probe,
};
@@ -3160,8 +3636,10 @@ static int __init it87_device_add(int index, unsigned short address,
int err;
err = acpi_check_resource_conflict(&res);
- if (err)
- return err;
+ if (err) {
+ if (!ignore_resource_conflict)
+ return err;
+ }
pdev = platform_device_alloc(DRVNAME, address);
if (!pdev)
@@ -3194,6 +3672,46 @@ exit_device_put:
return err;
}
+/* callback function for DMI */
+static int it87_dmi_cb(const struct dmi_system_id *dmi_entry)
+{
+ dmi_data = dmi_entry->driver_data;
+
+ if (dmi_data && dmi_data->skip_pwm)
+ pr_info("Disabling pwm2 due to hardware constraints\n");
+
+ return 1;
+}
+
+/*
+ * 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
+ * the PWM2 duty cycle, so we disable it.
+ * I use the board name string as the trigger in case
+ * the same board is ever used in other systems.
+ */
+static struct it87_dmi_data nvidia_fn68pt = {
+ .skip_pwm = BIT(1),
+};
+
+#define IT87_DMI_MATCH_VND(vendor, name, cb, data) \
+ { \
+ .callback = cb, \
+ .matches = { \
+ DMI_EXACT_MATCH(DMI_BOARD_VENDOR, vendor), \
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, name), \
+ }, \
+ .driver_data = data, \
+ }
+
+static const struct dmi_system_id it87_dmi_table[] __initconst = {
+ IT87_DMI_MATCH_VND("nVIDIA", "FN68PT", it87_dmi_cb, &nvidia_fn68pt),
+ { }
+
+};
+MODULE_DEVICE_TABLE(dmi, it87_dmi_table);
+
static int __init sm_it87_init(void)
{
int sioaddr[2] = { REG_2E, REG_4E };
@@ -3206,10 +3724,12 @@ static int __init sm_it87_init(void)
if (err)
return err;
+ dmi_check_system(it87_dmi_table);
+
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;
/*
@@ -3257,11 +3777,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);