Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
* 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6: hwmon: (it87) Support for 16-bit fan reading in it8705 >= rev 0x03 hwmon: (it87) Support for 16-bit fan reading in it8712 >= rev 0x07 hwmon: (hwmon-vid) Add 6-bit vid codes for AMD NPT 0Fh cpus hwmon: (hwmon-vid) Trivial format multi-line comments per CodingStyle hwmon: ad7414 driver hwmon: (thmc50) Add support for critical temperature limits hwmon: (adm9240) Remove EXPERIMENTAL dependency hwmon: (w83627hf) Drop reset module parameter hwmon: (w83627hf) Add pwm_enable sysfs interface hwmon: (w83791d) Use fan divisor bits from vbat register hwmon: (f71882fg) Delete needless forward declarations hwmon: (dme1737) Add support for the SMSC SCH5027 hwmon: (dme1737) Skip detection if forced hwmon: (dme1737) Cleanups
This commit is contained in:
@@ -10,6 +10,10 @@ Supported chips:
|
|||||||
Prefix: 'sch311x'
|
Prefix: 'sch311x'
|
||||||
Addresses scanned: none, address read from Super-I/O config space
|
Addresses scanned: none, address read from Super-I/O config space
|
||||||
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
|
Datasheet: http://www.nuhorizons.com/FeaturedProducts/Volume1/SMSC/311x.pdf
|
||||||
|
* SMSC SCH5027
|
||||||
|
Prefix: 'sch5027'
|
||||||
|
Addresses scanned: I2C 0x2c, 0x2d, 0x2e
|
||||||
|
Datasheet: Provided by SMSC upon request and under NDA
|
||||||
|
|
||||||
Authors:
|
Authors:
|
||||||
Juerg Haefliger <juergh@gmail.com>
|
Juerg Haefliger <juergh@gmail.com>
|
||||||
@@ -27,33 +31,31 @@ Module Parameters
|
|||||||
following boards:
|
following boards:
|
||||||
- VIA EPIA SN18000
|
- VIA EPIA SN18000
|
||||||
|
|
||||||
Note that there is no need to use this parameter if the driver loads without
|
|
||||||
complaining. The driver will say so if it is necessary.
|
|
||||||
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
This driver implements support for the hardware monitoring capabilities of the
|
This driver implements support for the hardware monitoring capabilities of the
|
||||||
SMSC DME1737 and Asus A8000 (which are the same) and SMSC SCH311x Super-I/O
|
SMSC DME1737 and Asus A8000 (which are the same), SMSC SCH5027, and SMSC
|
||||||
chips. These chips feature monitoring of 3 temp sensors temp[1-3] (2 remote
|
SCH311x Super-I/O chips. These chips feature monitoring of 3 temp sensors
|
||||||
diodes and 1 internal), 7 voltages in[0-6] (6 external and 1 internal) and up
|
temp[1-3] (2 remote diodes and 1 internal), 7 voltages in[0-6] (6 external and
|
||||||
to 6 fan speeds fan[1-6]. Additionally, the chips implement up to 5 PWM
|
1 internal) and up to 6 fan speeds fan[1-6]. Additionally, the chips implement
|
||||||
outputs pwm[1-3,5-6] for controlling fan speeds both manually and
|
up to 5 PWM outputs pwm[1-3,5-6] for controlling fan speeds both manually and
|
||||||
automatically.
|
automatically.
|
||||||
|
|
||||||
For the DME1737 and A8000, fan[1-2] and pwm[1-2] are always present. Fan[3-6]
|
For the DME1737, A8000 and SCH5027, fan[1-2] and pwm[1-2] are always present.
|
||||||
and pwm[3,5-6] are optional features and their availability depends on the
|
Fan[3-6] and pwm[3,5-6] are optional features and their availability depends on
|
||||||
configuration of the chip. The driver will detect which features are present
|
the configuration of the chip. The driver will detect which features are
|
||||||
during initialization and create the sysfs attributes accordingly.
|
present during initialization and create the sysfs attributes accordingly.
|
||||||
|
|
||||||
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
|
For the SCH311x, fan[1-3] and pwm[1-3] are always present and fan[4-6] and
|
||||||
pwm[5-6] don't exist.
|
pwm[5-6] don't exist.
|
||||||
|
|
||||||
The hardware monitoring features of the DME1737 and A8000 are only accessible
|
The hardware monitoring features of the DME1737, A8000, and SCH5027 are only
|
||||||
via SMBus, while the SCH311x only provides access via the ISA bus. The driver
|
accessible via SMBus, while the SCH311x only provides access via the ISA bus.
|
||||||
will therefore register itself as an I2C client driver if it detects a DME1737
|
The driver will therefore register itself as an I2C client driver if it detects
|
||||||
or A8000 and as a platform driver if it detects a SCH311x chip.
|
a DME1737, A8000, or SCH5027 and as a platform driver if it detects a SCH311x
|
||||||
|
chip.
|
||||||
|
|
||||||
|
|
||||||
Voltage Monitoring
|
Voltage Monitoring
|
||||||
@@ -64,6 +66,7 @@ scaling resistors. The values returned by the driver therefore reflect true
|
|||||||
millivolts and don't need scaling. The voltage inputs are mapped as follows
|
millivolts and don't need scaling. The voltage inputs are mapped as follows
|
||||||
(the last column indicates the input ranges):
|
(the last column indicates the input ranges):
|
||||||
|
|
||||||
|
DME1737, A8000:
|
||||||
in0: +5VTR (+5V standby) 0V - 6.64V
|
in0: +5VTR (+5V standby) 0V - 6.64V
|
||||||
in1: Vccp (processor core) 0V - 3V
|
in1: Vccp (processor core) 0V - 3V
|
||||||
in2: VCC (internal +3.3V) 0V - 4.38V
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
@@ -72,6 +75,24 @@ millivolts and don't need scaling. The voltage inputs are mapped as follows
|
|||||||
in5: VTR (+3.3V standby) 0V - 4.38V
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
in6: Vbat (+3.0V) 0V - 4.38V
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
|
SCH311x:
|
||||||
|
in0: +2.5V 0V - 6.64V
|
||||||
|
in1: Vccp (processor core) 0V - 2V
|
||||||
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
|
in3: +5V 0V - 6.64V
|
||||||
|
in4: +12V 0V - 16V
|
||||||
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
|
SCH5027:
|
||||||
|
in0: +5VTR (+5V standby) 0V - 6.64V
|
||||||
|
in1: Vccp (processor core) 0V - 3V
|
||||||
|
in2: VCC (internal +3.3V) 0V - 4.38V
|
||||||
|
in3: V2_IN 0V - 1.5V
|
||||||
|
in4: V1_IN 0V - 1.5V
|
||||||
|
in5: VTR (+3.3V standby) 0V - 4.38V
|
||||||
|
in6: Vbat (+3.0V) 0V - 4.38V
|
||||||
|
|
||||||
Each voltage input has associated min and max limits which trigger an alarm
|
Each voltage input has associated min and max limits which trigger an alarm
|
||||||
when crossed.
|
when crossed.
|
||||||
|
|
||||||
|
@@ -6,12 +6,14 @@ Supported chips:
|
|||||||
Prefix: 'it87'
|
Prefix: 'it87'
|
||||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||||
Datasheet: Publicly available at the ITE website
|
Datasheet: Publicly available at the ITE website
|
||||||
http://www.ite.com.tw/
|
http://www.ite.com.tw/product_info/file/pc/IT8705F_V.0.4.1.pdf
|
||||||
* IT8712F
|
* IT8712F
|
||||||
Prefix: 'it8712'
|
Prefix: 'it8712'
|
||||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||||
Datasheet: Publicly available at the ITE website
|
Datasheet: Publicly available at the ITE website
|
||||||
http://www.ite.com.tw/
|
http://www.ite.com.tw/product_info/file/pc/IT8712F_V0.9.1.pdf
|
||||||
|
http://www.ite.com.tw/product_info/file/pc/Errata%20V0.1%20for%20IT8712F%20V0.9.1.pdf
|
||||||
|
http://www.ite.com.tw/product_info/file/pc/IT8712F_V0.9.3.pdf
|
||||||
* IT8716F/IT8726F
|
* IT8716F/IT8726F
|
||||||
Prefix: 'it8716'
|
Prefix: 'it8716'
|
||||||
Addresses scanned: from Super I/O config space (8 I/O ports)
|
Addresses scanned: from Super I/O config space (8 I/O ports)
|
||||||
@@ -90,14 +92,13 @@ upper VID bits share their pins with voltage inputs (in5 and in6) so you
|
|||||||
can't have both on a given board.
|
can't have both on a given board.
|
||||||
|
|
||||||
The IT8716F, IT8718F and later IT8712F revisions have support for
|
The IT8716F, IT8718F and later IT8712F revisions have support for
|
||||||
2 additional fans. They are supported by the driver for the IT8716F and
|
2 additional fans. The additional fans are supported by the driver.
|
||||||
IT8718F but not for the IT8712F
|
|
||||||
|
|
||||||
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
|
The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
|
||||||
16-bit tachometer counters for fans 1 to 3. This is better (no more fan
|
16-bit tachometer counters for fans 1 to 3. This is better (no more fan
|
||||||
clock divider mess) but not compatible with the older chips and
|
clock divider mess) but not compatible with the older chips and
|
||||||
revisions. For now, the driver only uses the 16-bit mode on the
|
revisions. The 16-bit tachometer mode is enabled by the driver when one
|
||||||
IT8716F and IT8718F.
|
of the above chips is detected.
|
||||||
|
|
||||||
The IT8726F is just bit enhanced IT8716F with additional hardware
|
The IT8726F is just bit enhanced IT8716F with additional hardware
|
||||||
for AMD power sequencing. Therefore the chip will appear as IT8716F
|
for AMD power sequencing. Therefore the chip will appear as IT8716F
|
||||||
|
@@ -40,10 +40,6 @@ Module Parameters
|
|||||||
(default is 1)
|
(default is 1)
|
||||||
Use 'init=0' to bypass initializing the chip.
|
Use 'init=0' to bypass initializing the chip.
|
||||||
Try this if your computer crashes when you load the module.
|
Try this if your computer crashes when you load the module.
|
||||||
* reset: int
|
|
||||||
(default is 0)
|
|
||||||
The driver used to reset the chip on load, but does no more. Use
|
|
||||||
'reset=1' to restore the old behavior. Report if you need to do this.
|
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
|
@@ -22,6 +22,7 @@ Credits:
|
|||||||
|
|
||||||
Additional contributors:
|
Additional contributors:
|
||||||
Sven Anders <anders@anduras.de>
|
Sven Anders <anders@anduras.de>
|
||||||
|
Marc Hulsman <m.hulsman@tudelft.nl>
|
||||||
|
|
||||||
Module Parameters
|
Module Parameters
|
||||||
-----------------
|
-----------------
|
||||||
@@ -67,9 +68,8 @@ on until the temperature falls below the Hysteresis value.
|
|||||||
|
|
||||||
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
|
||||||
triggered if the rotation speed has dropped below a programmable limit. Fan
|
triggered if the rotation speed has dropped below a programmable limit. Fan
|
||||||
readings can be divided by a programmable divider (1, 2, 4, 8 for fan 1/2/3
|
readings can be divided by a programmable divider (1, 2, 4, 8, 16,
|
||||||
and 1, 2, 4, 8, 16, 32, 64 or 128 for fan 4/5) to give the readings more
|
32, 64 or 128 for all fans) to give the readings more range or accuracy.
|
||||||
range or accuracy.
|
|
||||||
|
|
||||||
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
Voltage sensors (also known as IN sensors) report their values in millivolts.
|
||||||
An alarm is triggered if the voltage has crossed a programmable minimum
|
An alarm is triggered if the voltage has crossed a programmable minimum
|
||||||
|
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
|
|||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called abituguru3.
|
will be called abituguru3.
|
||||||
|
|
||||||
|
config SENSORS_AD7414
|
||||||
|
tristate "Analog Devices AD7414"
|
||||||
|
depends on I2C && EXPERIMENTAL
|
||||||
|
help
|
||||||
|
If you say yes here you get support for the Analog Devices
|
||||||
|
AD7414 temperature monitoring chip.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called ad7414.
|
||||||
|
|
||||||
config SENSORS_AD7418
|
config SENSORS_AD7418
|
||||||
tristate "Analog Devices AD7416, AD7417 and AD7418"
|
tristate "Analog Devices AD7416, AD7417 and AD7418"
|
||||||
depends on I2C && EXPERIMENTAL
|
depends on I2C && EXPERIMENTAL
|
||||||
@@ -124,7 +134,7 @@ config SENSORS_ADM1031
|
|||||||
|
|
||||||
config SENSORS_ADM9240
|
config SENSORS_ADM9240
|
||||||
tristate "Analog Devices ADM9240 and compatibles"
|
tristate "Analog Devices ADM9240 and compatibles"
|
||||||
depends on I2C && EXPERIMENTAL
|
depends on I2C
|
||||||
select HWMON_VID
|
select HWMON_VID
|
||||||
help
|
help
|
||||||
If you say yes here you get support for Analog Devices ADM9240,
|
If you say yes here you get support for Analog Devices ADM9240,
|
||||||
@@ -575,8 +585,8 @@ config SENSORS_DME1737
|
|||||||
select HWMON_VID
|
select HWMON_VID
|
||||||
help
|
help
|
||||||
If you say yes here you get support for the hardware monitoring
|
If you say yes here you get support for the hardware monitoring
|
||||||
and fan control features of the SMSC DME1737 (and compatibles
|
and fan control features of the SMSC DME1737, SCH311x, SCH5027, and
|
||||||
like the Asus A8000) and SCH311x Super-I/O chips.
|
Asus A8000 Super-I/O chips.
|
||||||
|
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called dme1737.
|
will be called dme1737.
|
||||||
|
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
|
|||||||
|
|
||||||
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
|
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
|
||||||
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
|
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
|
||||||
|
obj-$(CONFIG_SENSORS_AD7414) += ad7414.o
|
||||||
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
|
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
|
||||||
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
|
||||||
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
|
||||||
|
268
drivers/hwmon/ad7414.c
Normal file
268
drivers/hwmon/ad7414.c
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* An hwmon driver for the Analog Devices AD7414
|
||||||
|
*
|
||||||
|
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 PIKA Technologies
|
||||||
|
* Sean MacLennan <smaclennan@pikatech.com>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Spansion Inc.
|
||||||
|
* Frank Edelhaeuser <frank.edelhaeuser at spansion.com>
|
||||||
|
* (converted to "new style" I2C driver model, removed checkpatch.pl warnings)
|
||||||
|
*
|
||||||
|
* Based on ad7418.c
|
||||||
|
* Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo at towertech.it>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/hwmon.h>
|
||||||
|
#include <linux/hwmon-sysfs.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/sysfs.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* AD7414 registers */
|
||||||
|
#define AD7414_REG_TEMP 0x00
|
||||||
|
#define AD7414_REG_CONF 0x01
|
||||||
|
#define AD7414_REG_T_HIGH 0x02
|
||||||
|
#define AD7414_REG_T_LOW 0x03
|
||||||
|
|
||||||
|
static u8 AD7414_REG_LIMIT[] = { AD7414_REG_T_HIGH, AD7414_REG_T_LOW };
|
||||||
|
|
||||||
|
struct ad7414_data {
|
||||||
|
struct device *hwmon_dev;
|
||||||
|
struct mutex lock; /* atomic read data updates */
|
||||||
|
char valid; /* !=0 if following fields are valid */
|
||||||
|
unsigned long next_update; /* In jiffies */
|
||||||
|
s16 temp_input; /* Register values */
|
||||||
|
s8 temps[ARRAY_SIZE(AD7414_REG_LIMIT)];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* REG: (0.25C/bit, two's complement) << 6 */
|
||||||
|
static inline int ad7414_temp_from_reg(s16 reg)
|
||||||
|
{
|
||||||
|
/* use integer division instead of equivalent right shift to
|
||||||
|
* guarantee arithmetic shift and preserve the sign
|
||||||
|
*/
|
||||||
|
return ((int)reg / 64) * 250;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ad7414_read(struct i2c_client *client, u8 reg)
|
||||||
|
{
|
||||||
|
if (reg == AD7414_REG_TEMP) {
|
||||||
|
int value = i2c_smbus_read_word_data(client, reg);
|
||||||
|
return (value < 0) ? value : swab16(value);
|
||||||
|
} else
|
||||||
|
return i2c_smbus_read_byte_data(client, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ad7414_write(struct i2c_client *client, u8 reg, u8 value)
|
||||||
|
{
|
||||||
|
return i2c_smbus_write_byte_data(client, reg, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ad7414_data *ad7414_update_device(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
mutex_lock(&data->lock);
|
||||||
|
|
||||||
|
if (time_after(jiffies, data->next_update) || !data->valid) {
|
||||||
|
int value, i;
|
||||||
|
|
||||||
|
dev_dbg(&client->dev, "starting ad7414 update\n");
|
||||||
|
|
||||||
|
value = ad7414_read(client, AD7414_REG_TEMP);
|
||||||
|
if (value < 0)
|
||||||
|
dev_dbg(&client->dev, "AD7414_REG_TEMP err %d\n",
|
||||||
|
value);
|
||||||
|
else
|
||||||
|
data->temp_input = value;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(AD7414_REG_LIMIT); ++i) {
|
||||||
|
value = ad7414_read(client, AD7414_REG_LIMIT[i]);
|
||||||
|
if (value < 0)
|
||||||
|
dev_dbg(&client->dev, "AD7414 reg %d err %d\n",
|
||||||
|
AD7414_REG_LIMIT[i], value);
|
||||||
|
else
|
||||||
|
data->temps[i] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->next_update = jiffies + HZ + HZ / 2;
|
||||||
|
data->valid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&data->lock);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_temp_input(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct ad7414_data *data = ad7414_update_device(dev);
|
||||||
|
return sprintf(buf, "%d\n", ad7414_temp_from_reg(data->temp_input));
|
||||||
|
}
|
||||||
|
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0);
|
||||||
|
|
||||||
|
static ssize_t show_max_min(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
int index = to_sensor_dev_attr(attr)->index;
|
||||||
|
struct ad7414_data *data = ad7414_update_device(dev);
|
||||||
|
return sprintf(buf, "%d\n", data->temps[index] * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t set_max_min(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||||
|
int index = to_sensor_dev_attr(attr)->index;
|
||||||
|
u8 reg = AD7414_REG_LIMIT[index];
|
||||||
|
long temp = simple_strtol(buf, NULL, 10);
|
||||||
|
|
||||||
|
temp = SENSORS_LIMIT(temp, -40000, 85000);
|
||||||
|
temp = (temp + (temp < 0 ? -500 : 500)) / 1000;
|
||||||
|
|
||||||
|
mutex_lock(&data->lock);
|
||||||
|
data->temps[index] = temp;
|
||||||
|
ad7414_write(client, reg, temp);
|
||||||
|
mutex_unlock(&data->lock);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
|
||||||
|
show_max_min, set_max_min, 0);
|
||||||
|
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
|
||||||
|
show_max_min, set_max_min, 1);
|
||||||
|
|
||||||
|
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
int bitnr = to_sensor_dev_attr(attr)->index;
|
||||||
|
struct ad7414_data *data = ad7414_update_device(dev);
|
||||||
|
int value = (data->temp_input >> bitnr) & 1;
|
||||||
|
return sprintf(buf, "%d\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 3);
|
||||||
|
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 4);
|
||||||
|
|
||||||
|
static struct attribute *ad7414_attributes[] = {
|
||||||
|
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group ad7414_group = {
|
||||||
|
.attrs = ad7414_attributes,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ad7414_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *dev_id)
|
||||||
|
{
|
||||||
|
struct ad7414_data *data;
|
||||||
|
int conf;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
|
I2C_FUNC_SMBUS_READ_WORD_DATA))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
|
||||||
|
if (!data) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, data);
|
||||||
|
mutex_init(&data->lock);
|
||||||
|
|
||||||
|
dev_info(&client->dev, "chip found\n");
|
||||||
|
|
||||||
|
/* Make sure the chip is powered up. */
|
||||||
|
conf = i2c_smbus_read_byte_data(client, AD7414_REG_CONF);
|
||||||
|
if (conf < 0)
|
||||||
|
dev_warn(&client->dev,
|
||||||
|
"ad7414_probe unable to read config register.\n");
|
||||||
|
else {
|
||||||
|
conf &= ~(1 << 7);
|
||||||
|
i2c_smbus_write_byte_data(client, AD7414_REG_CONF, conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register sysfs hooks */
|
||||||
|
err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
|
||||||
|
if (err)
|
||||||
|
goto exit_free;
|
||||||
|
|
||||||
|
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
|
err = PTR_ERR(data->hwmon_dev);
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit_remove:
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
|
||||||
|
exit_free:
|
||||||
|
kfree(data);
|
||||||
|
exit:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __devexit ad7414_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct ad7414_data *data = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
sysfs_remove_group(&client->dev.kobj, &ad7414_group);
|
||||||
|
kfree(data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id ad7414_id[] = {
|
||||||
|
{ "ad7414", 0 },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct i2c_driver ad7414_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "ad7414",
|
||||||
|
},
|
||||||
|
.probe = ad7414_probe,
|
||||||
|
.remove = __devexit_p(ad7414_remove),
|
||||||
|
.id_table = ad7414_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init ad7414_init(void)
|
||||||
|
{
|
||||||
|
return i2c_add_driver(&ad7414_driver);
|
||||||
|
}
|
||||||
|
module_init(ad7414_init);
|
||||||
|
|
||||||
|
static void __exit ad7414_exit(void)
|
||||||
|
{
|
||||||
|
i2c_del_driver(&ad7414_driver);
|
||||||
|
}
|
||||||
|
module_exit(ad7414_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Stefan Roese <sr at denx.de>, "
|
||||||
|
"Frank Edelhaeuser <frank.edelhaeuser at spansion.com>");
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("AD7414 driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x
|
* dme1737.c - Driver for the SMSC DME1737, Asus A8000, SMSC SCH311x and
|
||||||
* Super-I/O chips integrated hardware monitoring features.
|
* SCH5027 Super-I/O chips integrated hardware monitoring features.
|
||||||
* Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
|
* Copyright (c) 2007, 2008 Juerg Haefliger <juergh@gmail.com>
|
||||||
*
|
*
|
||||||
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
|
* This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access
|
||||||
* the chip registers if a DME1737 (or A8000) is found and the ISA bus if a
|
* the chip registers if a DME1737, A8000, or SCH5027 is found and the ISA bus
|
||||||
* SCH311x chip is found. Both types of chips have very similar hardware
|
* if a SCH311x chip is found. Both types of chips have very similar hardware
|
||||||
* monitoring capabilities but differ in the way they can be accessed.
|
* monitoring capabilities but differ in the way they can be accessed.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -57,7 +57,10 @@ MODULE_PARM_DESC(probe_all_addr, "Include probing of non-standard LPC "
|
|||||||
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
static const unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
|
||||||
|
|
||||||
/* Insmod parameters */
|
/* Insmod parameters */
|
||||||
I2C_CLIENT_INSMOD_1(dme1737);
|
I2C_CLIENT_INSMOD_2(dme1737, sch5027);
|
||||||
|
|
||||||
|
/* ISA chip types */
|
||||||
|
enum isa_chips { sch311x = sch5027 + 1 };
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------
|
/* ---------------------------------------------------------------------
|
||||||
* Registers
|
* Registers
|
||||||
@@ -163,6 +166,7 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
|
|||||||
#define DME1737_VERSTEP 0x88
|
#define DME1737_VERSTEP 0x88
|
||||||
#define DME1737_VERSTEP_MASK 0xf8
|
#define DME1737_VERSTEP_MASK 0xf8
|
||||||
#define SCH311X_DEVICE 0x8c
|
#define SCH311X_DEVICE 0x8c
|
||||||
|
#define SCH5027_VERSTEP 0x69
|
||||||
|
|
||||||
/* Length of ISA address segment */
|
/* Length of ISA address segment */
|
||||||
#define DME1737_EXTENT 2
|
#define DME1737_EXTENT 2
|
||||||
@@ -182,6 +186,7 @@ struct dme1737_data {
|
|||||||
unsigned long last_update; /* in jiffies */
|
unsigned long last_update; /* in jiffies */
|
||||||
unsigned long last_vbat; /* in jiffies */
|
unsigned long last_vbat; /* in jiffies */
|
||||||
enum chips type;
|
enum chips type;
|
||||||
|
const int *in_nominal; /* pointer to IN_NOMINAL array */
|
||||||
|
|
||||||
u8 vid;
|
u8 vid;
|
||||||
u8 pwm_rr_en;
|
u8 pwm_rr_en;
|
||||||
@@ -220,23 +225,23 @@ static const int IN_NOMINAL_DME1737[] = {5000, 2250, 3300, 5000, 12000, 3300,
|
|||||||
3300};
|
3300};
|
||||||
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
|
static const int IN_NOMINAL_SCH311x[] = {2500, 1500, 3300, 5000, 12000, 3300,
|
||||||
3300};
|
3300};
|
||||||
#define IN_NOMINAL(ix, type) (((type) == dme1737) ? \
|
static const int IN_NOMINAL_SCH5027[] = {5000, 2250, 3300, 1125, 1125, 3300,
|
||||||
IN_NOMINAL_DME1737[(ix)] : \
|
3300};
|
||||||
IN_NOMINAL_SCH311x[(ix)])
|
#define IN_NOMINAL(type) ((type) == sch311x ? IN_NOMINAL_SCH311x : \
|
||||||
|
(type) == sch5027 ? IN_NOMINAL_SCH5027 : \
|
||||||
|
IN_NOMINAL_DME1737)
|
||||||
|
|
||||||
/* Voltage input
|
/* Voltage input
|
||||||
* Voltage inputs have 16 bits resolution, limit values have 8 bits
|
* Voltage inputs have 16 bits resolution, limit values have 8 bits
|
||||||
* resolution. */
|
* resolution. */
|
||||||
static inline int IN_FROM_REG(int reg, int ix, int res, int type)
|
static inline int IN_FROM_REG(int reg, int nominal, int res)
|
||||||
{
|
{
|
||||||
return (reg * IN_NOMINAL(ix, type) + (3 << (res - 3))) /
|
return (reg * nominal + (3 << (res - 3))) / (3 << (res - 2));
|
||||||
(3 << (res - 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int IN_TO_REG(int val, int ix, int type)
|
static inline int IN_TO_REG(int val, int nominal)
|
||||||
{
|
{
|
||||||
return SENSORS_LIMIT((val * 192 + IN_NOMINAL(ix, type) / 2) /
|
return SENSORS_LIMIT((val * 192 + nominal / 2) / nominal, 0, 255);
|
||||||
IN_NOMINAL(ix, type), 0, 255);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temperature input
|
/* Temperature input
|
||||||
@@ -565,7 +570,10 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
|||||||
|
|
||||||
/* Sample register contents every 1 sec */
|
/* Sample register contents every 1 sec */
|
||||||
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
|
||||||
data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
|
if (data->type != sch5027) {
|
||||||
|
data->vid = dme1737_read(client, DME1737_REG_VID) &
|
||||||
|
0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
/* In (voltage) registers */
|
/* In (voltage) registers */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
|
||||||
@@ -593,9 +601,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
|||||||
DME1737_REG_TEMP_MIN(ix));
|
DME1737_REG_TEMP_MIN(ix));
|
||||||
data->temp_max[ix] = dme1737_read(client,
|
data->temp_max[ix] = dme1737_read(client,
|
||||||
DME1737_REG_TEMP_MAX(ix));
|
DME1737_REG_TEMP_MAX(ix));
|
||||||
|
if (data->type != sch5027) {
|
||||||
data->temp_offset[ix] = dme1737_read(client,
|
data->temp_offset[ix] = dme1737_read(client,
|
||||||
DME1737_REG_TEMP_OFFSET(ix));
|
DME1737_REG_TEMP_OFFSET(ix));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* In and temp LSB registers
|
/* In and temp LSB registers
|
||||||
* The LSBs are latched when the MSBs are read, so the order in
|
* The LSBs are latched when the MSBs are read, so the order in
|
||||||
@@ -669,10 +679,12 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
|
|||||||
data->zone_abs[ix] = dme1737_read(client,
|
data->zone_abs[ix] = dme1737_read(client,
|
||||||
DME1737_REG_ZONE_ABS(ix));
|
DME1737_REG_ZONE_ABS(ix));
|
||||||
}
|
}
|
||||||
|
if (data->type != sch5027) {
|
||||||
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
|
||||||
data->zone_hyst[ix] = dme1737_read(client,
|
data->zone_hyst[ix] = dme1737_read(client,
|
||||||
DME1737_REG_ZONE_HYST(ix));
|
DME1737_REG_ZONE_HYST(ix));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Alarm registers */
|
/* Alarm registers */
|
||||||
data->alarms = dme1737_read(client,
|
data->alarms = dme1737_read(client,
|
||||||
@@ -735,13 +747,13 @@ static ssize_t show_in(struct device *dev, struct device_attribute *attr,
|
|||||||
|
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_IN_INPUT:
|
case SYS_IN_INPUT:
|
||||||
res = IN_FROM_REG(data->in[ix], ix, 16, data->type);
|
res = IN_FROM_REG(data->in[ix], data->in_nominal[ix], 16);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MIN:
|
case SYS_IN_MIN:
|
||||||
res = IN_FROM_REG(data->in_min[ix], ix, 8, data->type);
|
res = IN_FROM_REG(data->in_min[ix], data->in_nominal[ix], 8);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MAX:
|
case SYS_IN_MAX:
|
||||||
res = IN_FROM_REG(data->in_max[ix], ix, 8, data->type);
|
res = IN_FROM_REG(data->in_max[ix], data->in_nominal[ix], 8);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_ALARM:
|
case SYS_IN_ALARM:
|
||||||
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
|
res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
|
||||||
@@ -768,12 +780,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
|
|||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case SYS_IN_MIN:
|
case SYS_IN_MIN:
|
||||||
data->in_min[ix] = IN_TO_REG(val, ix, data->type);
|
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MIN(ix),
|
dme1737_write(client, DME1737_REG_IN_MIN(ix),
|
||||||
data->in_min[ix]);
|
data->in_min[ix]);
|
||||||
break;
|
break;
|
||||||
case SYS_IN_MAX:
|
case SYS_IN_MAX:
|
||||||
data->in_max[ix] = IN_TO_REG(val, ix, data->type);
|
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
|
||||||
dme1737_write(client, DME1737_REG_IN_MAX(ix),
|
dme1737_write(client, DME1737_REG_IN_MAX(ix),
|
||||||
data->in_max[ix]);
|
data->in_max[ix]);
|
||||||
break;
|
break;
|
||||||
@@ -1166,7 +1178,7 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
|
|||||||
return sprintf(buf, "%d\n", res);
|
return sprintf(buf, "%d\n", res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct attribute *dme1737_attr_pwm[];
|
static struct attribute *dme1737_pwm_chmod_attr[];
|
||||||
static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
|
static void dme1737_chmod_file(struct device*, struct attribute*, mode_t);
|
||||||
|
|
||||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
||||||
@@ -1230,7 +1242,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||||||
switch (val) {
|
switch (val) {
|
||||||
case 0:
|
case 0:
|
||||||
/* Change permissions of pwm[ix] to read-only */
|
/* Change permissions of pwm[ix] to read-only */
|
||||||
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
|
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
|
||||||
S_IRUGO);
|
S_IRUGO);
|
||||||
/* Turn fan fully on */
|
/* Turn fan fully on */
|
||||||
data->pwm_config[ix] = PWM_EN_TO_REG(0,
|
data->pwm_config[ix] = PWM_EN_TO_REG(0,
|
||||||
@@ -1245,12 +1257,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
|
|||||||
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
|
||||||
data->pwm_config[ix]);
|
data->pwm_config[ix]);
|
||||||
/* Change permissions of pwm[ix] to read-writeable */
|
/* Change permissions of pwm[ix] to read-writeable */
|
||||||
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
|
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
/* Change permissions of pwm[ix] to read-only */
|
/* Change permissions of pwm[ix] to read-only */
|
||||||
dme1737_chmod_file(dev, dme1737_attr_pwm[ix],
|
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
|
||||||
S_IRUGO);
|
S_IRUGO);
|
||||||
/* Turn on auto mode using the saved zone channel
|
/* Turn on auto mode using the saved zone channel
|
||||||
* assignment */
|
* assignment */
|
||||||
@@ -1570,38 +1582,29 @@ static struct attribute *dme1737_attr[] ={
|
|||||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
&sensor_dev_attr_temp1_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
|
||||||
/* Zones */
|
/* Zones */
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_channels_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_channels_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_channels_temp.dev_attr.attr,
|
||||||
/* Misc */
|
|
||||||
&dev_attr_vrm.attr,
|
|
||||||
&dev_attr_cpu0_vid.attr,
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1609,49 +1612,68 @@ static const struct attribute_group dme1737_group = {
|
|||||||
.attrs = dme1737_attr,
|
.attrs = dme1737_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The following struct holds misc attributes, which are not available in all
|
||||||
|
* chips. Their creation depends on the chip type which is determined during
|
||||||
|
* module load. */
|
||||||
|
static struct attribute *dme1737_misc_attr[] = {
|
||||||
|
/* Temperatures */
|
||||||
|
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
||||||
|
/* Zones */
|
||||||
|
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
||||||
|
/* Misc */
|
||||||
|
&dev_attr_vrm.attr,
|
||||||
|
&dev_attr_cpu0_vid.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group dme1737_misc_group = {
|
||||||
|
.attrs = dme1737_misc_attr,
|
||||||
|
};
|
||||||
|
|
||||||
/* The following structs hold the PWM attributes, some of which are optional.
|
/* The following structs hold the PWM attributes, some of which are optional.
|
||||||
* Their creation depends on the chip configuration which is determined during
|
* Their creation depends on the chip configuration which is determined during
|
||||||
* module load. */
|
* module load. */
|
||||||
static struct attribute *dme1737_attr_pwm1[] = {
|
static struct attribute *dme1737_pwm1_attr[] = {
|
||||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm2[] = {
|
static struct attribute *dme1737_pwm2_attr[] = {
|
||||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm3[] = {
|
static struct attribute *dme1737_pwm3_attr[] = {
|
||||||
&sensor_dev_attr_pwm3.dev_attr.attr,
|
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm5[] = {
|
static struct attribute *dme1737_pwm5_attr[] = {
|
||||||
&sensor_dev_attr_pwm5.dev_attr.attr,
|
&sensor_dev_attr_pwm5.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm5_enable.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm6[] = {
|
static struct attribute *dme1737_pwm6_attr[] = {
|
||||||
&sensor_dev_attr_pwm6.dev_attr.attr,
|
&sensor_dev_attr_pwm6.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm6_enable.dev_attr.attr,
|
||||||
@@ -1659,53 +1681,62 @@ static struct attribute *dme1737_attr_pwm6[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_pwm_group[] = {
|
static const struct attribute_group dme1737_pwm_group[] = {
|
||||||
{ .attrs = dme1737_attr_pwm1 },
|
{ .attrs = dme1737_pwm1_attr },
|
||||||
{ .attrs = dme1737_attr_pwm2 },
|
{ .attrs = dme1737_pwm2_attr },
|
||||||
{ .attrs = dme1737_attr_pwm3 },
|
{ .attrs = dme1737_pwm3_attr },
|
||||||
{ .attrs = NULL },
|
{ .attrs = NULL },
|
||||||
{ .attrs = dme1737_attr_pwm5 },
|
{ .attrs = dme1737_pwm5_attr },
|
||||||
{ .attrs = dme1737_attr_pwm6 },
|
{ .attrs = dme1737_pwm6_attr },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The following struct holds misc PWM attributes, which are not available in
|
||||||
|
* all chips. Their creation depends on the chip type which is determined
|
||||||
|
* during module load. */
|
||||||
|
static struct attribute *dme1737_pwm_misc_attr[] = {
|
||||||
|
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The following structs hold the fan attributes, some of which are optional.
|
/* The following structs hold the fan attributes, some of which are optional.
|
||||||
* Their creation depends on the chip configuration which is determined during
|
* Their creation depends on the chip configuration which is determined during
|
||||||
* module load. */
|
* module load. */
|
||||||
static struct attribute *dme1737_attr_fan1[] = {
|
static struct attribute *dme1737_fan1_attr[] = {
|
||||||
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
&sensor_dev_attr_fan1_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan1_min.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,
|
||||||
&sensor_dev_attr_fan1_type.dev_attr.attr,
|
&sensor_dev_attr_fan1_type.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_fan2[] = {
|
static struct attribute *dme1737_fan2_attr[] = {
|
||||||
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
&sensor_dev_attr_fan2_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan2_min.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,
|
||||||
&sensor_dev_attr_fan2_type.dev_attr.attr,
|
&sensor_dev_attr_fan2_type.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_fan3[] = {
|
static struct attribute *dme1737_fan3_attr[] = {
|
||||||
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
&sensor_dev_attr_fan3_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan3_min.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,
|
||||||
&sensor_dev_attr_fan3_type.dev_attr.attr,
|
&sensor_dev_attr_fan3_type.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_fan4[] = {
|
static struct attribute *dme1737_fan4_attr[] = {
|
||||||
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
&sensor_dev_attr_fan4_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan4_min.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,
|
||||||
&sensor_dev_attr_fan4_type.dev_attr.attr,
|
&sensor_dev_attr_fan4_type.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_fan5[] = {
|
static struct attribute *dme1737_fan5_attr[] = {
|
||||||
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
&sensor_dev_attr_fan5_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan5_min.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,
|
||||||
&sensor_dev_attr_fan5_max.dev_attr.attr,
|
&sensor_dev_attr_fan5_max.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_fan6[] = {
|
static struct attribute *dme1737_fan6_attr[] = {
|
||||||
&sensor_dev_attr_fan6_input.dev_attr.attr,
|
&sensor_dev_attr_fan6_input.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan6_min.dev_attr.attr,
|
&sensor_dev_attr_fan6_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_fan6_alarm.dev_attr.attr,
|
&sensor_dev_attr_fan6_alarm.dev_attr.attr,
|
||||||
@@ -1714,94 +1745,83 @@ static struct attribute *dme1737_attr_fan6[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_fan_group[] = {
|
static const struct attribute_group dme1737_fan_group[] = {
|
||||||
{ .attrs = dme1737_attr_fan1 },
|
{ .attrs = dme1737_fan1_attr },
|
||||||
{ .attrs = dme1737_attr_fan2 },
|
{ .attrs = dme1737_fan2_attr },
|
||||||
{ .attrs = dme1737_attr_fan3 },
|
{ .attrs = dme1737_fan3_attr },
|
||||||
{ .attrs = dme1737_attr_fan4 },
|
{ .attrs = dme1737_fan4_attr },
|
||||||
{ .attrs = dme1737_attr_fan5 },
|
{ .attrs = dme1737_fan5_attr },
|
||||||
{ .attrs = dme1737_attr_fan6 },
|
{ .attrs = dme1737_fan6_attr },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The permissions of all of the following attributes are changed to read-
|
/* The permissions of the following zone attributes are changed to read-
|
||||||
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
|
* writeable if the chip is *not* locked. Otherwise they stay read-only. */
|
||||||
static struct attribute *dme1737_attr_lock[] = {
|
static struct attribute *dme1737_zone_chmod_attr[] = {
|
||||||
/* Temperatures */
|
|
||||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp2_offset.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_temp3_offset.dev_attr.attr,
|
|
||||||
/* Zones */
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone1_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone2_auto_point3_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp_hyst.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point1_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point2_temp.dev_attr.attr,
|
||||||
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
&sensor_dev_attr_zone3_auto_point3_temp.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_lock_group = {
|
static const struct attribute_group dme1737_zone_chmod_group = {
|
||||||
.attrs = dme1737_attr_lock,
|
.attrs = dme1737_zone_chmod_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The permissions of the following PWM attributes are changed to read-
|
/* The permissions of the following PWM attributes are changed to read-
|
||||||
* writeable if the chip is *not* locked and the respective PWM is available.
|
* writeable if the chip is *not* locked and the respective PWM is available.
|
||||||
* Otherwise they stay read-only. */
|
* Otherwise they stay read-only. */
|
||||||
static struct attribute *dme1737_attr_pwm1_lock[] = {
|
static struct attribute *dme1737_pwm1_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm1_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm2_lock[] = {
|
static struct attribute *dme1737_pwm2_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm2_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm3_lock[] = {
|
static struct attribute *dme1737_pwm3_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
&sensor_dev_attr_pwm3_ramp_rate.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_channels_zone.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_auto_pwm_min.dev_attr.attr,
|
|
||||||
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm5_lock[] = {
|
static struct attribute *dme1737_pwm5_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm5.dev_attr.attr,
|
&sensor_dev_attr_pwm5.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm5_freq.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static struct attribute *dme1737_attr_pwm6_lock[] = {
|
static struct attribute *dme1737_pwm6_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm6.dev_attr.attr,
|
&sensor_dev_attr_pwm6.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm6_freq.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct attribute_group dme1737_pwm_lock_group[] = {
|
static const struct attribute_group dme1737_pwm_chmod_group[] = {
|
||||||
{ .attrs = dme1737_attr_pwm1_lock },
|
{ .attrs = dme1737_pwm1_chmod_attr },
|
||||||
{ .attrs = dme1737_attr_pwm2_lock },
|
{ .attrs = dme1737_pwm2_chmod_attr },
|
||||||
{ .attrs = dme1737_attr_pwm3_lock },
|
{ .attrs = dme1737_pwm3_chmod_attr },
|
||||||
{ .attrs = NULL },
|
{ .attrs = NULL },
|
||||||
{ .attrs = dme1737_attr_pwm5_lock },
|
{ .attrs = dme1737_pwm5_chmod_attr },
|
||||||
{ .attrs = dme1737_attr_pwm6_lock },
|
{ .attrs = dme1737_pwm6_chmod_attr },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
|
/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
|
||||||
* chip is not locked. Otherwise they are read-only. */
|
* chip is not locked. Otherwise they are read-only. */
|
||||||
static struct attribute *dme1737_attr_pwm[] = {
|
static struct attribute *dme1737_pwm_chmod_attr[] = {
|
||||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2.dev_attr.attr,
|
&sensor_dev_attr_pwm2.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3.dev_attr.attr,
|
&sensor_dev_attr_pwm3.dev_attr.attr,
|
||||||
@@ -1875,8 +1895,16 @@ static void dme1737_remove_files(struct device *dev)
|
|||||||
if (data->has_pwm & (1 << ix)) {
|
if (data->has_pwm & (1 << ix)) {
|
||||||
sysfs_remove_group(&dev->kobj,
|
sysfs_remove_group(&dev->kobj,
|
||||||
&dme1737_pwm_group[ix]);
|
&dme1737_pwm_group[ix]);
|
||||||
|
if (data->type != sch5027 && ix < 3) {
|
||||||
|
sysfs_remove_file(&dev->kobj,
|
||||||
|
dme1737_pwm_misc_attr[ix]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->type != sch5027) {
|
||||||
|
sysfs_remove_group(&dev->kobj, &dme1737_misc_group);
|
||||||
|
}
|
||||||
|
|
||||||
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
sysfs_remove_group(&dev->kobj, &dme1737_group);
|
||||||
|
|
||||||
@@ -1901,6 +1929,13 @@ static int dme1737_create_files(struct device *dev)
|
|||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create misc sysfs attributes */
|
||||||
|
if ((data->type != sch5027) &&
|
||||||
|
(err = sysfs_create_group(&dev->kobj,
|
||||||
|
&dme1737_misc_group))) {
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create fan sysfs attributes */
|
/* Create fan sysfs attributes */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
|
||||||
if (data->has_fan & (1 << ix)) {
|
if (data->has_fan & (1 << ix)) {
|
||||||
@@ -1918,6 +1953,11 @@ static int dme1737_create_files(struct device *dev)
|
|||||||
&dme1737_pwm_group[ix]))) {
|
&dme1737_pwm_group[ix]))) {
|
||||||
goto exit_remove;
|
goto exit_remove;
|
||||||
}
|
}
|
||||||
|
if (data->type != sch5027 && ix < 3 &&
|
||||||
|
(err = sysfs_create_file(&dev->kobj,
|
||||||
|
dme1737_pwm_misc_attr[ix]))) {
|
||||||
|
goto exit_remove;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1927,16 +1967,27 @@ static int dme1737_create_files(struct device *dev)
|
|||||||
dev_info(dev, "Device is locked. Some attributes "
|
dev_info(dev, "Device is locked. Some attributes "
|
||||||
"will be read-only.\n");
|
"will be read-only.\n");
|
||||||
} else {
|
} else {
|
||||||
/* Change permissions of standard attributes */
|
/* Change permissions of zone sysfs attributes */
|
||||||
dme1737_chmod_group(dev, &dme1737_lock_group,
|
dme1737_chmod_group(dev, &dme1737_zone_chmod_group,
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
|
|
||||||
/* Change permissions of PWM attributes */
|
/* Change permissions of misc sysfs attributes */
|
||||||
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
|
if (data->type != sch5027) {
|
||||||
|
dme1737_chmod_group(dev, &dme1737_misc_group,
|
||||||
|
S_IRUGO | S_IWUSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change permissions of PWM sysfs attributes */
|
||||||
|
for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_chmod_group); ix++) {
|
||||||
if (data->has_pwm & (1 << ix)) {
|
if (data->has_pwm & (1 << ix)) {
|
||||||
dme1737_chmod_group(dev,
|
dme1737_chmod_group(dev,
|
||||||
&dme1737_pwm_lock_group[ix],
|
&dme1737_pwm_chmod_group[ix],
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
|
if (data->type != sch5027 && ix < 3) {
|
||||||
|
dme1737_chmod_file(dev,
|
||||||
|
dme1737_pwm_misc_attr[ix],
|
||||||
|
S_IRUGO | S_IWUSR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1945,7 +1996,7 @@ static int dme1737_create_files(struct device *dev)
|
|||||||
if ((data->has_pwm & (1 << ix)) &&
|
if ((data->has_pwm & (1 << ix)) &&
|
||||||
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
|
(PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
|
||||||
dme1737_chmod_file(dev,
|
dme1737_chmod_file(dev,
|
||||||
dme1737_attr_pwm[ix],
|
dme1737_pwm_chmod_attr[ix],
|
||||||
S_IRUGO | S_IWUSR);
|
S_IRUGO | S_IWUSR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1966,6 +2017,9 @@ static int dme1737_init_device(struct device *dev)
|
|||||||
int ix;
|
int ix;
|
||||||
u8 reg;
|
u8 reg;
|
||||||
|
|
||||||
|
/* Point to the right nominal voltages array */
|
||||||
|
data->in_nominal = IN_NOMINAL(data->type);
|
||||||
|
|
||||||
data->config = dme1737_read(client, DME1737_REG_CONFIG);
|
data->config = dme1737_read(client, DME1737_REG_CONFIG);
|
||||||
/* Inform if part is not monitoring/started */
|
/* Inform if part is not monitoring/started */
|
||||||
if (!(data->config & 0x01)) {
|
if (!(data->config & 0x01)) {
|
||||||
@@ -2076,7 +2130,9 @@ static int dme1737_init_device(struct device *dev)
|
|||||||
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
|
data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
|
||||||
|
|
||||||
/* Set VRM */
|
/* Set VRM */
|
||||||
|
if (data->type != sch5027) {
|
||||||
data->vrm = vid_which_vrm();
|
data->vrm = vid_which_vrm();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2095,9 +2151,10 @@ static int dme1737_i2c_get_features(int sio_cip, struct dme1737_data *data)
|
|||||||
dme1737_sio_enter(sio_cip);
|
dme1737_sio_enter(sio_cip);
|
||||||
|
|
||||||
/* Check device ID
|
/* Check device ID
|
||||||
* The DME1737 can return either 0x78 or 0x77 as its device ID. */
|
* The DME1737 can return either 0x78 or 0x77 as its device ID.
|
||||||
|
* The SCH5027 returns 0x89 as its device ID. */
|
||||||
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
reg = force_id ? force_id : dme1737_sio_inb(sio_cip, 0x20);
|
||||||
if (!(reg == 0x77 || reg == 0x78)) {
|
if (!(reg == 0x77 || reg == 0x78 || reg == 0x89)) {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
@@ -2166,15 +2223,24 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
|||||||
company = dme1737_read(client, DME1737_REG_COMPANY);
|
company = dme1737_read(client, DME1737_REG_COMPANY);
|
||||||
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
|
verstep = dme1737_read(client, DME1737_REG_VERSTEP);
|
||||||
|
|
||||||
if (!((company == DME1737_COMPANY_SMSC) &&
|
if (company == DME1737_COMPANY_SMSC &&
|
||||||
((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
|
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
|
||||||
|
kind = dme1737;
|
||||||
|
} else if (company == DME1737_COMPANY_SMSC &&
|
||||||
|
verstep == SCH5027_VERSTEP) {
|
||||||
|
kind = sch5027;
|
||||||
|
} else {
|
||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (kind == sch5027) {
|
||||||
|
name = "sch5027";
|
||||||
|
} else {
|
||||||
kind = dme1737;
|
kind = dme1737;
|
||||||
name = "dme1737";
|
name = "dme1737";
|
||||||
|
}
|
||||||
data->type = kind;
|
data->type = kind;
|
||||||
|
|
||||||
/* Fill in the remaining client fields and put it into the global
|
/* Fill in the remaining client fields and put it into the global
|
||||||
@@ -2187,8 +2253,9 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
|
|||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(dev, "Found a DME1737 chip at 0x%02x (rev 0x%02x).\n",
|
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
|
||||||
client->addr, verstep);
|
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
|
||||||
|
verstep);
|
||||||
|
|
||||||
/* Initialize the DME1737 chip */
|
/* Initialize the DME1737 chip */
|
||||||
if ((err = dme1737_init_device(dev))) {
|
if ((err = dme1737_init_device(dev))) {
|
||||||
@@ -2360,6 +2427,8 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
|||||||
client->addr = res->start;
|
client->addr = res->start;
|
||||||
platform_set_drvdata(pdev, data);
|
platform_set_drvdata(pdev, data);
|
||||||
|
|
||||||
|
/* Skip chip detection if module is loaded with force_id parameter */
|
||||||
|
if (!force_id) {
|
||||||
company = dme1737_read(client, DME1737_REG_COMPANY);
|
company = dme1737_read(client, DME1737_REG_COMPANY);
|
||||||
device = dme1737_read(client, DME1737_REG_DEVICE);
|
device = dme1737_read(client, DME1737_REG_DEVICE);
|
||||||
|
|
||||||
@@ -2368,7 +2437,8 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
|
|||||||
err = -ENODEV;
|
err = -ENODEV;
|
||||||
goto exit_kfree;
|
goto exit_kfree;
|
||||||
}
|
}
|
||||||
data->type = -1;
|
}
|
||||||
|
data->type = sch311x;
|
||||||
|
|
||||||
/* Fill in the remaining client fields and initialize the mutex */
|
/* Fill in the remaining client fields and initialize the mutex */
|
||||||
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
|
strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
|
||||||
|
@@ -87,8 +87,6 @@ static inline void superio_enter(int base);
|
|||||||
static inline void superio_select(int base, int ld);
|
static inline void superio_select(int base, int ld);
|
||||||
static inline void superio_exit(int base);
|
static inline void superio_exit(int base);
|
||||||
|
|
||||||
static inline u16 fan_from_reg ( u16 reg );
|
|
||||||
|
|
||||||
struct f71882fg_data {
|
struct f71882fg_data {
|
||||||
unsigned short addr;
|
unsigned short addr;
|
||||||
struct device *hwmon_dev;
|
struct device *hwmon_dev;
|
||||||
@@ -116,10 +114,6 @@ struct f71882fg_data {
|
|||||||
u8 temp_diode_open;
|
u8 temp_diode_open;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u8 f71882fg_read8(struct f71882fg_data *data, u8 reg);
|
|
||||||
static u16 f71882fg_read16(struct f71882fg_data *data, u8 reg);
|
|
||||||
static void f71882fg_write8(struct f71882fg_data *data, u8 reg, u8 val);
|
|
||||||
|
|
||||||
/* Sysfs in*/
|
/* Sysfs in*/
|
||||||
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
|
static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
|
||||||
char *buf);
|
char *buf);
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
/*
|
/*
|
||||||
hwmon-vid.c - VID/VRM/VRD voltage conversions
|
* hwmon-vid.c - VID/VRM/VRD voltage conversions
|
||||||
|
*
|
||||||
Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
|
* Copyright (c) 2004 Rudolf Marek <r.marek@assembler.cz>
|
||||||
|
*
|
||||||
Partly imported from i2c-vid.h of the lm_sensors project
|
* Partly imported from i2c-vid.h of the lm_sensors project
|
||||||
Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
|
* Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
|
||||||
With assistance from Trent Piepho <xyzzy@speakeasy.org>
|
* With assistance from Trent Piepho <xyzzy@speakeasy.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
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
(at your option) any later version.
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
@@ -27,50 +27,48 @@
|
|||||||
#include <linux/hwmon-vid.h>
|
#include <linux/hwmon-vid.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Common code for decoding VID pins.
|
* Common code for decoding VID pins.
|
||||||
|
*
|
||||||
References:
|
* References:
|
||||||
|
*
|
||||||
For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
|
* For VRM 8.4 to 9.1, "VRM x.y DC-DC Converter Design Guidelines",
|
||||||
available at http://developer.intel.com/.
|
* available at http://developer.intel.com/.
|
||||||
|
*
|
||||||
For VRD 10.0 and up, "VRD x.y Design Guide",
|
* For VRD 10.0 and up, "VRD x.y Design Guide",
|
||||||
available at http://developer.intel.com/.
|
* available at http://developer.intel.com/.
|
||||||
|
*
|
||||||
AMD Opteron processors don't follow the Intel specifications.
|
* AMD NPT 0Fh (Athlon64 & Opteron), AMD Publication 32559,
|
||||||
I'm going to "make up" 2.4 as the spec number for the Opterons.
|
* http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
|
||||||
No good reason just a mnemonic for the 24x Opteron processor
|
* Table 71. VID Code Voltages
|
||||||
series.
|
* AMD Opteron processors don't follow the Intel specifications.
|
||||||
|
* I'm going to "make up" 2.4 as the spec number for the Opterons.
|
||||||
Opteron VID encoding is:
|
* No good reason just a mnemonic for the 24x Opteron processor
|
||||||
00000 = 1.550 V
|
* series.
|
||||||
00001 = 1.525 V
|
*
|
||||||
. . . .
|
* The 17 specification is in fact Intel Mobile Voltage Positioning -
|
||||||
11110 = 0.800 V
|
* (IMVP-II). You can find more information in the datasheet of Max1718
|
||||||
11111 = 0.000 V (off)
|
* http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
|
||||||
|
*
|
||||||
The 17 specification is in fact Intel Mobile Voltage Positioning -
|
* The 13 specification corresponds to the Intel Pentium M series. There
|
||||||
(IMVP-II). You can find more information in the datasheet of Max1718
|
* doesn't seem to be any named specification for these. The conversion
|
||||||
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2452
|
* tables are detailed directly in the various Pentium M datasheets:
|
||||||
|
* http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
|
||||||
The 13 specification corresponds to the Intel Pentium M series. There
|
*
|
||||||
doesn't seem to be any named specification for these. The conversion
|
* The 14 specification corresponds to Intel Core series. There
|
||||||
tables are detailed directly in the various Pentium M datasheets:
|
* doesn't seem to be any named specification for these. The conversion
|
||||||
http://www.intel.com/design/intarch/pentiumm/docs_pentiumm.htm
|
* tables are detailed directly in the various Pentium Core datasheets:
|
||||||
|
* http://www.intel.com/design/mobile/datashts/309221.htm
|
||||||
The 14 specification corresponds to Intel Core series. There
|
*
|
||||||
doesn't seem to be any named specification for these. The conversion
|
* The 110 (VRM 11) specification corresponds to Intel Conroe based series.
|
||||||
tables are detailed directly in the various Pentium Core datasheets:
|
* http://www.intel.com/design/processor/applnots/313214.htm
|
||||||
http://www.intel.com/design/mobile/datashts/309221.htm
|
|
||||||
|
|
||||||
The 110 (VRM 11) specification corresponds to Intel Conroe based series.
|
|
||||||
http://www.intel.com/design/processor/applnots/313214.htm
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* vrm is the VRM/VRD document version multiplied by 10.
|
/*
|
||||||
val is the 4-bit or more VID code.
|
* vrm is the VRM/VRD document version multiplied by 10.
|
||||||
Returned value is in mV to avoid floating point in the kernel.
|
* val is the 4-bit or more VID code.
|
||||||
Some VID have some bits in uV scale, this is rounded to mV */
|
* Returned value is in mV to avoid floating point in the kernel.
|
||||||
|
* Some VID have some bits in uV scale, this is rounded to mV.
|
||||||
|
*/
|
||||||
int vid_from_reg(int val, u8 vrm)
|
int vid_from_reg(int val, u8 vrm)
|
||||||
{
|
{
|
||||||
int vid;
|
int vid;
|
||||||
@@ -96,9 +94,11 @@ int vid_from_reg(int val, u8 vrm)
|
|||||||
if (val < 0x02 || val > 0xb2)
|
if (val < 0x02 || val > 0xb2)
|
||||||
return 0;
|
return 0;
|
||||||
return((1600000 - (val - 2) * 6250 + 500) / 1000);
|
return((1600000 - (val - 2) * 6250 + 500) / 1000);
|
||||||
case 24: /* Opteron processor */
|
|
||||||
val &= 0x1f;
|
case 24: /* AMD NPT 0Fh (Athlon64 & Opteron) */
|
||||||
return(val == 0x1f ? 0 : 1550 - val * 25);
|
val &= 0x3f;
|
||||||
|
return (val < 32) ? 1550 - 25 * val
|
||||||
|
: 775 - (25 * (val - 31)) / 2;
|
||||||
|
|
||||||
case 91: /* VRM 9.1 */
|
case 91: /* VRM 9.1 */
|
||||||
case 90: /* VRM 9.0 */
|
case 90: /* VRM 9.0 */
|
||||||
@@ -141,8 +141,8 @@ int vid_from_reg(int val, u8 vrm)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
After this point is the code to automatically determine which
|
* After this point is the code to automatically determine which
|
||||||
VRM/VRD specification should be used depending on the CPU.
|
* VRM/VRD specification should be used depending on the CPU.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct vrm_model {
|
struct vrm_model {
|
||||||
|
@@ -151,9 +151,9 @@ static int fix_pwm_polarity;
|
|||||||
/* The IT8718F has the VID value in a different register, in Super-I/O
|
/* The IT8718F has the VID value in a different register, in Super-I/O
|
||||||
configuration space. */
|
configuration space. */
|
||||||
#define IT87_REG_VID 0x0a
|
#define IT87_REG_VID 0x0a
|
||||||
/* Warning: register 0x0b is used for something completely different in
|
/* The IT8705F and IT8712F earlier than revision 0x08 use register 0x0b
|
||||||
new chips/revisions. I suspect only 16-bit tachometer mode will work
|
for fan divisors. Later IT8712F revisions must use 16-bit tachometer
|
||||||
for these. */
|
mode. */
|
||||||
#define IT87_REG_FAN_DIV 0x0b
|
#define IT87_REG_FAN_DIV 0x0b
|
||||||
#define IT87_REG_FAN_16BIT 0x0c
|
#define IT87_REG_FAN_16BIT 0x0c
|
||||||
|
|
||||||
@@ -234,6 +234,7 @@ static const unsigned int pwm_freq[8] = {
|
|||||||
struct it87_sio_data {
|
struct it87_sio_data {
|
||||||
enum chips type;
|
enum chips type;
|
||||||
/* Values read from Super-I/O config space */
|
/* Values read from Super-I/O config space */
|
||||||
|
u8 revision;
|
||||||
u8 vid_value;
|
u8 vid_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -242,6 +243,7 @@ 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;
|
||||||
|
|
||||||
unsigned short addr;
|
unsigned short addr;
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -268,6 +270,16 @@ struct it87_data {
|
|||||||
u8 manual_pwm_ctl[3]; /* manual PWM value set by user */
|
u8 manual_pwm_ctl[3]; /* manual PWM value set by user */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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 7h == Version I.
|
||||||
|
These are the first revisions with 16bit tachometer support. */
|
||||||
|
return (data->type == it87 && data->revision >= 0x03)
|
||||||
|
|| (data->type == it8712 && data->revision >= 0x07)
|
||||||
|
|| data->type == it8716
|
||||||
|
|| data->type == it8718;
|
||||||
|
}
|
||||||
|
|
||||||
static int it87_probe(struct platform_device *pdev);
|
static int it87_probe(struct platform_device *pdev);
|
||||||
static int __devexit it87_remove(struct platform_device *pdev);
|
static int __devexit it87_remove(struct platform_device *pdev);
|
||||||
@@ -991,8 +1003,9 @@ static int __init it87_find(unsigned short *address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
|
sio_data->revision = superio_inb(DEVREV) & 0x0f;
|
||||||
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
|
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
|
||||||
chip_type, *address, superio_inb(DEVREV) & 0x0f);
|
chip_type, *address, sio_data->revision);
|
||||||
|
|
||||||
/* Read GPIO config and VID value from LDN 7 (GPIO) */
|
/* Read GPIO config and VID value from LDN 7 (GPIO) */
|
||||||
if (chip_type != IT8705F_DEVID) {
|
if (chip_type != IT8705F_DEVID) {
|
||||||
@@ -1045,6 +1058,7 @@ static int __devinit 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->name = names[sio_data->type];
|
data->name = names[sio_data->type];
|
||||||
|
|
||||||
/* Now, we do the remaining detection. */
|
/* Now, we do the remaining detection. */
|
||||||
@@ -1069,7 +1083,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
|
|||||||
goto ERROR2;
|
goto ERROR2;
|
||||||
|
|
||||||
/* Do not create fan files for disabled fans */
|
/* Do not create fan files for disabled fans */
|
||||||
if (data->type == it8716 || data->type == it8718) {
|
if (has_16bit_fans(data)) {
|
||||||
/* 16-bit tachometers */
|
/* 16-bit tachometers */
|
||||||
if (data->has_fan & (1 << 0)) {
|
if (data->has_fan & (1 << 0)) {
|
||||||
if ((err = device_create_file(dev,
|
if ((err = device_create_file(dev,
|
||||||
@@ -1350,7 +1364,7 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
|||||||
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
|
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
|
||||||
|
|
||||||
/* Set tachometers to 16-bit mode if needed */
|
/* Set tachometers to 16-bit mode if needed */
|
||||||
if (data->type == it8716 || data->type == it8718) {
|
if (has_16bit_fans(data)) {
|
||||||
tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
|
tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
|
||||||
if (~tmp & 0x07 & data->has_fan) {
|
if (~tmp & 0x07 & data->has_fan) {
|
||||||
dev_dbg(&pdev->dev,
|
dev_dbg(&pdev->dev,
|
||||||
@@ -1358,11 +1372,14 @@ static void __devinit it87_init_device(struct platform_device *pdev)
|
|||||||
it87_write_value(data, IT87_REG_FAN_16BIT,
|
it87_write_value(data, IT87_REG_FAN_16BIT,
|
||||||
tmp | 0x07);
|
tmp | 0x07);
|
||||||
}
|
}
|
||||||
|
/* IT8705F only supports three fans. */
|
||||||
|
if (data->type != it87) {
|
||||||
if (tmp & (1 << 4))
|
if (tmp & (1 << 4))
|
||||||
data->has_fan |= (1 << 3); /* fan4 enabled */
|
data->has_fan |= (1 << 3); /* fan4 enabled */
|
||||||
if (tmp & (1 << 5))
|
if (tmp & (1 << 5))
|
||||||
data->has_fan |= (1 << 4); /* fan5 enabled */
|
data->has_fan |= (1 << 4); /* fan5 enabled */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Set current fan mode registers and the default settings for the
|
/* Set current fan mode registers and the default settings for the
|
||||||
* other mode registers */
|
* other mode registers */
|
||||||
@@ -1426,7 +1443,7 @@ static struct it87_data *it87_update_device(struct device *dev)
|
|||||||
data->fan[i] = it87_read_value(data,
|
data->fan[i] = 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 (data->type == it8716 || data->type == it8718) {
|
if (has_16bit_fans(data)) {
|
||||||
data->fan[i] |= it87_read_value(data,
|
data->fan[i] |= it87_read_value(data,
|
||||||
IT87_REG_FANX[i]) << 8;
|
IT87_REG_FANX[i]) << 8;
|
||||||
data->fan_min[i] |= it87_read_value(data,
|
data->fan_min[i] |= it87_read_value(data,
|
||||||
@@ -1443,8 +1460,7 @@ static struct it87_data *it87_update_device(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Newer chips don't have clock dividers */
|
/* Newer chips don't have clock dividers */
|
||||||
if ((data->has_fan & 0x07) && data->type != it8716
|
if ((data->has_fan & 0x07) && !has_16bit_fans(data)) {
|
||||||
&& data->type != it8718) {
|
|
||||||
i = it87_read_value(data, IT87_REG_FAN_DIV);
|
i = it87_read_value(data, IT87_REG_FAN_DIV);
|
||||||
data->fan_div[0] = i & 0x07;
|
data->fan_div[0] = i & 0x07;
|
||||||
data->fan_div[1] = (i >> 3) & 0x07;
|
data->fan_div[1] = (i >> 3) & 0x07;
|
||||||
@@ -1460,7 +1476,8 @@ static struct it87_data *it87_update_device(struct device *dev)
|
|||||||
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
|
data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
|
||||||
|
|
||||||
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
|
||||||
/* The 8705 does not have VID capability */
|
/* The 8705 does not have VID capability.
|
||||||
|
The 8718 does not use IT87_REG_VID for the same purpose. */
|
||||||
if (data->type == it8712 || data->type == it8716) {
|
if (data->type == it8712 || data->type == it8716) {
|
||||||
data->vid = it87_read_value(data, IT87_REG_VID);
|
data->vid = it87_read_value(data, IT87_REG_VID);
|
||||||
/* The older IT8712F revisions had only 5 VID pins,
|
/* The older IT8712F revisions had only 5 VID pins,
|
||||||
|
@@ -55,8 +55,11 @@ I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
|
|||||||
static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
|
static const u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
|
||||||
static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
|
static const u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
|
||||||
static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
|
static const u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
|
||||||
|
static const u8 THMC50_REG_TEMP_CRITICAL[] = { 0x13, 0x14, 0x14 };
|
||||||
|
static const u8 THMC50_REG_TEMP_DEFAULT[] = { 0x17, 0x18, 0x18 };
|
||||||
|
|
||||||
#define THMC50_REG_CONF_nFANOFF 0x20
|
#define THMC50_REG_CONF_nFANOFF 0x20
|
||||||
|
#define THMC50_REG_CONF_PROGRAMMED 0x08
|
||||||
|
|
||||||
/* Each client has this additional data */
|
/* Each client has this additional data */
|
||||||
struct thmc50_data {
|
struct thmc50_data {
|
||||||
@@ -72,6 +75,7 @@ struct thmc50_data {
|
|||||||
s8 temp_input[3];
|
s8 temp_input[3];
|
||||||
s8 temp_max[3];
|
s8 temp_max[3];
|
||||||
s8 temp_min[3];
|
s8 temp_min[3];
|
||||||
|
s8 temp_critical[3];
|
||||||
u8 analog_out;
|
u8 analog_out;
|
||||||
u8 alarms;
|
u8 alarms;
|
||||||
};
|
};
|
||||||
@@ -199,6 +203,15 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t show_temp_critical(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
int nr = to_sensor_dev_attr(attr)->index;
|
||||||
|
struct thmc50_data *data = thmc50_update_device(dev);
|
||||||
|
return sprintf(buf, "%d\n", data->temp_critical[nr] * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
@@ -214,7 +227,9 @@ static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp, \
|
|||||||
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR, \
|
||||||
show_temp_min, set_temp_min, offset - 1); \
|
show_temp_min, set_temp_min, offset - 1); \
|
||||||
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
|
||||||
show_temp_max, set_temp_max, offset - 1);
|
show_temp_max, set_temp_max, offset - 1); \
|
||||||
|
static SENSOR_DEVICE_ATTR(temp##offset##_crit, S_IRUGO, \
|
||||||
|
show_temp_critical, NULL, offset - 1);
|
||||||
|
|
||||||
temp_reg(1);
|
temp_reg(1);
|
||||||
temp_reg(2);
|
temp_reg(2);
|
||||||
@@ -234,10 +249,12 @@ static struct attribute *thmc50_attributes[] = {
|
|||||||
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
&sensor_dev_attr_temp1_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
&sensor_dev_attr_temp1_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp1_crit.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
&sensor_dev_attr_temp2_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
&sensor_dev_attr_temp2_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
&sensor_dev_attr_temp2_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp2_crit.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
&sensor_dev_attr_temp2_fault.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm1.dev_attr.attr,
|
&sensor_dev_attr_pwm1.dev_attr.attr,
|
||||||
@@ -254,6 +271,7 @@ static struct attribute *temp3_attributes[] = {
|
|||||||
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
&sensor_dev_attr_temp3_max.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
&sensor_dev_attr_temp3_min.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
&sensor_dev_attr_temp3_input.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_temp3_crit.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
|
||||||
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
&sensor_dev_attr_temp3_fault.dev_attr.attr,
|
||||||
NULL
|
NULL
|
||||||
@@ -429,6 +447,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
|
|||||||
|
|
||||||
int temps = data->has_temp3 ? 3 : 2;
|
int temps = data->has_temp3 ? 3 : 2;
|
||||||
int i;
|
int i;
|
||||||
|
int prog = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
|
||||||
|
|
||||||
|
prog &= THMC50_REG_CONF_PROGRAMMED;
|
||||||
|
|
||||||
for (i = 0; i < temps; i++) {
|
for (i = 0; i < temps; i++) {
|
||||||
data->temp_input[i] = i2c_smbus_read_byte_data(client,
|
data->temp_input[i] = i2c_smbus_read_byte_data(client,
|
||||||
THMC50_REG_TEMP[i]);
|
THMC50_REG_TEMP[i]);
|
||||||
@@ -436,6 +458,10 @@ static struct thmc50_data *thmc50_update_device(struct device *dev)
|
|||||||
THMC50_REG_TEMP_MAX[i]);
|
THMC50_REG_TEMP_MAX[i]);
|
||||||
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
data->temp_min[i] = i2c_smbus_read_byte_data(client,
|
||||||
THMC50_REG_TEMP_MIN[i]);
|
THMC50_REG_TEMP_MIN[i]);
|
||||||
|
data->temp_critical[i] =
|
||||||
|
i2c_smbus_read_byte_data(client,
|
||||||
|
prog ? THMC50_REG_TEMP_CRITICAL[i]
|
||||||
|
: THMC50_REG_TEMP_DEFAULT[i]);
|
||||||
}
|
}
|
||||||
data->analog_out =
|
data->analog_out =
|
||||||
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
|
i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
|
||||||
|
@@ -67,10 +67,6 @@ module_param(force_i2c, byte, 0);
|
|||||||
MODULE_PARM_DESC(force_i2c,
|
MODULE_PARM_DESC(force_i2c,
|
||||||
"Initialize the i2c address of the sensors");
|
"Initialize the i2c address of the sensors");
|
||||||
|
|
||||||
static int reset;
|
|
||||||
module_param(reset, bool, 0);
|
|
||||||
MODULE_PARM_DESC(reset, "Set to one to reset chip on load");
|
|
||||||
|
|
||||||
static int init = 1;
|
static int init = 1;
|
||||||
module_param(init, bool, 0);
|
module_param(init, bool, 0);
|
||||||
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
|
MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");
|
||||||
@@ -209,6 +205,13 @@ static const u16 w83627hf_reg_temp_over[] = { 0x39, 0x155, 0x255 };
|
|||||||
#define W83627HF_REG_PWM1 0x5A
|
#define W83627HF_REG_PWM1 0x5A
|
||||||
#define W83627HF_REG_PWM2 0x5B
|
#define W83627HF_REG_PWM2 0x5B
|
||||||
|
|
||||||
|
static const u8 W83627THF_REG_PWM_ENABLE[] = {
|
||||||
|
0x04, /* FAN 1 mode */
|
||||||
|
0x04, /* FAN 2 mode */
|
||||||
|
0x12, /* FAN AUX mode */
|
||||||
|
};
|
||||||
|
static const u8 W83627THF_PWM_ENABLE_SHIFT[] = { 2, 4, 1 };
|
||||||
|
|
||||||
#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
|
#define W83627THF_REG_PWM1 0x01 /* 697HF/637HF/687THF too */
|
||||||
#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
|
#define W83627THF_REG_PWM2 0x03 /* 697HF/637HF/687THF too */
|
||||||
#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
|
#define W83627THF_REG_PWM3 0x11 /* 637HF/687THF too */
|
||||||
@@ -366,6 +369,9 @@ struct w83627hf_data {
|
|||||||
u32 alarms; /* Register encoding, combined */
|
u32 alarms; /* Register encoding, combined */
|
||||||
u32 beep_mask; /* Register encoding, combined */
|
u32 beep_mask; /* Register encoding, combined */
|
||||||
u8 pwm[3]; /* Register value */
|
u8 pwm[3]; /* Register value */
|
||||||
|
u8 pwm_enable[3]; /* 1 = manual
|
||||||
|
2 = thermal cruise (also called SmartFan I)
|
||||||
|
3 = fan speed cruise */
|
||||||
u8 pwm_freq[3]; /* Register value */
|
u8 pwm_freq[3]; /* Register value */
|
||||||
u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
|
u16 sens[3]; /* 1 = pentium diode; 2 = 3904 diode;
|
||||||
4 = thermistor */
|
4 = thermistor */
|
||||||
@@ -956,6 +962,42 @@ static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0);
|
|||||||
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
|
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 1);
|
||||||
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
|
static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 2);
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
show_pwm_enable(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||||
|
{
|
||||||
|
int nr = to_sensor_dev_attr(devattr)->index;
|
||||||
|
struct w83627hf_data *data = w83627hf_update_device(dev);
|
||||||
|
return sprintf(buf, "%d\n", data->pwm_enable[nr]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
store_pwm_enable(struct device *dev, struct device_attribute *devattr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
int nr = to_sensor_dev_attr(devattr)->index;
|
||||||
|
struct w83627hf_data *data = dev_get_drvdata(dev);
|
||||||
|
unsigned long val = simple_strtoul(buf, NULL, 10);
|
||||||
|
u8 reg;
|
||||||
|
|
||||||
|
if (!val || (val > 3)) /* modes 1, 2 and 3 are supported */
|
||||||
|
return -EINVAL;
|
||||||
|
mutex_lock(&data->update_lock);
|
||||||
|
data->pwm_enable[nr] = val;
|
||||||
|
reg = w83627hf_read_value(data, W83627THF_REG_PWM_ENABLE[nr]);
|
||||||
|
reg &= ~(0x03 << W83627THF_PWM_ENABLE_SHIFT[nr]);
|
||||||
|
reg |= (val - 1) << W83627THF_PWM_ENABLE_SHIFT[nr];
|
||||||
|
w83627hf_write_value(data, W83627THF_REG_PWM_ENABLE[nr], reg);
|
||||||
|
mutex_unlock(&data->update_lock);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
|
||||||
|
store_pwm_enable, 0);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
|
||||||
|
store_pwm_enable, 1);
|
||||||
|
static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
|
||||||
|
store_pwm_enable, 2);
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
|
show_pwm_freq(struct device *dev, struct device_attribute *devattr, char *buf)
|
||||||
{
|
{
|
||||||
@@ -1223,6 +1265,11 @@ static struct attribute *w83627hf_attributes_opt[] = {
|
|||||||
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm1_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm2_freq.dev_attr.attr,
|
||||||
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
&sensor_dev_attr_pwm3_freq.dev_attr.attr,
|
||||||
|
|
||||||
|
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm2_enable.dev_attr.attr,
|
||||||
|
&sensor_dev_attr_pwm3_enable.dev_attr.attr,
|
||||||
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1366,6 +1413,19 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|
|||||||
&sensor_dev_attr_pwm3_freq.dev_attr)))
|
&sensor_dev_attr_pwm3_freq.dev_attr)))
|
||||||
goto ERROR4;
|
goto ERROR4;
|
||||||
|
|
||||||
|
if (data->type != w83627hf)
|
||||||
|
if ((err = device_create_file(dev,
|
||||||
|
&sensor_dev_attr_pwm1_enable.dev_attr))
|
||||||
|
|| (err = device_create_file(dev,
|
||||||
|
&sensor_dev_attr_pwm2_enable.dev_attr)))
|
||||||
|
goto ERROR4;
|
||||||
|
|
||||||
|
if (data->type == w83627thf || data->type == w83637hf
|
||||||
|
|| data->type == w83687thf)
|
||||||
|
if ((err = device_create_file(dev,
|
||||||
|
&sensor_dev_attr_pwm3_enable.dev_attr)))
|
||||||
|
goto ERROR4;
|
||||||
|
|
||||||
data->hwmon_dev = hwmon_device_register(dev);
|
data->hwmon_dev = hwmon_device_register(dev);
|
||||||
if (IS_ERR(data->hwmon_dev)) {
|
if (IS_ERR(data->hwmon_dev)) {
|
||||||
err = PTR_ERR(data->hwmon_dev);
|
err = PTR_ERR(data->hwmon_dev);
|
||||||
@@ -1536,29 +1596,6 @@ static void __devinit w83627hf_init_device(struct platform_device *pdev)
|
|||||||
enum chips type = data->type;
|
enum chips type = data->type;
|
||||||
u8 tmp;
|
u8 tmp;
|
||||||
|
|
||||||
if (reset) {
|
|
||||||
/* Resetting the chip has been the default for a long time,
|
|
||||||
but repeatedly caused problems (fans going to full
|
|
||||||
speed...) so it is now optional. It might even go away if
|
|
||||||
nobody reports it as being useful, as I see very little
|
|
||||||
reason why this would be needed at all. */
|
|
||||||
dev_info(&pdev->dev, "If reset=1 solved a problem you were "
|
|
||||||
"having, please report!\n");
|
|
||||||
|
|
||||||
/* save this register */
|
|
||||||
i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);
|
|
||||||
/* Reset all except Watchdog values and last conversion values
|
|
||||||
This sets fan-divs to 2, among others */
|
|
||||||
w83627hf_write_value(data, W83781D_REG_CONFIG, 0x80);
|
|
||||||
/* Restore the register and disable power-on abnormal beep.
|
|
||||||
This saves FAN 1/2/3 input/output values set by BIOS. */
|
|
||||||
w83627hf_write_value(data, W83781D_REG_BEEP_CONFIG, i | 0x80);
|
|
||||||
/* Disable master beep-enable (reset turns it on).
|
|
||||||
Individual beeps should be reset to off but for some reason
|
|
||||||
disabling this bit helps some people not get beeped */
|
|
||||||
w83627hf_write_value(data, W83781D_REG_BEEP_INTS2, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 */
|
||||||
@@ -1655,6 +1692,7 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct w83627hf_data *data = dev_get_drvdata(dev);
|
struct w83627hf_data *data = dev_get_drvdata(dev);
|
||||||
int i, num_temps = (data->type == w83697hf) ? 2 : 3;
|
int i, num_temps = (data->type == w83697hf) ? 2 : 3;
|
||||||
|
int num_pwms = (data->type == w83697hf) ? 2 : 3;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
@@ -1707,6 +1745,15 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (data->type != w83627hf) {
|
||||||
|
for (i = 0; i < num_pwms; i++) {
|
||||||
|
u8 tmp = w83627hf_read_value(data,
|
||||||
|
W83627THF_REG_PWM_ENABLE[i]);
|
||||||
|
data->pwm_enable[i] =
|
||||||
|
((tmp >> W83627THF_PWM_ENABLE_SHIFT[i])
|
||||||
|
& 0x03) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (i = 0; i < num_temps; i++) {
|
for (i = 0; i < num_temps; i++) {
|
||||||
data->temp[i] = w83627hf_read_value(
|
data->temp[i] = w83627hf_read_value(
|
||||||
data, w83627hf_reg_temp[i]);
|
data, w83627hf_reg_temp[i]);
|
||||||
|
@@ -233,11 +233,9 @@ static u8 fan_to_reg(long rpm, int div)
|
|||||||
static u8 div_to_reg(int nr, long val)
|
static u8 div_to_reg(int nr, long val)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int max;
|
|
||||||
|
|
||||||
/* first three fan's divisor max out at 8, rest max out at 128 */
|
/* fan divisors max out at 128 */
|
||||||
max = (nr < 3) ? 8 : 128;
|
val = SENSORS_LIMIT(val, 1, 128) >> 1;
|
||||||
val = SENSORS_LIMIT(val, 1, max) >> 1;
|
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
if (val == 0)
|
if (val == 0)
|
||||||
break;
|
break;
|
||||||
@@ -530,6 +528,7 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
|
|||||||
unsigned long min;
|
unsigned long min;
|
||||||
u8 tmp_fan_div;
|
u8 tmp_fan_div;
|
||||||
u8 fan_div_reg;
|
u8 fan_div_reg;
|
||||||
|
u8 vbat_reg;
|
||||||
int indx = 0;
|
int indx = 0;
|
||||||
u8 keep_mask = 0;
|
u8 keep_mask = 0;
|
||||||
u8 new_shift = 0;
|
u8 new_shift = 0;
|
||||||
@@ -581,6 +580,16 @@ static ssize_t store_fan_div(struct device *dev, struct device_attribute *attr,
|
|||||||
w83791d_write(client, W83791D_REG_FAN_DIV[indx],
|
w83791d_write(client, W83791D_REG_FAN_DIV[indx],
|
||||||
fan_div_reg | tmp_fan_div);
|
fan_div_reg | tmp_fan_div);
|
||||||
|
|
||||||
|
/* Bit 2 of fans 0-2 is stored in the vbat register (bits 5-7) */
|
||||||
|
if (nr < 3) {
|
||||||
|
keep_mask = ~(1 << (nr + 5));
|
||||||
|
vbat_reg = w83791d_read(client, W83791D_REG_VBAT)
|
||||||
|
& keep_mask;
|
||||||
|
tmp_fan_div = (data->fan_div[nr] << (3 + nr)) & ~keep_mask;
|
||||||
|
w83791d_write(client, W83791D_REG_VBAT,
|
||||||
|
vbat_reg | tmp_fan_div);
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore fan_min */
|
/* Restore fan_min */
|
||||||
data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
|
data->fan_min[nr] = fan_to_reg(min, DIV_FROM_REG(data->fan_div[nr]));
|
||||||
w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
|
w83791d_write(client, W83791D_REG_FAN_MIN[nr], data->fan_min[nr]);
|
||||||
@@ -1182,6 +1191,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
|
|||||||
struct w83791d_data *data = i2c_get_clientdata(client);
|
struct w83791d_data *data = i2c_get_clientdata(client);
|
||||||
int i, j;
|
int i, j;
|
||||||
u8 reg_array_tmp[3];
|
u8 reg_array_tmp[3];
|
||||||
|
u8 vbat_reg;
|
||||||
|
|
||||||
mutex_lock(&data->update_lock);
|
mutex_lock(&data->update_lock);
|
||||||
|
|
||||||
@@ -1219,6 +1229,12 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
|
|||||||
data->fan_div[3] = reg_array_tmp[2] & 0x07;
|
data->fan_div[3] = reg_array_tmp[2] & 0x07;
|
||||||
data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
|
data->fan_div[4] = (reg_array_tmp[2] >> 4) & 0x07;
|
||||||
|
|
||||||
|
/* The fan divisor for fans 0-2 get bit 2 from
|
||||||
|
bits 5-7 respectively of vbat register */
|
||||||
|
vbat_reg = w83791d_read(client, W83791D_REG_VBAT);
|
||||||
|
for (i = 0; i < 3; i++)
|
||||||
|
data->fan_div[i] |= (vbat_reg >> (3 + i)) & 0x04;
|
||||||
|
|
||||||
/* Update the first temperature sensor */
|
/* Update the first temperature sensor */
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
data->temp1[i] = w83791d_read(client,
|
data->temp1[i] = w83791d_read(client,
|
||||||
|
Reference in New Issue
Block a user