Commit 8cb68bdf authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging

Pull hwmon subsystem update from Jean Delvare:
 "There are many improvements to the it87 driver, as well as suspend
  support for the Winbond Super-I/O chips, and a few other fixes."

* 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
  hwmon-vid: Add support for AMD family 11h to 15h processors
  hwmon: (it87) Support PECI for additional chips
  hwmon: (it87) Report thermal sensor type as Intel PECI if appropriate
  hwmon: (it87) Manage device specific features with table
  hwmon: (it87) Replace pwm group macro with direct attribute definitions
  hwmon: (it87) Avoid quoted string splits across lines
  hwmon: (it87) Save fan registers in 2-dimensional array
  hwmon: (it87) Introduce support for tempX_offset sysfs attribute
  hwmon: (it87) Replace macro defining tempX_type sensors with direct definitions
  hwmon: (it87) Save voltage register values in 2-dimensional array
  hwmon: (it87) Save temperature registers in 2-dimensional array
  hwmon: (w83627ehf) Get rid of smatch warnings
  hwmon: (w83627hf) Don't touch nonexistent I2C address registers
  hwmon: (w83627ehf) Add support for suspend
  hwmon: (w83627hf) Add support for suspend
  hwmon: Fix PCI device reference leak in quirk
parents b6b19f25 c8ecd27d
...@@ -209,3 +209,13 @@ doesn't use CPU cycles. ...@@ -209,3 +209,13 @@ doesn't use CPU cycles.
Trip points must be set properly before switching to automatic fan speed Trip points must be set properly before switching to automatic fan speed
control mode. The driver will perform basic integrity checks before control mode. The driver will perform basic integrity checks before
actually switching to automatic control mode. actually switching to automatic control mode.
Temperature offset attributes
-----------------------------
The driver supports temp[1-3]_offset sysfs attributes to adjust the reported
temperature for thermal diodes or diode-connected thermal transistors.
If a temperature sensor is configured for thermistors, the attribute values
are ignored. If the thermal sensor type is Intel PECI, the temperature offset
must be programmed to the critical CPU temperature.
...@@ -115,6 +115,12 @@ int vid_from_reg(int val, u8 vrm) ...@@ -115,6 +115,12 @@ int vid_from_reg(int val, u8 vrm)
return (val < 32) ? 1550 - 25 * val return (val < 32) ? 1550 - 25 * val
: 775 - (25 * (val - 31)) / 2; : 775 - (25 * (val - 31)) / 2;
case 26: /* AMD family 10h to 15h, serial VID */
val &= 0x7f;
if (val >= 0x7c)
return 0;
return DIV_ROUND_CLOSEST(15500 - 125 * val, 10);
case 91: /* VRM 9.1 */ case 91: /* VRM 9.1 */
case 90: /* VRM 9.0 */ case 90: /* VRM 9.0 */
val &= 0x1f; val &= 0x1f;
...@@ -195,6 +201,10 @@ static struct vrm_model vrm_models[] = { ...@@ -195,6 +201,10 @@ static struct vrm_model vrm_models[] = {
{X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24}, /* NPT family 0Fh */ {X86_VENDOR_AMD, 0xF, 0x40, 0x7F, ANY, 24}, /* NPT family 0Fh */
{X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25}, /* future fam. 0Fh */ {X86_VENDOR_AMD, 0xF, 0x80, ANY, ANY, 25}, /* future fam. 0Fh */
{X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25}, /* NPT family 10h */ {X86_VENDOR_AMD, 0x10, 0x0, ANY, ANY, 25}, /* NPT family 10h */
{X86_VENDOR_AMD, 0x11, 0x0, ANY, ANY, 26}, /* family 11h */
{X86_VENDOR_AMD, 0x12, 0x0, ANY, ANY, 26}, /* family 12h */
{X86_VENDOR_AMD, 0x14, 0x0, ANY, ANY, 26}, /* family 14h */
{X86_VENDOR_AMD, 0x15, 0x0, ANY, ANY, 26}, /* family 15h */
{X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82}, /* Pentium Pro, {X86_VENDOR_INTEL, 0x6, 0x0, 0x6, ANY, 82}, /* Pentium Pro,
* Pentium II, Xeon, * Pentium II, Xeon,
......
...@@ -84,19 +84,21 @@ static void __init hwmon_pci_quirks(void) ...@@ -84,19 +84,21 @@ static void __init hwmon_pci_quirks(void)
/* Open access to 0x295-0x296 on MSI MS-7031 */ /* Open access to 0x295-0x296 on MSI MS-7031 */
sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
if (sb && if (sb) {
(sb->subsystem_vendor == 0x1462 && /* MSI */ if (sb->subsystem_vendor == 0x1462 && /* MSI */
sb->subsystem_device == 0x0031)) { /* MS-7031 */ sb->subsystem_device == 0x0031) { /* MS-7031 */
pci_read_config_byte(sb, 0x48, &enable);
pci_read_config_byte(sb, 0x48, &enable); pci_read_config_word(sb, 0x64, &base);
pci_read_config_word(sb, 0x64, &base);
if (base == 0 && !(enable & BIT(2))) {
if (base == 0 && !(enable & BIT(2))) { dev_info(&sb->dev,
dev_info(&sb->dev, "Opening wide generic port at 0x295\n");
"Opening wide generic port at 0x295\n"); pci_write_config_word(sb, 0x64, 0x295);
pci_write_config_word(sb, 0x64, 0x295); pci_write_config_byte(sb, 0x48,
pci_write_config_byte(sb, 0x48, enable | BIT(2)); enable | BIT(2));
}
} }
pci_dev_put(sb);
} }
#endif #endif
} }
......
...@@ -203,6 +203,8 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 }; ...@@ -203,6 +203,8 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 }; static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86 };
static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 }; static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83 };
static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
#define IT87_REG_FAN_MAIN_CTRL 0x13 #define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14 #define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr)) #define IT87_REG_PWM(nr) (0x15 + (nr))
...@@ -226,6 +228,83 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 }; ...@@ -226,6 +228,83 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i)) #define IT87_REG_AUTO_TEMP(nr, i) (0x60 + (nr) * 8 + (i))
#define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i)) #define IT87_REG_AUTO_PWM(nr, i) (0x65 + (nr) * 8 + (i))
struct it87_devices {
const char *name;
u16 features;
u8 peci_mask;
u8 old_peci_mask;
};
#define FEAT_12MV_ADC (1 << 0)
#define FEAT_NEWER_AUTOPWM (1 << 1)
#define FEAT_OLD_AUTOPWM (1 << 2)
#define FEAT_16BIT_FANS (1 << 3)
#define FEAT_TEMP_OFFSET (1 << 4)
#define FEAT_TEMP_PECI (1 << 5)
#define FEAT_TEMP_OLD_PECI (1 << 6)
static const struct it87_devices it87_devices[] = {
[it87] = {
.name = "it87",
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
},
[it8712] = {
.name = "it8712",
.features = FEAT_OLD_AUTOPWM, /* may need to overwrite */
},
[it8716] = {
.name = "it8716",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET,
},
[it8718] = {
.name = "it8718",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI,
.old_peci_mask = 0x4,
},
[it8720] = {
.name = "it8720",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI,
.old_peci_mask = 0x4,
},
[it8721] = {
.name = "it8721",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
[it8728] = {
.name = "it8728",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
.peci_mask = 0x07,
},
[it8782] = {
.name = "it8782",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
.features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
| FEAT_TEMP_OLD_PECI,
.old_peci_mask = 0x4,
},
};
#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
#define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC)
#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM)
#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM)
#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET)
#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \
((data)->peci_mask & (1 << nr)))
#define has_temp_old_peci(data, nr) \
(((data)->features & FEAT_TEMP_OLD_PECI) && \
((data)->old_peci_mask & (1 << nr)))
struct it87_sio_data { struct it87_sio_data {
enum chips type; enum chips type;
...@@ -249,7 +328,9 @@ struct it87_sio_data { ...@@ -249,7 +328,9 @@ struct it87_sio_data {
struct it87_data { struct it87_data {
struct device *hwmon_dev; struct device *hwmon_dev;
enum chips type; enum chips type;
u8 revision; u16 features;
u8 peci_mask;
u8 old_peci_mask;
unsigned short addr; unsigned short addr;
const char *name; const char *name;
...@@ -258,17 +339,13 @@ struct it87_data { ...@@ -258,17 +339,13 @@ 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]; /* Register value */ u8 in[9][3]; /* [nr][0]=in, [1]=min, [2]=max */
u8 in_max[8]; /* Register value */
u8 in_min[8]; /* Register value */
u8 has_fan; /* Bitfield, fans enabled */ u8 has_fan; /* Bitfield, fans enabled */
u16 fan[5]; /* Register values, possibly combined */ u16 fan[5][2]; /* Register values, [nr][0]=fan, [1]=min */
u16 fan_min[5]; /* Register values, possibly combined */
u8 has_temp; /* Bitfield, temp sensors enabled */ u8 has_temp; /* Bitfield, temp sensors enabled */
s8 temp[3]; /* Register value */ s8 temp[3][4]; /* [nr][0]=temp, [1]=min, [2]=max, [3]=offset */
s8 temp_high[3]; /* Register value */ u8 sensor; /* Register value (IT87_REG_TEMP_ENABLE) */
s8 temp_low[3]; /* Register value */ u8 extra; /* Register value (IT87_REG_TEMP_EXTRA) */
u8 sensor; /* Register value */
u8 fan_div[3]; /* Register encoding, shifted right */ u8 fan_div[3]; /* Register encoding, shifted right */
u8 vid; /* Register encoding, combined */ u8 vid; /* Register encoding, combined */
u8 vrm; u8 vrm;
...@@ -296,26 +373,6 @@ struct it87_data { ...@@ -296,26 +373,6 @@ struct it87_data {
s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */ s8 auto_temp[3][5]; /* [nr][0] is point1_temp_hyst */
}; };
static inline int has_12mv_adc(const struct it87_data *data)
{
/*
* IT8721F and later have a 12 mV ADC, also with internal scaling
* on selected inputs.
*/
return data->type == it8721
|| data->type == it8728;
}
static inline int has_newer_autopwm(const struct it87_data *data)
{
/*
* IT8721F and later have separate registers for the temperature
* mapping and the manual duty cycle.
*/
return data->type == it8721
|| data->type == it8728;
}
static int adc_lsb(const struct it87_data *data, int nr) static int adc_lsb(const struct it87_data *data, int nr)
{ {
int lsb = has_12mv_adc(data) ? 12 : 16; int lsb = has_12mv_adc(data) ? 12 : 16;
...@@ -398,35 +455,6 @@ static const unsigned int pwm_freq[8] = { ...@@ -398,35 +455,6 @@ static const unsigned int pwm_freq[8] = {
750000 / 128, 750000 / 128,
}; };
static inline int has_16bit_fans(const struct it87_data *data)
{
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
* These are the first revisions with 16-bit tachometer support.
*/
return (data->type == it87 && data->revision >= 0x03)
|| (data->type == it8712 && data->revision >= 0x08)
|| data->type == it8716
|| data->type == it8718
|| data->type == it8720
|| data->type == it8721
|| data->type == it8728
|| data->type == it8782
|| data->type == it8783;
}
static inline int has_old_autopwm(const struct it87_data *data)
{
/*
* The old automatic fan speed control interface is implemented
* by IT8705F chips up to revision F and IT8712F chips up to
* revision G.
*/
return (data->type == it87 && data->revision < 0x03)
|| (data->type == it8712 && data->revision < 0x08);
}
static int it87_probe(struct platform_device *pdev); static int it87_probe(struct platform_device *pdev);
static int it87_remove(struct platform_device *pdev); static int it87_remove(struct platform_device *pdev);
...@@ -447,59 +475,22 @@ static struct platform_driver it87_driver = { ...@@ -447,59 +475,22 @@ static struct platform_driver it87_driver = {
}; };
static ssize_t show_in(struct device *dev, struct device_attribute *attr, static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf) 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);
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr]));
}
static ssize_t show_in_min(struct device *dev, struct device_attribute *attr,
char *buf)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
struct it87_data *data = it87_update_device(dev); struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_min[nr])); return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in[nr][index]));
} }
static ssize_t show_in_max(struct device *dev, struct device_attribute *attr, static ssize_t set_in(struct device *dev, struct device_attribute *attr,
char *buf) const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", in_from_reg(data, nr, data->in_max[nr]));
}
static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev);
unsigned long val;
if (kstrtoul(buf, 10, &val) < 0)
return -EINVAL;
mutex_lock(&data->update_lock);
data->in_min[nr] = in_to_reg(data, nr, val);
it87_write_value(data, IT87_REG_VIN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
struct it87_data *data = dev_get_drvdata(dev); struct it87_data *data = dev_get_drvdata(dev);
unsigned long val; unsigned long val;
...@@ -508,140 +499,167 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, ...@@ -508,140 +499,167 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->in_max[nr] = in_to_reg(data, nr, val); data->in[nr][index] = in_to_reg(data, nr, val);
it87_write_value(data, IT87_REG_VIN_MAX(nr), it87_write_value(data,
data->in_max[nr]); index == 1 ? IT87_REG_VIN_MIN(nr)
: IT87_REG_VIN_MAX(nr),
data->in[nr][index]);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
} }
#define show_in_offset(offset) \ static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
show_in, NULL, offset); 0, 1);
static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
#define limit_in_offset(offset) \ 0, 2);
static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
show_in_min, set_in_min, offset); \ static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_max, set_in_max, offset); 1, 1);
static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(0); 1, 2);
limit_in_offset(0);
show_in_offset(1); static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
limit_in_offset(1); static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(2); 2, 1);
limit_in_offset(2); static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(3); 2, 2);
limit_in_offset(3);
show_in_offset(4); static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
limit_in_offset(4); static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(5); 3, 1);
limit_in_offset(5); static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(6); 3, 2);
limit_in_offset(6);
show_in_offset(7); static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
limit_in_offset(7); static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
show_in_offset(8); 4, 1);
static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
4, 2);
static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, 0);
static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
5, 1);
static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
5, 2);
static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in, NULL, 6, 0);
static SENSOR_DEVICE_ATTR_2(in6_min, S_IRUGO | S_IWUSR, show_in, set_in,
6, 1);
static SENSOR_DEVICE_ATTR_2(in6_max, S_IRUGO | S_IWUSR, show_in, set_in,
6, 2);
static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in, NULL, 7, 0);
static SENSOR_DEVICE_ATTR_2(in7_min, S_IRUGO | S_IWUSR, show_in, set_in,
7, 1);
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);
/* 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,
char *buf) char *buf)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
struct it87_data *data = it87_update_device(dev); struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr]));
}
static ssize_t show_temp_max(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); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr][index]));
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr]));
} }
static ssize_t show_temp_min(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); static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])); const char *buf, size_t count)
}
static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
struct it87_data *data = dev_get_drvdata(dev); struct it87_data *data = dev_get_drvdata(dev);
long val; long val;
u8 reg, regval;
if (kstrtol(buf, 10, &val) < 0) if (kstrtol(buf, 10, &val) < 0)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->temp_high[nr] = TEMP_TO_REG(val);
it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev); switch (index) {
long val; default:
case 1:
if (kstrtol(buf, 10, &val) < 0) reg = IT87_REG_TEMP_LOW(nr);
return -EINVAL; break;
case 2:
reg = IT87_REG_TEMP_HIGH(nr);
break;
case 3:
regval = it87_read_value(data, IT87_REG_BEEP_ENABLE);
if (!(regval & 0x80)) {
regval |= 0x80;
it87_write_value(data, IT87_REG_BEEP_ENABLE, regval);
}
data->valid = 0;
reg = IT87_REG_TEMP_OFFSET[nr];
break;
}
mutex_lock(&data->update_lock); data->temp[nr][index] = TEMP_TO_REG(val);
data->temp_low[nr] = TEMP_TO_REG(val); it87_write_value(data, reg, data->temp[nr][index]);
it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
} }
#define show_temp_offset(offset) \
static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
show_temp, NULL, offset - 1); \ static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ 0, 1);
show_temp_max, set_temp_max, offset - 1); \ static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \ 0, 2);
show_temp_min, set_temp_min, offset - 1); static SENSOR_DEVICE_ATTR_2(temp1_offset, S_IRUGO | S_IWUSR, show_temp,
set_temp, 0, 3);
show_temp_offset(1); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, 0);
show_temp_offset(2); static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
show_temp_offset(3); 1, 1);
static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
static ssize_t show_sensor(struct device *dev, struct device_attribute *attr, 1, 2);
char *buf) static SENSOR_DEVICE_ATTR_2(temp2_offset, S_IRUGO | S_IWUSR, show_temp,
set_temp, 1, 3);
static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, 0);
static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
2, 1);
static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
2, 2);
static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
set_temp, 2, 3);
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); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index; int nr = sensor_attr->index;
struct it87_data *data = it87_update_device(dev); struct it87_data *data = it87_update_device(dev);
u8 reg = data->sensor; /* In case value is updated while used */ 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)) if (reg & (1 << nr))
return sprintf(buf, "3\n"); /* thermal diode */ return sprintf(buf, "3\n"); /* thermal diode */
if (reg & (8 << nr)) if (reg & (8 << nr))
return sprintf(buf, "4\n"); /* thermistor */ return sprintf(buf, "4\n"); /* thermistor */
return sprintf(buf, "0\n"); /* disabled */ return sprintf(buf, "0\n"); /* disabled */
} }
static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) static ssize_t set_temp_type(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index; int nr = sensor_attr->index;
struct it87_data *data = dev_get_drvdata(dev); struct it87_data *data = dev_get_drvdata(dev);
long val; long val;
u8 reg; u8 reg, extra;
if (kstrtol(buf, 10, &val) < 0) if (kstrtol(buf, 10, &val) < 0)
return -EINVAL; return -EINVAL;
...@@ -649,33 +667,45 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr, ...@@ -649,33 +667,45 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
reg = it87_read_value(data, IT87_REG_TEMP_ENABLE); reg = it87_read_value(data, IT87_REG_TEMP_ENABLE);
reg &= ~(1 << nr); reg &= ~(1 << nr);
reg &= ~(8 << nr); reg &= ~(8 << nr);
if (has_temp_peci(data, nr) && (reg >> 6 == nr + 1 || val == 6))
reg &= 0x3f;
extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
if (has_temp_old_peci(data, nr) && ((extra & 0x80) || val == 6))
extra &= 0x7f;
if (val == 2) { /* backwards compatibility */ if (val == 2) { /* backwards compatibility */
dev_warn(dev, "Sensor type 2 is deprecated, please use 4 " dev_warn(dev,
"instead\n"); "Sensor type 2 is deprecated, please use 4 instead\n");
val = 4; val = 4;
} }
/* 3 = thermal diode; 4 = thermistor; 0 = disabled */ /* 3 = thermal diode; 4 = thermistor; 6 = Intel PECI; 0 = disabled */
if (val == 3) if (val == 3)
reg |= 1 << nr; reg |= 1 << nr;
else if (val == 4) else if (val == 4)
reg |= 8 << nr; reg |= 8 << nr;
else if (has_temp_peci(data, nr) && val == 6)
reg |= (nr + 1) << 6;
else if (has_temp_old_peci(data, nr) && val == 6)
extra |= 0x80;
else if (val != 0) else if (val != 0)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
data->sensor = reg; data->sensor = reg;
data->extra = extra;
it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor); 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 */ data->valid = 0; /* Force cache refresh */
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
} }
#define show_sensor_offset(offset) \
static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \
show_sensor, set_sensor, offset - 1);
show_sensor_offset(1); static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR, show_temp_type,
show_sensor_offset(2); set_temp_type, 0);
show_sensor_offset(3); static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
set_temp_type, 1);
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
set_temp_type, 2);
/* 3 Fans */ /* 3 Fans */
...@@ -692,25 +722,21 @@ static int pwm_mode(const struct it87_data *data, int nr) ...@@ -692,25 +722,21 @@ static int pwm_mode(const struct it87_data *data, int nr)
} }
static ssize_t show_fan(struct device *dev, struct device_attribute *attr, static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
int speed;
struct it87_data *data = it87_update_device(dev); struct it87_data *data = it87_update_device(dev);
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])));
}
static ssize_t show_fan_min(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); speed = has_16bit_fans(data) ?
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], FAN16_FROM_REG(data->fan[nr][index]) :
DIV_FROM_REG(data->fan_div[nr]))); FAN_FROM_REG(data->fan[nr][index],
DIV_FROM_REG(data->fan_div[nr]));
return sprintf(buf, "%d\n", speed);
} }
static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr, static ssize_t show_fan_div(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -747,11 +773,13 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr, ...@@ -747,11 +773,13 @@ static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", pwm_freq[index]); return sprintf(buf, "%u\n", pwm_freq[index]);
} }
static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{ {
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
int nr = sensor_attr->index; int nr = sattr->nr;
int index = sattr->index;
struct it87_data *data = dev_get_drvdata(dev); struct it87_data *data = dev_get_drvdata(dev);
long val; long val;
...@@ -761,24 +789,36 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr, ...@@ -761,24 +789,36 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
reg = it87_read_value(data, IT87_REG_FAN_DIV);
switch (nr) { if (has_16bit_fans(data)) {
case 0: data->fan[nr][index] = FAN16_TO_REG(val);
data->fan_div[nr] = reg & 0x07; it87_write_value(data, IT87_REG_FAN_MIN[nr],
break; data->fan[nr][index] & 0xff);
case 1: it87_write_value(data, IT87_REG_FANX_MIN[nr],
data->fan_div[nr] = (reg >> 3) & 0x07; data->fan[nr][index] >> 8);
break; } else {
case 2: reg = it87_read_value(data, IT87_REG_FAN_DIV);
data->fan_div[nr] = (reg & 0x40) ? 3 : 1; switch (nr) {
break; case 0:
data->fan_div[nr] = reg & 0x07;
break;
case 1:
data->fan_div[nr] = (reg >> 3) & 0x07;
break;
case 2:
data->fan_div[nr] = (reg & 0x40) ? 3 : 1;
break;
}
data->fan[nr][index] =
FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
it87_write_value(data, IT87_REG_FAN_MIN[nr],
data->fan[nr][index]);
} }
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan_min[nr]);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
} }
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
...@@ -797,7 +837,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, ...@@ -797,7 +837,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
old = it87_read_value(data, IT87_REG_FAN_DIV); old = it87_read_value(data, IT87_REG_FAN_DIV);
/* Save fan min limit */ /* Save fan min limit */
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])); min = FAN_FROM_REG(data->fan[nr][1], DIV_FROM_REG(data->fan_div[nr]));
switch (nr) { switch (nr) {
case 0: case 0:
...@@ -818,8 +858,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, ...@@ -818,8 +858,8 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
it87_write_value(data, IT87_REG_FAN_DIV, val); it87_write_value(data, IT87_REG_FAN_DIV, val);
/* Restore fan min limit */ /* Restore fan min limit */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 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_min[nr]); it87_write_value(data, IT87_REG_FAN_MIN[nr], data->fan[nr][1]);
mutex_unlock(&data->update_lock); mutex_unlock(&data->update_lock);
return count; return count;
...@@ -843,8 +883,8 @@ static int check_trip_points(struct device *dev, int nr) ...@@ -843,8 +883,8 @@ static int check_trip_points(struct device *dev, int nr)
} }
if (err) { if (err) {
dev_err(dev, "Inconsistent trip points, not switching to " dev_err(dev,
"automatic mode\n"); "Inconsistent trip points, not switching to automatic mode\n");
dev_err(dev, "Adjust the trip points and try again\n"); dev_err(dev, "Adjust the trip points and try again\n");
} }
return err; return err;
...@@ -1092,118 +1132,106 @@ static ssize_t set_auto_temp(struct device *dev, ...@@ -1092,118 +1132,106 @@ static ssize_t set_auto_temp(struct device *dev,
return count; return count;
} }
#define show_fan_offset(offset) \ static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, 0);
static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
show_fan, NULL, offset - 1); \ 0, 1);
static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div,
show_fan_min, set_fan_min, offset - 1); \ set_fan_div, 0);
static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
show_fan_div, set_fan_div, offset - 1); static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, 0);
static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
show_fan_offset(1); 1, 1);
show_fan_offset(2); static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, show_fan_div,
show_fan_offset(3); set_fan_div, 1);
#define show_pwm_offset(offset) \ static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, 0);
static SENSOR_DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR, \ static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
show_pwm_enable, set_pwm_enable, offset - 1); \ 2, 1);
static SENSOR_DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO | S_IWUSR, show_fan_div,
show_pwm, set_pwm, offset - 1); \ set_fan_div, 2);
static DEVICE_ATTR(pwm##offset##_freq, \
(offset == 1 ? S_IRUGO | S_IWUSR : S_IRUGO), \ static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, 0);
show_pwm_freq, (offset == 1 ? set_pwm_freq : NULL)); \ static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
static SENSOR_DEVICE_ATTR(pwm##offset##_auto_channels_temp, \ 3, 1);
S_IRUGO | S_IWUSR, show_pwm_temp_map, set_pwm_temp_map, \
offset - 1); \ static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, 0);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_pwm, \ static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ 4, 1);
offset - 1, 0); \
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_pwm, \ static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ show_pwm_enable, set_pwm_enable, 0);
offset - 1, 1); \ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 0);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_pwm, \ static DEVICE_ATTR(pwm1_freq, S_IRUGO | S_IWUSR, show_pwm_freq, set_pwm_freq);
S_IRUGO | S_IWUSR, show_auto_pwm, set_auto_pwm, \ static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO | S_IWUSR,
offset - 1, 2); \ show_pwm_temp_map, set_pwm_temp_map, 0);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_pwm, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO | S_IWUSR,
S_IRUGO, show_auto_pwm, NULL, offset - 1, 3); \ show_auto_pwm, set_auto_pwm, 0, 0);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_pwm, S_IRUGO | S_IWUSR,
S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ show_auto_pwm, set_auto_pwm, 0, 1);
offset - 1, 1); \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_pwm, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point1_temp_hyst, \ show_auto_pwm, set_auto_pwm, 0, 2);
S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_pwm, S_IRUGO,
offset - 1, 0); \ show_auto_pwm, NULL, 0, 3);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point2_temp, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ show_auto_temp, set_auto_temp, 0, 1);
offset - 1, 2); \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point3_temp, \ show_auto_temp, set_auto_temp, 0, 0);
S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
offset - 1, 3); \ show_auto_temp, set_auto_temp, 0, 2);
static SENSOR_DEVICE_ATTR_2(pwm##offset##_auto_point4_temp, \ static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
S_IRUGO | S_IWUSR, show_auto_temp, set_auto_temp, \ show_auto_temp, set_auto_temp, 0, 3);
offset - 1, 4); static SENSOR_DEVICE_ATTR_2(pwm1_auto_point4_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 0, 4);
show_pwm_offset(1);
show_pwm_offset(2); static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR,
show_pwm_offset(3); show_pwm_enable, set_pwm_enable, 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 1);
/* A different set of callbacks for 16-bit fans */ static DEVICE_ATTR(pwm2_freq, S_IRUGO, show_pwm_freq, NULL);
static ssize_t show_fan16(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IRUGO | S_IWUSR,
char *buf) show_pwm_temp_map, set_pwm_temp_map, 1);
{ static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_pwm, S_IRUGO | S_IWUSR,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); show_auto_pwm, set_auto_pwm, 1, 0);
int nr = sensor_attr->index; static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_pwm, S_IRUGO | S_IWUSR,
struct it87_data *data = it87_update_device(dev); show_auto_pwm, set_auto_pwm, 1, 1);
return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr])); static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_pwm, S_IRUGO | S_IWUSR,
} show_auto_pwm, set_auto_pwm, 1, 2);
static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_pwm, S_IRUGO,
static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr, show_auto_pwm, NULL, 1, 3);
char *buf) static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
{ show_auto_temp, set_auto_temp, 1, 1);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
int nr = sensor_attr->index; show_auto_temp, set_auto_temp, 1, 0);
struct it87_data *data = it87_update_device(dev); static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr])); show_auto_temp, set_auto_temp, 1, 2);
} static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 1, 3);
static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR_2(pwm2_auto_point4_temp, S_IRUGO | S_IWUSR,
const char *buf, size_t count) show_auto_temp, set_auto_temp, 1, 4);
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR,
int nr = sensor_attr->index; show_pwm_enable, set_pwm_enable, 2);
struct it87_data *data = dev_get_drvdata(dev); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, set_pwm, 2);
long val; static DEVICE_ATTR(pwm3_freq, S_IRUGO, show_pwm_freq, NULL);
static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IRUGO | S_IWUSR,
if (kstrtol(buf, 10, &val) < 0) show_pwm_temp_map, set_pwm_temp_map, 2);
return -EINVAL; static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO | S_IWUSR,
show_auto_pwm, set_auto_pwm, 2, 0);
mutex_lock(&data->update_lock); static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR,
data->fan_min[nr] = FAN16_TO_REG(val); show_auto_pwm, set_auto_pwm, 2, 1);
it87_write_value(data, IT87_REG_FAN_MIN[nr], static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_pwm, S_IRUGO | S_IWUSR,
data->fan_min[nr] & 0xff); show_auto_pwm, set_auto_pwm, 2, 2);
it87_write_value(data, IT87_REG_FANX_MIN[nr], static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_pwm, S_IRUGO,
data->fan_min[nr] >> 8); show_auto_pwm, NULL, 2, 3);
mutex_unlock(&data->update_lock); static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
return count; show_auto_temp, set_auto_temp, 2, 1);
} static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp_hyst, S_IRUGO | S_IWUSR,
show_auto_temp, set_auto_temp, 2, 0);
/* static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
* We want to use the same sysfs file names as 8-bit fans, but we need show_auto_temp, set_auto_temp, 2, 2);
* different variable names, so we have to use SENSOR_ATTR instead of static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
* SENSOR_DEVICE_ATTR. show_auto_temp, set_auto_temp, 2, 3);
*/ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point4_temp, S_IRUGO | S_IWUSR,
#define show_fan16_offset(offset) \ show_auto_temp, set_auto_temp, 2, 4);
static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
= SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
show_fan16, NULL, offset - 1); \
static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
= SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
show_fan16_min, set_fan16_min, offset - 1)
show_fan16_offset(1);
show_fan16_offset(2);
show_fan16_offset(3);
show_fan16_offset(4);
show_fan16_offset(5);
/* Alarms */ /* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
...@@ -1471,6 +1499,12 @@ static const struct attribute_group it87_group_temp[3] = { ...@@ -1471,6 +1499,12 @@ static const struct attribute_group it87_group_temp[3] = {
{ .attrs = it87_attributes_temp[2] }, { .attrs = it87_attributes_temp[2] },
}; };
static struct attribute *it87_attributes_temp_offset[] = {
&sensor_dev_attr_temp1_offset.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
};
static struct attribute *it87_attributes[] = { static struct attribute *it87_attributes[] = {
&dev_attr_alarms.attr, &dev_attr_alarms.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr, &sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
...@@ -1500,73 +1534,47 @@ static struct attribute *it87_attributes_temp_beep[] = { ...@@ -1500,73 +1534,47 @@ static struct attribute *it87_attributes_temp_beep[] = {
&sensor_dev_attr_temp3_beep.dev_attr.attr, &sensor_dev_attr_temp3_beep.dev_attr.attr,
}; };
static struct attribute *it87_attributes_fan16[5][3+1] = { { static struct attribute *it87_attributes_fan[5][3+1] = { {
&sensor_dev_attr_fan1_input16.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min16.dev_attr.attr, &sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr, &sensor_dev_attr_fan1_alarm.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_fan2_input16.dev_attr.attr, &sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min16.dev_attr.attr, &sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr, &sensor_dev_attr_fan2_alarm.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_fan3_input16.dev_attr.attr, &sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min16.dev_attr.attr, &sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr, &sensor_dev_attr_fan3_alarm.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_fan4_input16.dev_attr.attr, &sensor_dev_attr_fan4_input.dev_attr.attr,
&sensor_dev_attr_fan4_min16.dev_attr.attr, &sensor_dev_attr_fan4_min.dev_attr.attr,
&sensor_dev_attr_fan4_alarm.dev_attr.attr, &sensor_dev_attr_fan4_alarm.dev_attr.attr,
NULL NULL
}, { }, {
&sensor_dev_attr_fan5_input16.dev_attr.attr, &sensor_dev_attr_fan5_input.dev_attr.attr,
&sensor_dev_attr_fan5_min16.dev_attr.attr, &sensor_dev_attr_fan5_min.dev_attr.attr,
&sensor_dev_attr_fan5_alarm.dev_attr.attr, &sensor_dev_attr_fan5_alarm.dev_attr.attr,
NULL NULL
} }; } };
static const struct attribute_group it87_group_fan16[5] = { static const struct attribute_group it87_group_fan[5] = {
{ .attrs = it87_attributes_fan16[0] }, { .attrs = it87_attributes_fan[0] },
{ .attrs = it87_attributes_fan16[1] }, { .attrs = it87_attributes_fan[1] },
{ .attrs = it87_attributes_fan16[2] }, { .attrs = it87_attributes_fan[2] },
{ .attrs = it87_attributes_fan16[3] }, { .attrs = it87_attributes_fan[3] },
{ .attrs = it87_attributes_fan16[4] }, { .attrs = it87_attributes_fan[4] },
}; };
static struct attribute *it87_attributes_fan[3][4+1] = { { static const struct attribute *it87_attributes_fan_div[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
&sensor_dev_attr_fan1_min.dev_attr.attr,
&sensor_dev_attr_fan1_div.dev_attr.attr, &sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan1_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan2_input.dev_attr.attr,
&sensor_dev_attr_fan2_min.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr, &sensor_dev_attr_fan2_div.dev_attr.attr,
&sensor_dev_attr_fan2_alarm.dev_attr.attr,
NULL
}, {
&sensor_dev_attr_fan3_input.dev_attr.attr,
&sensor_dev_attr_fan3_min.dev_attr.attr,
&sensor_dev_attr_fan3_div.dev_attr.attr, &sensor_dev_attr_fan3_div.dev_attr.attr,
&sensor_dev_attr_fan3_alarm.dev_attr.attr,
NULL
} };
static const struct attribute_group it87_group_fan[3] = {
{ .attrs = it87_attributes_fan[0] },
{ .attrs = it87_attributes_fan[1] },
{ .attrs = it87_attributes_fan[2] },
}; };
static const struct attribute_group *
it87_get_fan_group(const struct it87_data *data)
{
return has_16bit_fans(data) ? it87_group_fan16 : it87_group_fan;
}
static struct attribute *it87_attributes_pwm[3][4+1] = { { static struct attribute *it87_attributes_pwm[3][4+1] = { {
&sensor_dev_attr_pwm1_enable.dev_attr.attr, &sensor_dev_attr_pwm1_enable.dev_attr.attr,
&sensor_dev_attr_pwm1.dev_attr.attr, &sensor_dev_attr_pwm1.dev_attr.attr,
...@@ -1925,7 +1933,6 @@ static void it87_remove_files(struct device *dev) ...@@ -1925,7 +1933,6 @@ static void it87_remove_files(struct device *dev)
{ {
struct it87_data *data = platform_get_drvdata(pdev); struct it87_data *data = platform_get_drvdata(pdev);
struct it87_sio_data *sio_data = dev->platform_data; struct it87_sio_data *sio_data = dev->platform_data;
const struct attribute_group *fan_group = it87_get_fan_group(data);
int i; int i;
sysfs_remove_group(&dev->kobj, &it87_group); sysfs_remove_group(&dev->kobj, &it87_group);
...@@ -1941,6 +1948,9 @@ static void it87_remove_files(struct device *dev) ...@@ -1941,6 +1948,9 @@ static void it87_remove_files(struct device *dev)
if (!(data->has_temp & (1 << i))) if (!(data->has_temp & (1 << i)))
continue; continue;
sysfs_remove_group(&dev->kobj, &it87_group_temp[i]); sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
if (has_temp_offset(data))
sysfs_remove_file(&dev->kobj,
it87_attributes_temp_offset[i]);
if (sio_data->beep_pin) if (sio_data->beep_pin)
sysfs_remove_file(&dev->kobj, sysfs_remove_file(&dev->kobj,
it87_attributes_temp_beep[i]); it87_attributes_temp_beep[i]);
...@@ -1948,10 +1958,13 @@ static void it87_remove_files(struct device *dev) ...@@ -1948,10 +1958,13 @@ static void it87_remove_files(struct device *dev)
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
if (!(data->has_fan & (1 << i))) if (!(data->has_fan & (1 << i)))
continue; continue;
sysfs_remove_group(&dev->kobj, &fan_group[i]); sysfs_remove_group(&dev->kobj, &it87_group_fan[i]);
if (sio_data->beep_pin) if (sio_data->beep_pin)
sysfs_remove_file(&dev->kobj, sysfs_remove_file(&dev->kobj,
it87_attributes_fan_beep[i]); it87_attributes_fan_beep[i]);
if (i < 3 && !has_16bit_fans(data))
sysfs_remove_file(&dev->kobj,
it87_attributes_fan_div[i]);
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (sio_data->skip_pwm & (1 << 0)) if (sio_data->skip_pwm & (1 << 0))
...@@ -1972,21 +1985,9 @@ static int it87_probe(struct platform_device *pdev) ...@@ -1972,21 +1985,9 @@ static int it87_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev->platform_data; struct it87_sio_data *sio_data = dev->platform_data;
const struct attribute_group *fan_group;
int err = 0, i; int err = 0, i;
int enable_pwm_interface; int enable_pwm_interface;
int fan_beep_need_rw; int fan_beep_need_rw;
static const char * const names[] = {
"it87",
"it8712",
"it8716",
"it8718",
"it8720",
"it8721",
"it8728",
"it8782",
"it8783",
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0); res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT, if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
...@@ -2003,8 +2004,31 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2003,8 +2004,31 @@ static int it87_probe(struct platform_device *pdev)
data->addr = res->start; data->addr = res->start;
data->type = sio_data->type; data->type = sio_data->type;
data->revision = sio_data->revision; data->features = it87_devices[sio_data->type].features;
data->name = names[sio_data->type]; data->peci_mask = it87_devices[sio_data->type].peci_mask;
data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
data->name = it87_devices[sio_data->type].name;
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
* These are the first revisions with 16-bit tachometer support.
*/
switch (data->type) {
case it87:
if (sio_data->revision >= 0x03) {
data->features &= ~FEAT_OLD_AUTOPWM;
data->features |= FEAT_16BIT_FANS;
}
break;
case it8712:
if (sio_data->revision >= 0x08) {
data->features &= ~FEAT_OLD_AUTOPWM;
data->features |= FEAT_16BIT_FANS;
}
break;
default:
break;
}
/* Now, we do the remaining detection. */ /* Now, we do the remaining detection. */
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80) if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
...@@ -2068,6 +2092,12 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2068,6 +2092,12 @@ static int it87_probe(struct platform_device *pdev)
err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]); err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
if (err) if (err)
goto error; goto error;
if (has_temp_offset(data)) {
err = sysfs_create_file(&dev->kobj,
it87_attributes_temp_offset[i]);
if (err)
goto error;
}
if (sio_data->beep_pin) { if (sio_data->beep_pin) {
err = sysfs_create_file(&dev->kobj, err = sysfs_create_file(&dev->kobj,
it87_attributes_temp_beep[i]); it87_attributes_temp_beep[i]);
...@@ -2077,15 +2107,21 @@ static int it87_probe(struct platform_device *pdev) ...@@ -2077,15 +2107,21 @@ static int it87_probe(struct platform_device *pdev)
} }
/* Do not create fan files for disabled fans */ /* Do not create fan files for disabled fans */
fan_group = it87_get_fan_group(data);
fan_beep_need_rw = 1; fan_beep_need_rw = 1;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
if (!(data->has_fan & (1 << i))) if (!(data->has_fan & (1 << i)))
continue; continue;
err = sysfs_create_group(&dev->kobj, &fan_group[i]); err = sysfs_create_group(&dev->kobj, &it87_group_fan[i]);
if (err) if (err)
goto error; goto error;
if (i < 3 && !has_16bit_fans(data)) {
err = sysfs_create_file(&dev->kobj,
it87_attributes_fan_div[i]);
if (err)
goto error;
}
if (sio_data->beep_pin) { if (sio_data->beep_pin) {
err = sysfs_create_file(&dev->kobj, err = sysfs_create_file(&dev->kobj,
it87_attributes_fan_beep[i]); it87_attributes_fan_beep[i]);
...@@ -2221,8 +2257,8 @@ static int it87_check_pwm(struct device *dev) ...@@ -2221,8 +2257,8 @@ static int it87_check_pwm(struct device *dev)
* PWM interface). * PWM interface).
*/ */
if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) { if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
dev_info(dev, "Reconfiguring PWM to " dev_info(dev,
"active high polarity\n"); "Reconfiguring PWM to active high polarity\n");
it87_write_value(data, IT87_REG_FAN_CTL, it87_write_value(data, IT87_REG_FAN_CTL,
tmp | 0x87); tmp | 0x87);
for (i = 0; i < 3; i++) for (i = 0; i < 3; i++)
...@@ -2232,16 +2268,16 @@ static int it87_check_pwm(struct device *dev) ...@@ -2232,16 +2268,16 @@ static int it87_check_pwm(struct device *dev)
return 1; return 1;
} }
dev_info(dev, "PWM configuration is " dev_info(dev,
"too broken to be fixed\n"); "PWM configuration is too broken to be fixed\n");
} }
dev_info(dev, "Detected broken BIOS " dev_info(dev,
"defaults, disabling PWM interface\n"); "Detected broken BIOS defaults, disabling PWM interface\n");
return 0; return 0;
} else if (fix_pwm_polarity) { } else if (fix_pwm_polarity) {
dev_info(dev, "PWM configuration looks " dev_info(dev,
"sane, won't touch\n"); "PWM configuration looks sane, won't touch\n");
} }
return 1; return 1;
...@@ -2389,42 +2425,46 @@ static struct it87_data *it87_update_device(struct device *dev) ...@@ -2389,42 +2425,46 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(data, IT87_REG_CONFIG) | 0x40); it87_read_value(data, IT87_REG_CONFIG) | 0x40);
} }
for (i = 0; i <= 7; i++) { for (i = 0; i <= 7; i++) {
data->in[i] = data->in[i][0] =
it87_read_value(data, IT87_REG_VIN(i)); it87_read_value(data, IT87_REG_VIN(i));
data->in_min[i] = data->in[i][1] =
it87_read_value(data, IT87_REG_VIN_MIN(i)); it87_read_value(data, IT87_REG_VIN_MIN(i));
data->in_max[i] = data->in[i][2] =
it87_read_value(data, IT87_REG_VIN_MAX(i)); it87_read_value(data, IT87_REG_VIN_MAX(i));
} }
/* in8 (battery) has no limit registers */ /* in8 (battery) has no limit registers */
data->in[8] = it87_read_value(data, IT87_REG_VIN(8)); data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
/* Skip disabled fans */ /* Skip disabled fans */
if (!(data->has_fan & (1 << i))) if (!(data->has_fan & (1 << i)))
continue; continue;
data->fan_min[i] = data->fan[i][1] =
it87_read_value(data, IT87_REG_FAN_MIN[i]); it87_read_value(data, IT87_REG_FAN_MIN[i]);
data->fan[i] = it87_read_value(data, data->fan[i][0] = it87_read_value(data,
IT87_REG_FAN[i]); IT87_REG_FAN[i]);
/* Add high byte if in 16-bit mode */ /* Add high byte if in 16-bit mode */
if (has_16bit_fans(data)) { if (has_16bit_fans(data)) {
data->fan[i] |= it87_read_value(data, data->fan[i][0] |= it87_read_value(data,
IT87_REG_FANX[i]) << 8; IT87_REG_FANX[i]) << 8;
data->fan_min[i] |= it87_read_value(data, data->fan[i][1] |= it87_read_value(data,
IT87_REG_FANX_MIN[i]) << 8; IT87_REG_FANX_MIN[i]) << 8;
} }
} }
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
if (!(data->has_temp & (1 << i))) if (!(data->has_temp & (1 << i)))
continue; continue;
data->temp[i] = data->temp[i][0] =
it87_read_value(data, IT87_REG_TEMP(i)); it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] = data->temp[i][1] =
it87_read_value(data, IT87_REG_TEMP_HIGH(i));
data->temp_low[i] =
it87_read_value(data, IT87_REG_TEMP_LOW(i)); it87_read_value(data, IT87_REG_TEMP_LOW(i));
data->temp[i][2] =
it87_read_value(data, IT87_REG_TEMP_HIGH(i));
if (has_temp_offset(data))
data->temp[i][3] =
it87_read_value(data,
IT87_REG_TEMP_OFFSET[i]);
} }
/* Newer chips don't have clock dividers */ /* Newer chips don't have clock dividers */
...@@ -2448,6 +2488,7 @@ static struct it87_data *it87_update_device(struct device *dev) ...@@ -2448,6 +2488,7 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_update_pwm_ctrl(data, i); it87_update_pwm_ctrl(data, i);
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE); data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
data->extra = it87_read_value(data, IT87_REG_TEMP_EXTRA);
/* /*
* The IT8705F does not have VID capability. * The IT8705F does not have VID capability.
* The IT8718F and later don't use IT87_REG_VID for the * The IT8718F and later don't use IT87_REG_VID for the
...@@ -2549,8 +2590,7 @@ static void __exit sm_it87_exit(void) ...@@ -2549,8 +2590,7 @@ static void __exit sm_it87_exit(void)
} }
MODULE_AUTHOR("Chris Gauthron, " MODULE_AUTHOR("Chris Gauthron, Jean Delvare <khali@linux-fr.org>");
"Jean Delvare <khali@linux-fr.org>");
MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver"); MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
module_param(update_vbat, bool, 0); module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value"); MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
......
/* /*
* w83627ehf - Driver for the hardware monitoring functionality of * w83627ehf - Driver for the hardware monitoring functionality of
* the Winbond W83627EHF Super-I/O chip * the Winbond W83627EHF Super-I/O chip
* Copyright (C) 2005-2011 Jean Delvare <khali@linux-fr.org> * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org>
* Copyright (C) 2006 Yuan Mu (Winbond), * Copyright (C) 2006 Yuan Mu (Winbond),
* Rudolf Marek <r.marek@assembler.cz> * Rudolf Marek <r.marek@assembler.cz>
* David Hubbard <david.c.hubbard@gmail.com> * David Hubbard <david.c.hubbard@gmail.com>
...@@ -502,6 +502,13 @@ struct w83627ehf_data { ...@@ -502,6 +502,13 @@ struct w83627ehf_data {
u16 have_temp_offset; u16 have_temp_offset;
u8 in6_skip:1; u8 in6_skip:1;
u8 temp3_val_only:1; u8 temp3_val_only:1;
#ifdef CONFIG_PM
/* Remember extra register values over suspend/resume */
u8 vbat;
u8 fandiv1;
u8 fandiv2;
#endif
}; };
struct w83627ehf_sio_data { struct w83627ehf_sio_data {
...@@ -898,6 +905,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev) ...@@ -898,6 +905,8 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
data->temp_max_hyst[i] data->temp_max_hyst[i]
= w83627ehf_read_temp(data, = w83627ehf_read_temp(data,
data->reg_temp_hyst[i]); data->reg_temp_hyst[i]);
if (i > 2)
continue;
if (data->have_temp_offset & (1 << i)) if (data->have_temp_offset & (1 << i))
data->temp_offset[i] data->temp_offset[i]
= w83627ehf_read_value(data, = w83627ehf_read_value(data,
...@@ -2608,10 +2617,98 @@ static int w83627ehf_remove(struct platform_device *pdev) ...@@ -2608,10 +2617,98 @@ static int w83627ehf_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int w83627ehf_suspend(struct device *dev)
{
struct w83627ehf_data *data = w83627ehf_update_device(dev);
struct w83627ehf_sio_data *sio_data = dev->platform_data;
mutex_lock(&data->update_lock);
data->vbat = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
if (sio_data->kind == nct6775) {
data->fandiv1 = w83627ehf_read_value(data, NCT6775_REG_FANDIV1);
data->fandiv2 = w83627ehf_read_value(data, NCT6775_REG_FANDIV2);
}
mutex_unlock(&data->update_lock);
return 0;
}
static int w83627ehf_resume(struct device *dev)
{
struct w83627ehf_data *data = dev_get_drvdata(dev);
struct w83627ehf_sio_data *sio_data = dev->platform_data;
int i;
mutex_lock(&data->update_lock);
data->bank = 0xff; /* Force initial bank selection */
/* Restore limits */
for (i = 0; i < data->in_num; i++) {
if ((i == 6) && data->in6_skip)
continue;
w83627ehf_write_value(data, W83627EHF_REG_IN_MIN(i),
data->in_min[i]);
w83627ehf_write_value(data, W83627EHF_REG_IN_MAX(i),
data->in_max[i]);
}
for (i = 0; i < 5; i++) {
if (!(data->has_fan_min & (1 << i)))
continue;
w83627ehf_write_value(data, data->REG_FAN_MIN[i],
data->fan_min[i]);
}
for (i = 0; i < NUM_REG_TEMP; i++) {
if (!(data->have_temp & (1 << i)))
continue;
if (data->reg_temp_over[i])
w83627ehf_write_temp(data, data->reg_temp_over[i],
data->temp_max[i]);
if (data->reg_temp_hyst[i])
w83627ehf_write_temp(data, data->reg_temp_hyst[i],
data->temp_max_hyst[i]);
if (i > 2)
continue;
if (data->have_temp_offset & (1 << i))
w83627ehf_write_value(data,
W83627EHF_REG_TEMP_OFFSET[i],
data->temp_offset[i]);
}
/* Restore other settings */
w83627ehf_write_value(data, W83627EHF_REG_VBAT, data->vbat);
if (sio_data->kind == nct6775) {
w83627ehf_write_value(data, NCT6775_REG_FANDIV1, data->fandiv1);
w83627ehf_write_value(data, NCT6775_REG_FANDIV2, data->fandiv2);
}
/* Force re-reading all values */
data->valid = 0;
mutex_unlock(&data->update_lock);
return 0;
}
static const struct dev_pm_ops w83627ehf_dev_pm_ops = {
.suspend = w83627ehf_suspend,
.resume = w83627ehf_resume,
};
#define W83627EHF_DEV_PM_OPS (&w83627ehf_dev_pm_ops)
#else
#define W83627EHF_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static struct platform_driver w83627ehf_driver = { static struct platform_driver w83627ehf_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DRVNAME, .name = DRVNAME,
.pm = W83627EHF_DEV_PM_OPS,
}, },
.probe = w83627ehf_probe, .probe = w83627ehf_probe,
.remove = w83627ehf_remove, .remove = w83627ehf_remove,
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Philip Edelbrock <phil@netroedge.com>, * Philip Edelbrock <phil@netroedge.com>,
* and Mark Studebaker <mdsxyz123@yahoo.com> * and Mark Studebaker <mdsxyz123@yahoo.com>
* Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
* Copyright (c) 2007 Jean Delvare <khali@linux-fr.org> * Copyright (c) 2007 - 1012 Jean Delvare <khali@linux-fr.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -389,6 +389,12 @@ struct w83627hf_data { ...@@ -389,6 +389,12 @@ struct w83627hf_data {
*/ */
u8 vrm; u8 vrm;
u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */ u8 vrm_ovt; /* Register value, 627THF/637HF/687THF only */
#ifdef CONFIG_PM
/* Remember extra register values over suspend/resume */
u8 scfg1;
u8 scfg2;
#endif
}; };
...@@ -401,10 +407,77 @@ static void w83627hf_update_fan_div(struct w83627hf_data *data); ...@@ -401,10 +407,77 @@ static void w83627hf_update_fan_div(struct w83627hf_data *data);
static struct w83627hf_data *w83627hf_update_device(struct device *dev); static struct w83627hf_data *w83627hf_update_device(struct device *dev);
static void w83627hf_init_device(struct platform_device *pdev); static void w83627hf_init_device(struct platform_device *pdev);
#ifdef CONFIG_PM
static int w83627hf_suspend(struct device *dev)
{
struct w83627hf_data *data = w83627hf_update_device(dev);
mutex_lock(&data->update_lock);
data->scfg1 = w83627hf_read_value(data, W83781D_REG_SCFG1);
data->scfg2 = w83627hf_read_value(data, W83781D_REG_SCFG2);
mutex_unlock(&data->update_lock);
return 0;
}
static int w83627hf_resume(struct device *dev)
{
struct w83627hf_data *data = dev_get_drvdata(dev);
int i, num_temps = (data->type == w83697hf) ? 2 : 3;
/* Restore limits */
mutex_lock(&data->update_lock);
for (i = 0; i <= 8; i++) {
/* skip missing sensors */
if (((data->type == w83697hf) && (i == 1)) ||
((data->type != w83627hf && data->type != w83697hf)
&& (i == 5 || i == 6)))
continue;
w83627hf_write_value(data, W83781D_REG_IN_MAX(i),
data->in_max[i]);
w83627hf_write_value(data, W83781D_REG_IN_MIN(i),
data->in_min[i]);
}
for (i = 0; i <= 2; i++)
w83627hf_write_value(data, W83627HF_REG_FAN_MIN(i),
data->fan_min[i]);
for (i = 0; i < num_temps; i++) {
w83627hf_write_value(data, w83627hf_reg_temp_over[i],
data->temp_max[i]);
w83627hf_write_value(data, w83627hf_reg_temp_hyst[i],
data->temp_max_hyst[i]);
}
/* Fixup BIOS bugs */
if (data->type == w83627thf || data->type == w83637hf ||
data->type == w83687thf)
w83627hf_write_value(data, W83627THF_REG_VRM_OVT_CFG,
data->vrm_ovt);
w83627hf_write_value(data, W83781D_REG_SCFG1, data->scfg1);
w83627hf_write_value(data, W83781D_REG_SCFG2, data->scfg2);
/* Force re-reading all values */
data->valid = 0;
mutex_unlock(&data->update_lock);
return 0;
}
static const struct dev_pm_ops w83627hf_dev_pm_ops = {
.suspend = w83627hf_suspend,
.resume = w83627hf_resume,
};
#define W83627HF_DEV_PM_OPS (&w83627hf_dev_pm_ops)
#else
#define W83627HF_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
static struct platform_driver w83627hf_driver = { static struct platform_driver w83627hf_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DRVNAME, .name = DRVNAME,
.pm = W83627HF_DEV_PM_OPS,
}, },
.probe = w83627hf_probe, .probe = w83627hf_probe,
.remove = w83627hf_remove, .remove = w83627hf_remove,
...@@ -1659,8 +1732,10 @@ static void w83627hf_init_device(struct platform_device *pdev) ...@@ -1659,8 +1732,10 @@ static void w83627hf_init_device(struct platform_device *pdev)
/* Minimize conflicts with other winbond i2c-only clients... */ /* Minimize conflicts with other winbond i2c-only clients... */
/* disable i2c subclients... how to disable main i2c client?? */ /* disable i2c subclients... how to disable main i2c client?? */
/* force i2c address to relatively uncommon address */ /* force i2c address to relatively uncommon address */
w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89); if (type == w83627hf) {
w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c); w83627hf_write_value(data, W83781D_REG_I2C_SUBADDR, 0x89);
w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);
}
/* Read VID only once */ /* Read VID only once */
if (type == w83627hf || type == w83637hf) { if (type == w83627hf || type == w83637hf) {
......
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