diff options
51 files changed, 1534 insertions, 120 deletions
diff --git a/Documentation/hwmon/adt7473 b/Documentation/hwmon/adt7473 new file mode 100644 index 00000000000..22d8b19046a --- /dev/null +++ b/Documentation/hwmon/adt7473 @@ -0,0 +1,79 @@ +Kernel driver adt7473 +====================== + +Supported chips: + * Analog Devices ADT7473 + Prefix: 'adt7473' + Addresses scanned: I2C 0x2C, 0x2D, 0x2E + Datasheet: Publicly available at the Analog Devices website + +Author: Darrick J. Wong + +Description +----------- + +This driver implements support for the Analog Devices ADT7473 chip family. + +The LM85 uses the 2-wire interface compatible with the SMBUS 2.0 +specification. Using an analog to digital converter it measures three (3) +temperatures and two (2) voltages. It has three (3) 16-bit counters for +measuring fan speed. There are three (3) PWM outputs that can be used +to control fan speed. + +A sophisticated control system for the PWM outputs is designed into the +LM85 that allows fan speed to be adjusted automatically based on any of the +three temperature sensors. Each PWM output is individually adjustable and +programmable. Once configured, the ADT7473 will adjust the PWM outputs in +response to the measured temperatures without further host intervention. +This feature can also be disabled for manual control of the PWM's. + +Each of the measured inputs (voltage, temperature, fan speed) has +corresponding high/low limit values. The ADT7473 will signal an ALARM if +any measured value exceeds either limit. + +The ADT7473 samples all inputs continuously. The driver will not read +the registers more often than once every other second. Further, +configuration data is only read once per minute. + +Special Features +---------------- + +The ADT7473 have a 10-bit ADC and can therefore measure temperatures +with 0.25 degC resolution. Temperature readings can be configured either +for twos complement format or "Offset 64" format, wherein 63 is subtracted +from the raw value to get the temperature value. + +The Analog Devices datasheet is very detailed and describes a procedure for +determining an optimal configuration for the automatic PWM control. + +Hardware Configurations +----------------------- + +The ADT7473 chips have an optional SMBALERT output that can be used to +signal the chipset in case a limit is exceeded or the temperature sensors +fail. Individual sensor interrupts can be masked so they won't trigger +SMBALERT. The SMBALERT output if configured replaces the PWM2 function. + +Configuration Notes +------------------- + +Besides standard interfaces driver adds the following: + +* PWM Control + +* pwm#_auto_point1_pwm and pwm#_auto_point1_temp and +* pwm#_auto_point2_pwm and pwm#_auto_point2_temp - + +point1: Set the pwm speed at a lower temperature bound. +point2: Set the pwm speed at a higher temperature bound. + +The ADT7473 will scale the pwm between the lower and higher pwm speed when +the temperature is between the two temperature boundaries. PWM values range +from 0 (off) to 255 (full speed). + +Notes +----- + +The NVIDIA binary driver presents an ADT7473 chip via an on-card i2c bus. +Unfortunately, they fail to set the i2c adapter class, so this driver may +fail to find the chip until the nvidia driver is patched. diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp index 170bf862437..dbbe6c7025b 100644 --- a/Documentation/hwmon/coretemp +++ b/Documentation/hwmon/coretemp @@ -4,9 +4,10 @@ Kernel driver coretemp Supported chips: * All Intel Core family Prefix: 'coretemp' - CPUID: family 0x6, models 0xe, 0xf, 0x16 + CPUID: family 0x6, models 0xe, 0xf, 0x16, 0x17 Datasheet: Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3A: System Programming Guide + http://softwarecommunity.intel.com/Wiki/Mobility/720.htm Author: Rudolf Marek @@ -25,7 +26,8 @@ may be raised, if the temperature grows enough (more than TjMax) to trigger the Out-Of-Spec bit. Following table summarizes the exported sysfs files: temp1_input - Core temperature (in millidegrees Celsius). -temp1_crit - Maximum junction temperature (in millidegrees Celsius). +temp1_max - All cooling devices should be turned on (on Core2). +temp1_crit - Maximum junction temperature (in millidegrees Celsius). temp1_crit_alarm - Set when Out-of-spec bit is set, never clears. Correct CPU operation is no longer guaranteed. temp1_label - Contains string "Core X", where X is processor diff --git a/MAINTAINERS b/MAINTAINERS index fd81e0672c0..962babe226c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4261,7 +4261,7 @@ S: Maintained VT8231 HARDWARE MONITOR DRIVER P: Roger Lucas -M: roger@planbit.co.uk +M: vt8231@hiddenengine.co.uk L: lm-sensors@lm-sensors.org S: Maintained diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 410ffe4e9d8..368879ff5d8 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -143,6 +143,16 @@ config SENSORS_ADT7470 This driver can also be built as a module. If so, the module will be called adt7470. +config SENSORS_ADT7473 + tristate "Analog Devices ADT7473" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Analog Devices + ADT7473 temperature monitoring chips. + + This driver can also be built as a module. If so, the module + will be called adt7473. + config SENSORS_K8TEMP tristate "AMD Athlon64/FX or Opteron temperature sensor" depends on X86 && PCI && EXPERIMENTAL diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 824161337f1..3bdb05a5cbd 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o +obj-$(CONFIG_SENSORS_ADT7473) += adt7473.o obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o obj-$(CONFIG_SENSORS_AMS) += ams/ obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o diff --git a/drivers/hwmon/ad7418.c b/drivers/hwmon/ad7418.c index fcd7fe78f3f..466b9ee9279 100644 --- a/drivers/hwmon/ad7418.c +++ b/drivers/hwmon/ad7418.c @@ -26,7 +26,7 @@ #define DRV_VERSION "0.3" /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x28, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_3(ad7416, ad7417, ad7418); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index b96be772e49..ecbf69484bf 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -31,10 +31,8 @@ /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a, - 0x29, 0x2a, 0x2b, - 0x4c, 0x4d, 0x4e, - I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { + 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b, 0x4c, 0x4d, 0x4e, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_8(adm1021, adm1023, max1617, max1617a, thmc10, lm84, gl523sm, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index e96c3725203..1d76de7d75c 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -62,7 +62,7 @@ * NE1619 has two possible addresses: 0x2c and 0x2d. */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* * Insmod parameters diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index 8002f68240c..904c6ce9d83 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -35,7 +35,7 @@ #include <linux/mutex.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(adm1026); @@ -1624,6 +1624,7 @@ static struct attribute *adm1026_attributes_temp3[] = { &dev_attr_temp3_crit_enable.attr, &dev_attr_temp3_auto_point1_pwm.attr, &dev_attr_temp3_auto_point2_pwm.attr, + NULL }; static const struct attribute_group adm1026_group_temp3 = { @@ -1639,6 +1640,7 @@ static struct attribute *adm1026_attributes_in8_9[] = { &sensor_dev_attr_in9_max.dev_attr.attr, &sensor_dev_attr_in9_min.dev_attr.attr, &sensor_dev_attr_in9_alarm.dev_attr.attr, + NULL }; static const struct attribute_group adm1026_group_in8_9 = { diff --git a/drivers/hwmon/adm1029.c b/drivers/hwmon/adm1029.c index 0bc897dffa2..2c6608d453c 100644 --- a/drivers/hwmon/adm1029.c +++ b/drivers/hwmon/adm1029.c @@ -39,10 +39,8 @@ * Addresses to scan */ -static unsigned short normal_i2c[] = { - 0x28, 0x29, 0x2a, - 0x2b, 0x2c, 0x2d, - 0x2e, 0x2f, I2C_CLIENT_END +static const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, + 0x2e, 0x2f, I2C_CLIENT_END }; /* diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index 5aaad3636c9..2bffcab7dc9 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -61,7 +61,7 @@ #define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_2(adm1030, adm1031); diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 7671d2bf780..149ef25252e 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -52,7 +52,7 @@ #include <linux/mutex.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, +static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END }; /* Insmod parameters */ diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 6b8a73ef404..ed71a8bc70d 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -44,7 +44,7 @@ #define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, +static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, I2C_CLIENT_END }; /* Insmod parameters */ diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index 747693ab2ff..6b5325f33a2 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -30,7 +30,7 @@ #include <linux/log2.h> /* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; /* Insmod parameters */ I2C_CLIENT_INSMOD_1(adt7470); diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c new file mode 100644 index 00000000000..9587869bdba --- /dev/null +++ b/drivers/hwmon/adt7473.c @@ -0,0 +1,1157 @@ +/* + * A hwmon driver for the Analog Devices ADT7473 + * Copyright (C) 2007 IBM + * + * Author: Darrick J. Wong <djwong@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#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/delay.h> +#include <linux/log2.h> + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { 0x2C, 0x2D, 0x2E, I2C_CLIENT_END }; + +/* Insmod parameters */ +I2C_CLIENT_INSMOD_1(adt7473); + +/* ADT7473 registers */ +#define ADT7473_REG_BASE_ADDR 0x20 + +#define ADT7473_REG_VOLT_BASE_ADDR 0x21 +#define ADT7473_REG_VOLT_MAX_ADDR 0x22 +#define ADT7473_REG_VOLT_MIN_BASE_ADDR 0x46 +#define ADT7473_REG_VOLT_MIN_MAX_ADDR 0x49 + +#define ADT7473_REG_TEMP_BASE_ADDR 0x25 +#define ADT7473_REG_TEMP_MAX_ADDR 0x27 +#define ADT7473_REG_TEMP_LIMITS_BASE_ADDR 0x4E +#define ADT7473_REG_TEMP_LIMITS_MAX_ADDR 0x53 +#define ADT7473_REG_TEMP_TMIN_BASE_ADDR 0x67 +#define ADT7473_REG_TEMP_TMIN_MAX_ADDR 0x69 +#define ADT7473_REG_TEMP_TMAX_BASE_ADDR 0x6A +#define ADT7473_REG_TEMP_TMAX_MAX_ADDR 0x6C + +#define ADT7473_REG_FAN_BASE_ADDR 0x28 +#define ADT7473_REG_FAN_MAX_ADDR 0x2F +#define ADT7473_REG_FAN_MIN_BASE_ADDR 0x54 +#define ADT7473_REG_FAN_MIN_MAX_ADDR 0x5B + +#define ADT7473_REG_PWM_BASE_ADDR 0x30 +#define ADT7473_REG_PWM_MAX_ADDR 0x32 +#define ADT7473_REG_PWM_MIN_BASE_ADDR 0x64 +#define ADT7473_REG_PWM_MIN_MAX_ADDR 0x66 +#define ADT7473_REG_PWM_MAX_BASE_ADDR 0x38 +#define ADT7473_REG_PWM_MAX_MAX_ADDR 0x3A +#define ADT7473_REG_PWM_BHVR_BASE_ADDR 0x5C +#define ADT7473_REG_PWM_BHVR_MAX_ADDR 0x5E +#define ADT7473_PWM_BHVR_MASK 0xE0 +#define ADT7473_PWM_BHVR_SHIFT 5 + +#define ADT7473_REG_CFG1 0x40 +#define ADT7473_CFG1_START 0x01 +#define ADT7473_CFG1_READY 0x04 +#define ADT7473_REG_CFG2 0x73 +#define ADT7473_REG_CFG3 0x78 +#define ADT7473_REG_CFG4 0x7D +#define ADT7473_CFG4_MAX_DUTY_AT_OVT 0x08 +#define ADT7473_REG_CFG5 0x7C +#define ADT7473_CFG5_TEMP_TWOS 0x01 +#define ADT7473_CFG5_TEMP_OFFSET 0x02 + +#define ADT7473_REG_DEVICE 0x3D +#define ADT7473_VENDOR 0x41 +#define ADT7473_REG_VENDOR 0x3E +#define ADT7473_DEVICE 0x73 +#define ADT7473_REG_REVISION 0x3F +#define ADT7473_REV_68 0x68 +#define ADT7473_REV_69 0x69 + +#define ADT7473_REG_ALARM1 0x41 +#define ADT7473_VCCP_ALARM 0x02 +#define ADT7473_VCC_ALARM 0x04 +#define ADT7473_R1T_ALARM 0x10 +#define ADT7473_LT_ALARM 0x20 +#define ADT7473_R2T_ALARM 0x40 +#define ADT7473_OOL 0x80 +#define ADT7473_REG_ALARM2 0x42 +#define ADT7473_OVT_ALARM 0x02 +#define ADT7473_FAN1_ALARM 0x04 +#define ADT7473_FAN2_ALARM 0x08 +#define ADT7473_FAN3_ALARM 0x10 +#define ADT7473_FAN4_ALARM 0x20 +#define ADT7473_R1T_SHORT 0x40 +#define ADT7473_R2T_SHORT 0x80 +#define ADT7473_REG_MAX_ADDR 0x80 + +#define ALARM2(x) ((x) << 8) + +#define ADT7473_VOLT_COUNT 2 +#define ADT7473_REG_VOLT(x) (ADT7473_REG_VOLT_BASE_ADDR + (x)) +#define ADT7473_REG_VOLT_MIN(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + ((x) * 2)) +#define ADT7473_REG_VOLT_MAX(x) (ADT7473_REG_VOLT_MIN_BASE_ADDR + \ + ((x) * 2) + 1) + +#define ADT7473_TEMP_COUNT 3 +#define ADT7473_REG_TEMP(x) (ADT7473_REG_TEMP_BASE_ADDR + (x)) +#define ADT7473_REG_TEMP_MIN(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2)) +#define ADT7473_REG_TEMP_MAX(x) (ADT7473_REG_TEMP_LIMITS_BASE_ADDR + \ + ((x) * 2) + 1) +#define ADT7473_REG_TEMP_TMIN(x) (ADT7473_REG_TEMP_TMIN_BASE_ADDR + (x)) +#define ADT7473_REG_TEMP_TMAX(x) (ADT7473_REG_TEMP_TMAX_BASE_ADDR + (x)) + +#define ADT7473_FAN_COUNT 4 +#define ADT7473_REG_FAN(x) (ADT7473_REG_FAN_BASE_ADDR + ((x) * 2)) +#define ADT7473_REG_FAN_MIN(x) (ADT7473_REG_FAN_MIN_BASE_ADDR + ((x) * 2)) + +#define ADT7473_PWM_COUNT 3 +#define ADT7473_REG_PWM(x) (ADT7473_REG_PWM_BASE_ADDR + (x)) +#define ADT7473_REG_PWM_MAX(x) (ADT7473_REG_PWM_MAX_BASE_ADDR + (x)) +#define ADT7473_REG_PWM_MIN(x) (ADT7473_REG_PWM_MIN_BASE_ADDR + (x)) +#define ADT7473_REG_PWM_BHVR(x) (ADT7473_REG_PWM_BHVR_BASE_ADDR + (x)) + +/* How often do we reread sensors values? (In jiffies) */ +#define SENSOR_REFRESH_INTERVAL (2 * HZ) + +/* How often do we reread sensor limit values? (In jiffies) */ +#define LIMIT_REFRESH_INTERVAL (60 * HZ) + +/* datasheet says to divide this number by the fan reading to get fan rpm */ +#define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) +#define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM +#define FAN_PERIOD_INVALID 65535 +#define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) + +struct adt7473_data { + struct i2c_client client; + struct device *hwmon_dev; + struct attribute_group attrs; + struct mutex lock; + char sensors_valid; + char limits_valid; + unsigned long sensors_last_updated; /* In jiffies */ + unsigned long limits_last_updated; /* In jiffies */ + + u8 volt[ADT7473_VOLT_COUNT]; + s8 volt_min[ADT7473_VOLT_COUNT]; + s8 volt_max[ADT7473_VOLT_COUNT]; + + s8 temp[ADT7473_TEMP_COUNT]; + s8 temp_min[ADT7473_TEMP_COUNT]; + s8 temp_max[ADT7473_TEMP_COUNT]; + s8 temp_tmin[ADT7473_TEMP_COUNT]; + /* This is called the !THERM limit in the datasheet */ + s8 temp_tmax[ADT7473_TEMP_COUNT]; + + u16 fan[ADT7473_FAN_COUNT]; + u16 fan_min[ADT7473_FAN_COUNT]; + + u8 pwm[ADT7473_PWM_COUNT]; + u8 pwm_max[ADT7473_PWM_COUNT]; + u8 pwm_min[ADT7473_PWM_COUNT]; + u8 pwm_behavior[ADT7473_PWM_COUNT]; + + u8 temp_twos_complement; + u8 temp_offset; + + u16 alarm; + u8 max_duty_at_overheat; +}; + +static int adt7473_attach_adapter(struct i2c_adapter *adapter); +static int adt7473_detect(struct i2c_adapter *adapter, int address, int kind); +static int adt7473_detach_client(struct i2c_client *client); + +static struct i2c_driver adt7473_driver = { + .driver = { + .name = "adt7473", + }, + .attach_adapter = adt7473_attach_adapter, + .detach_client = adt7473_detach_client, +}; + +/* + * 16-bit registers on the ADT7473 are low-byte first. The data sheet says + * that the low byte must be read before the high byte. + */ +static inline int adt7473_read_word_data(struct i2c_client *client, u8 reg) +{ + u16 foo; + foo = i2c_smbus_read_byte_data(client, reg); + foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8); + return foo; +} + +static inline int adt7473_write_word_data(struct i2c_client *client, u8 reg, + u16 value) +{ + return i2c_smbus_write_byte_data(client, reg, value & 0xFF) + && i2c_smbus_write_byte_data(client, reg + 1, value >> 8); +} + +static void adt7473_init_client(struct i2c_client *client) +{ + int reg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG1); + + if (!(reg & ADT7473_CFG1_READY)) { + dev_err(&client->dev, "Chip not ready.\n"); + } else { + /* start monitoring */ + i2c_smbus_write_byte_data(client, ADT7473_REG_CFG1, + reg | ADT7473_CFG1_START); + } +} + +static struct adt7473_data *adt7473_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct adt7473_data *data = i2c_get_clientdata(client); + unsigned long local_jiffies = jiffies; + u8 cfg; + int i; + + mutex_lock(&data->lock); + if (time_before(local_jiffies, data->sensors_last_updated + + SENSOR_REFRESH_INTERVAL) + && data->sensors_valid) + goto no_sensor_update; + + for (i = 0; i < ADT7473_VOLT_COUNT; i++) + data->volt[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_VOLT(i)); + + /* Determine temperature encoding */ + cfg = i2c_smbus_read_byte_data(client, ADT7473_REG_CFG5); + data->temp_twos_complement = (cfg & ADT7473_CFG5_TEMP_TWOS); + + /* + * What does this do? it implies a variable temperature sensor + * offset, but the datasheet doesn't say anything about this bit + * and other parts of the datasheet imply that "offset64" mode + * means that you shift temp values by -64 if the above bit was set. + */ + data->temp_offset = (cfg & ADT7473_CFG5_TEMP_OFFSET); + + for (i = 0; i < ADT7473_TEMP_COUNT; i++) + data->temp[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_TEMP(i)); + + for (i = 0; i < ADT7473_FAN_COUNT; i++) + data->fan[i] = adt7473_read_word_data(client, + ADT7473_REG_FAN(i)); + + for (i = 0; i < ADT7473_PWM_COUNT; i++) + data->pwm[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_PWM(i)); + + data->alarm = i2c_smbus_read_byte_data(client, ADT7473_REG_ALARM1); + if (data->alarm & ADT7473_OOL) + data->alarm |= ALARM2(i2c_smbus_read_byte_data(client, + ADT7473_REG_ALARM2)); + + data->sensors_last_updated = local_jiffies; + data->sensors_valid = 1; + +no_sensor_update: + if (time_before(local_jiffies, data->limits_last_updated + + LIMIT_REFRESH_INTERVAL) + && data->limits_valid) + goto out; + + for (i = 0; i < ADT7473_VOLT_COUNT; i++) { + data->volt_min[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_VOLT_MIN(i)); + data->volt_max[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_VOLT_MAX(i)); + } + + for (i = 0; i < ADT7473_TEMP_COUNT; i++) { + data->temp_min[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_TEMP_MIN(i)); + data->temp_max[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_TEMP_MAX(i)); + data->temp_tmin[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_TEMP_TMIN(i)); + data->temp_tmax[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_TEMP_TMAX(i)); + } + + for (i = 0; i < ADT7473_FAN_COUNT; i++) + data->fan_min[i] = adt7473_read_word_data(client, + ADT7473_REG_FAN_MIN(i)); + + for (i = 0; i < ADT7473_PWM_COUNT; i++) { + data->pwm_max[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_PWM_MAX(i)); + data->pwm_min[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_PWM_MIN(i)); + data->pwm_behavior[i] = i2c_smbus_read_byte_data(client, + ADT7473_REG_PWM_BHVR(i)); + } + + data->limits_last_updated = local_jiffies; + data->limits_valid = 1; + +out: + mutex_unlock(&data->lock); + return data; +} + +/* + * On this chip, voltages are given as a count of steps between a minimum + * and maximum voltage, not a direct voltage. + */ +static const int volt_convert_table[][2] = { + {2997, 3}, + {4395, 4}, +}; + +static int decode_volt(int volt_index, u8 raw) +{ + int cmax = volt_convert_table[volt_index][0]; + int cmin = volt_convert_table[volt_index][1]; + return ((raw * (cmax - cmin)) / 255) + cmin; +} + +static u8 encode_volt(int volt_index, int cooked) +{ + int cmax = volt_convert_table[volt_index][0]; + int cmin = volt_convert_table[volt_index][1]; + u8 x; + + if (cooked > cmax) + cooked = cmax; + else if (cooked < cmin) + cooked = cmin; + + x = ((cooked - cmin) * 255) / (cmax - cmin); + + return x; +} + +static ssize_t show_volt_min(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adt7473_data *data = adt7473_update_device(dev); + return sprintf(buf, "%d\n", + decode_volt(attr->index, data->volt_min[attr->index])); +} + +static ssize_t set_volt_min(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct adt7473_data *data = i2c_get_clientdata(client); |