From cc4315029ea9ee4d2e056f5ee44718e99e999a87 Mon Sep 17 00:00:00 2001 From: Philip Edelbrock Date: Wed, 13 Sep 2000 23:28:14 +0000 Subject: [PATCH] (Phil) Initial addition of LM87 driver. Compiling testing not done yet, but will be done very shortly. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@872 7894878c-1315-0410-8ee3-d5d059ff63e0 --- kernel/chips/Module.mk | 3 +- kernel/chips/lm87.c | 910 +++++++++++++++++++++++++++++++++++++++ kernel/include/sensors.h | 26 ++ lib/chips.c | 84 ++++ lib/chips.h | 37 ++ 5 files changed, 1059 insertions(+), 1 deletion(-) create mode 100644 kernel/chips/lm87.c diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk index 80c2be3a..2c8f2e5b 100644 --- a/kernel/chips/Module.mk +++ b/kernel/chips/Module.mk @@ -28,7 +28,8 @@ KERNELCHIPSTARGETS := $(MODULE_DIR)/bt869.o $(MODULE_DIR)/gl520sm.o \ $(MODULE_DIR)/thmc50.o \ $(MODULE_DIR)/via686a.o \ $(MODULE_DIR)/ddcmon.o \ - $(MODULE_DIR)/adm1025.o + $(MODULE_DIR)/adm1025.o \ + $(MODULE_DIR)/lm87.o ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1021=y' $(LINUX)/.config; then echo 1; fi),1) KERNELCHIPSTARGETS += $(MODULE_DIR)/adm1021.o endif diff --git a/kernel/chips/lm87.c b/kernel/chips/lm87.c new file mode 100644 index 00000000..c403f014 --- /dev/null +++ b/kernel/chips/lm87.c @@ -0,0 +1,910 @@ +/* + LM87.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1999 Frodo Looijaard + Philip Edelbrock , and + Dan Eaton of Rocket Logix + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "version.h" +#include "i2c-isa.h" +#include "sensors.h" +#include + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)) +#define init_MUTEX(s) do { *(s) = MUTEX; } while(0) +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13) +#define THIS_MODULE NULL +#endif + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x2c, 0x2f, SENSORS_I2C_END }; +static unsigned int normal_isa[] = { SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(LM87); + +/* The following is the calculation for the register offset + * for the monitored items minimum and maximum locations. + */ +#define LM87_REG_IN_MAX(nr) (0x2b + (nr) * 2) +#define LM87_REG_IN_MIN(nr) (0x2c + (nr) * 2) +#define LM87_REG_IN(nr) (0x20 + (nr)) + + +/* + * LM87 register definition + * + */ + + /* The LM87 registers */ +#define LM87_INT_TEMP_HI_LIMIT_LOCKABLE 0x13 +#define LM87_EXT_TEMP_HI_LIMIT_LOCKABLE 0x14 +#define LM87_REG_TEST 0x15 +#define LM87_REG_CHANNEL_MODE 0x16 +#define LM87_REG_INT_TEMP_HI_LIMIT 0x17 +#define LM87_REG_EXT_TEMP_HI_LIMIT 0x18 +#define LM87_REG_ANALOG_OUT 0x19 + + /* These are all read-only */ +#define LM87_REG_2_5V_EXT_TEMP_2 0x20 /* front ambient for us */ +#define LM87_REG_VCCP1 0x21 /* this will be CPU core voltage */ +#define LM87_REG_3_3V 0x22 +#define LM87_REG_5V 0x23 +#define LM87_REG_12V 0x24 +#define LM87_REG_VCCP2 0x25 +#define LM87_REG_EXT_TEMP_1 0x26 /* CPU temp for us */ +#define LM87_REG_INT_TEMP 0x27 /* LM87 temp. */ +#define LM87_REG_FAN1_AIN1 0x28 /* this is AIN: 2.5V monitored */ +#define LM87_REG_FAN2_AIN2 0x29 + +/* These are read/write */ +#define LM87_REG_2_5V_EXT_TEMP_2_HIGH 0x2B +#define LM87_REG_2_5V_EXT_TEMP_2_LOW 0x2C +#define LM87_REG_VCCP1_HIGH 0x2D +#define LM87_REG_VCCP1_LOW 0x2E +#define LM87_REG_3_3V_HIGH 0x2F +#define LM87_REG_3_3V_LOW 0x30 +#define LM87_REG_5V_HIGH 0x31 +#define LM87_REG_5V_LOW 0x32 +#define LM87_REG_12V_HIGH 0x33 +#define LM87_REG_12V_LOW 0x34 +#define LM87_REG_VCCP2_HIGH 0x35 +#define LM87_REG_VCCP2_LOW 0x36 +#define LM87_REG_EXT_TEMP_1_HIGH 0x37 +#define LM87_REG_EXT_TEMP_1_LOW 0x38 +#define LM87_REG_INT_TEMP_HIGH 0x39 +#define LM87_REG_INT_TEMP_LOW 0x3A +#define LM87_REG_FAN1_AIN1_LIMIT 0x3B /* 2.5V high limit */ +#define LM87_REG_FAN2_AIN2_LIMIT 0x3C +#define LM87_REG_COMPANY_ID 0x3E +#define LM87_REG_DIE_REV 0x3F + +#define LM87_REG_CONFIG 0x40 +#define LM87_REG_INT1_STAT 0x41 +#define LM87_REG_INT2_STAT 0x42 +#define LM87_REG_INT1_MASK 0x43 +#define LM87_REG_INT2_MASK 0x44 +#define LM87_REG_CHASSIS_CLEAR 0x46 +#define LM87_REG_VID_FAN_DIV 0x47 +#define LM87_REG_VID4 0x49 +#define LM87_REG_CONFIG_2 0x4A +#define LM87_REG_INTRPT_STATUS_1_MIRROR 0x4C +#define LM87_REG_INTRPT_STATUS_2_MIRROR 0x4D +#define LM87_REG_SMBALERT_NUM_ENABLE 0x80 + + + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val,nr) (SENSORS_LIMIT(((val) & 0xff),0,255)) +#define IN_FROM_REG(val,nr) (val) + +extern inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, + 254); +} + +#define FAN_FROM_REG(val,div) ((val)==0?-1:\ + (val)==255?0:1350000/((div)*(val))) + +#define TEMP_FROM_REG(temp) (temp * 10) + +#define TEMP_LIMIT_FROM_REG(val) (((val)>0x80?(val)-0x100:(val))*10) + +#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT(((val)<0?(((val)-5)/10):\ + ((val)+5)/10),0,255) +#if 0 +#define TEMP_FROM_REG(temp) \ + ((temp)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \ + ((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \ + +#define TEMP_LIMIT_FROM_REG(val) (val) + +#define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val),0,255) +#endif + + +#define ALARMS_FROM_REG(val) (val) + +#define DIV_FROM_REG(val) (1 << (val)) +#define DIV_TO_REG(val) ((val)==1?0:((val)==8?3:((val)==4?2:1))) + +#define VID_FROM_REG(val) ((val)==0x1f?0:(val)>=0x10?510-(val)*10:\ + 205-(val)*5) + +/* Initial limits */ +#define LM87_INIT_IN_0 192 +#define LM87_INIT_IN_1 192 +#define LM87_INIT_IN_2 192 +#define LM87_INIT_IN_3 192 +#define LM87_INIT_IN_4 192 +#define LM87_INIT_IN_5 192 + +#define LM87_INIT_IN_PERCENTAGE 10 + +/********* 2.5V monitoring limits **********/ +#define LM87_INIT_IN_MIN_0 \ + (LM87_INIT_IN_0 - ((LM87_INIT_IN_0 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_0 \ + (LM87_INIT_IN_0 + ((LM87_INIT_IN_0 * LM87_INIT_IN_PERCENTAGE) / 100)) + +/********* Vccp1 monitoring limits **********/ +#define LM87_INIT_IN_MIN_1 \ + (LM87_INIT_IN_1 - ((LM87_INIT_IN_1 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_1 \ + (LM87_INIT_IN_1 + ((LM87_INIT_IN_1 * LM87_INIT_IN_PERCENTAGE) / 100)) + +/********* 3.3V monitoring limits **********/ +#define LM87_INIT_IN_MIN_2 \ + (LM87_INIT_IN_2 - ((LM87_INIT_IN_2 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_2 \ + (LM87_INIT_IN_2 + ((LM87_INIT_IN_2 * LM87_INIT_IN_PERCENTAGE) / 100)) + +/********* 5V monitoring limits **********/ +#define LM87_INIT_IN_MIN_3 \ + (LM87_INIT_IN_3 - ((LM87_INIT_IN_3 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_3 \ + (LM87_INIT_IN_3 + ((LM87_INIT_IN_3 * LM87_INIT_IN_PERCENTAGE) / 100)) + +/********* 12V monitoring limits **********/ +#define LM87_INIT_IN_MIN_4 \ + (LM87_INIT_IN_4 - ((LM87_INIT_IN_4 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_4 \ + (LM87_INIT_IN_4 + ((LM87_INIT_IN_4 * LM87_INIT_IN_PERCENTAGE) / 100)) + +/********* Vccp2 monitoring limits **********/ +#define LM87_INIT_IN_MIN_5 \ + (LM87_INIT_IN_5 - ((LM87_INIT_IN_5 * LM87_INIT_IN_PERCENTAGE) / 100)) +#define LM87_INIT_IN_MAX_5 \ + (LM87_INIT_IN_5 + ((LM87_INIT_IN_5 * LM87_INIT_IN_PERCENTAGE) / 100)) + +#define LM87_INIT_FAN_MIN 3000 + +#define LM87_INIT_EXT_TEMP_MAX 600 +#define LM87_INIT_EXT_TEMP_MIN 50 +#define LM87_INIT_INT_TEMP_MAX 600 +#define LM87_INIT_INT_TEMP_MIN 50 + +#ifdef MODULE +extern int init_module(void); +extern int cleanup_module(void); +#endif /* MODULE */ + +/* For each registered LM87, we need to keep some data in memory. That + data is pointed to by LM87_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new LM87 client is + allocated. */ +struct LM87_data { + int sysctl_id; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[6]; /* Register value */ + u8 in_max[6]; /* Register value */ + u8 in_min[6]; /* Register value */ + u8 fan; /* Register value */ + u8 fan_min; /* Register value */ + u8 fan_div; /* Register encoding, shifted right */ + int front_amb_temp; /* Temp, shifted right */ + int cpu_temp; /* Temp, shifted right */ + int int_temp; /* Temp, shifted right */ + u8 cpu_temp_max; /* Register value */ + u8 cpu_temp_min; /* Register value */ + u8 front_amb_temp_max; /* Register value */ + u8 front_amb_temp_min; /* Register value */ + u8 int_temp_max; /* Register value */ + u8 int_temp_min; /* Register value */ + u16 alarms; /* Register encoding, combined */ + u8 analog_out; /* Register value */ + u8 vid; /* Register value combined */ +}; + + +#ifdef MODULE +static +#else +extern +#endif +int __init sensors_LM87_init(void); +static int __init LM87_cleanup(void); + +static int LM87_attach_adapter(struct i2c_adapter *adapter); +static int LM87_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static int LM87_detach_client(struct i2c_client *client); +static int LM87_command(struct i2c_client *client, unsigned int cmd, + void *arg); +static void LM87_inc_use(struct i2c_client *client); +static void LM87_dec_use(struct i2c_client *client); + +static int LM87_read_value(struct i2c_client *client, u8 register); +static int LM87_write_value(struct i2c_client *client, u8 register, + u8 value); +static void LM87_update_client(struct i2c_client *client); +static void LM87_init_client(struct i2c_client *client); + + +static void LM87_in(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void LM87_fan(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void LM87_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void LM87_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void LM87_fan_div(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void LM87_analog_out(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, + long *results); +static void LM87_vid(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +/* I choose here for semi-static LM87 allocation. Complete dynamic + allocation could also be used; the code needed for this would probably + take more memory than the datastructure takes now. */ +static int LM87_id = 0; + +static struct i2c_driver LM87_driver = { + /* name */ "LM87 sensor driver", + /* id */ I2C_DRIVERID_LM87, + /* flags */ I2C_DF_NOTIFY, + /* attach_adapter */ &LM87_attach_adapter, + /* detach_client */ &LM87_detach_client, + /* command */ &LM87_command, + /* inc_use */ &LM87_inc_use, + /* dec_use */ &LM87_dec_use +}; + +/* Used by LM87_init/cleanup */ +static int __initdata LM87_initialized = 0; + +/* The /proc/sys entries */ +/* These files are created for each detected LM87. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ + +static ctl_table LM87_dir_table_template[] = { + {LM87_SYSCTL_IN0, "2.5V", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_IN1, "cpu_volt", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_IN2, "3.3V", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_IN3, "5V", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_IN4, "12V", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_IN5, "Vccp2", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_in}, + {LM87_SYSCTL_FAN, "fan", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_fan}, + {LM87_SYSCTL_FRNT_TEMP, "front_amb_temp", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_temp}, + {LM87_SYSCTL_CPU_TEMP, "cpu_temp", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_temp}, + {LM87_SYSCTL_INT_TEMP, "int_temp", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_temp}, + {LM87_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_fan_div}, + {LM87_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_alarms}, + {LM87_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_analog_out}, + {LM87_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &sensors_proc_real, + &sensors_sysctl_real, NULL, &LM87_vid}, + {0} +}; + +int LM87_attach_adapter(struct i2c_adapter *adapter) +{ + return sensors_detect(adapter, &addr_data, LM87_detect); +} + +static int LM87_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + int i; + struct i2c_client *new_client; + struct LM87_data *data; + int err = 0; + const char *type_name = ""; + const char *client_name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto ERROR0; + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access LM87_{read,write}_value. */ + + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct LM87_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + data = (struct LM87_data *) (new_client + 1); + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &LM87_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + if (kind < 0) { + if ((LM87_read_value(new_client, LM87_REG_CONFIG) & 0x80) != 0x00) + goto ERROR1; + } + + /* Fill in the remaining client fields and put it into the global list */ + type_name = "LM87"; + client_name = "LM87 chip"; + strcpy(new_client->name, client_name); + data->type = kind; + + new_client->id = LM87_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* Register a new directory entry with module sensors */ + if ((i = sensors_register_entry(new_client, + type_name, + LM87_dir_table_template, + THIS_MODULE)) < 0) { + err = i; + goto ERROR4; + } + data->sysctl_id = i; + + /* Initialize the LM87 chip */ + LM87_init_client(new_client); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + ERROR4: + i2c_detach_client(new_client); + ERROR3: + ERROR1: + kfree(new_client); + ERROR0: + return err; +} + +int LM87_detach_client(struct i2c_client *client) +{ + int err; + + sensors_deregister_entry(((struct LM87_data *) (client->data))-> + sysctl_id); + + if ((err = i2c_detach_client(client))) { + printk + ("LM87.o: Client deregistration failed, client not detached.\n"); + return err; + } + + kfree(client); + + return 0; + +} + +/* No commands defined yet */ +int LM87_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + return 0; +} + +void LM87_inc_use(struct i2c_client *client) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +void LM87_dec_use(struct i2c_client *client) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + +int LM87_read_value(struct i2c_client *client, u8 reg) +{ + return 0xFF & i2c_smbus_read_byte_data(client, reg); +} + +int LM87_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* Called when we have found a new LM87. It should set limits, etc. */ +void LM87_init_client(struct i2c_client *client) +{ + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others. This makes most other + initializations unnecessary */ + LM87_write_value(client, LM87_REG_CONFIG, 0x80); + + /* Setup Channel Mode register for configuration of monitoring + * bit 0 - Configures Fan 1/AIN 1 input (1 = AIN) + * bit 2 - Configures 2.5V/D2 input (1 = 2nd Therm.) + */ + LM87_write_value(client, LM87_REG_CHANNEL_MODE, 0x03); + + + LM87_write_value(client, LM87_REG_IN_MIN(1), + IN_TO_REG(LM87_INIT_IN_MIN_1, 1)); + LM87_write_value(client, LM87_REG_IN_MAX(1), + IN_TO_REG(LM87_INIT_IN_MAX_1, 1)); + LM87_write_value(client, LM87_REG_IN_MIN(2), + IN_TO_REG(LM87_INIT_IN_MIN_2, 2)); + LM87_write_value(client, LM87_REG_IN_MAX(2), + IN_TO_REG(LM87_INIT_IN_MAX_2, 2)); + LM87_write_value(client, LM87_REG_IN_MIN(3), + IN_TO_REG(LM87_INIT_IN_MIN_3, 3)); + LM87_write_value(client, LM87_REG_IN_MAX(3), + IN_TO_REG(LM87_INIT_IN_MAX_3, 3)); + LM87_write_value(client, LM87_REG_IN_MIN(4), + IN_TO_REG(LM87_INIT_IN_MIN_4, 4)); + LM87_write_value(client, LM87_REG_IN_MAX(4), + IN_TO_REG(LM87_INIT_IN_MAX_4, 4)); + LM87_write_value(client, LM87_REG_IN_MIN(5), + IN_TO_REG(LM87_INIT_IN_MIN_5, 5)); + LM87_write_value(client, LM87_REG_IN_MAX(5), + IN_TO_REG(LM87_INIT_IN_MAX_5, 5)); + + LM87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH, + TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX)); + LM87_write_value(client, LM87_REG_EXT_TEMP_1_LOW, + TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN)); + LM87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH, + TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MAX)); + LM87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW, + TEMP_LIMIT_TO_REG(LM87_INIT_EXT_TEMP_MIN)); + LM87_write_value(client, LM87_REG_INT_TEMP_HIGH, + TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MAX)); + LM87_write_value(client, LM87_REG_INT_TEMP_LOW, + TEMP_LIMIT_TO_REG(LM87_INIT_INT_TEMP_MIN)); + + LM87_write_value(client, LM87_REG_FAN1_AIN1_LIMIT, + IN_TO_REG(LM87_INIT_IN_MAX_0, 0)); + + LM87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, + FAN_TO_REG(LM87_INIT_FAN_MIN, 2)); + + /* Start monitoring */ + LM87_write_value(client, LM87_REG_CONFIG, 0x01); +} + +void LM87_update_client(struct i2c_client *client) +{ + struct LM87_data *data = client->data; + u8 i; + + down(&data->update_lock); + + if ( + (jiffies - data->last_updated > + (data->type == LM87 ? HZ / 2 : HZ * 2)) + || (jiffies < data->last_updated) || !data->valid) { + +#ifdef DEBUG + printk("Starting LM87 update\n"); +#endif + for (i = 0; i <= 5; i++) { + /* Since we are using AIN 1 as our 2.5V monitoring, need to + * accomodate with a hardcode register address and we only get + * to look at one threshold. + */ + if (i == 0) { + data->in[i] = LM87_read_value(client, LM87_REG_FAN1_AIN1); + data->in_min[i] = 0; + data->in_max[i] = LM87_read_value(client, LM87_REG_FAN1_AIN1_LIMIT); + } + else { + data->in[i] = + LM87_read_value(client, LM87_REG_IN(i)); + data->in_min[i] = + LM87_read_value(client, + LM87_REG_IN_MIN(i)); + data->in_max[i] = + LM87_read_value(client, + LM87_REG_IN_MAX(i)); + } + } + + data->fan = + LM87_read_value(client, LM87_REG_FAN2_AIN2); + data->fan_min = + LM87_read_value(client, LM87_REG_FAN2_AIN2_LIMIT); + + data->front_amb_temp = + LM87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2); + data->cpu_temp = + LM87_read_value(client, LM87_REG_EXT_TEMP_1); + data->int_temp = + LM87_read_value(client, LM87_REG_INT_TEMP); + + data->front_amb_temp_max = + LM87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH); + data->front_amb_temp_min = + LM87_read_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW); + + data->cpu_temp_max = + LM87_read_value(client, LM87_REG_EXT_TEMP_1_HIGH); + data->cpu_temp_min = + LM87_read_value(client, LM87_REG_EXT_TEMP_1_LOW); + + data->int_temp_max = + LM87_read_value(client, LM87_REG_INT_TEMP_HIGH); + data->int_temp_min = + LM87_read_value(client, LM87_REG_INT_TEMP_LOW); + + i = LM87_read_value(client, LM87_REG_VID_FAN_DIV); + data->fan_div = (i >> 4) & 0x03; + data->vid = i & 0x0f; + data->vid |= + (LM87_read_value(client, LM87_REG_VID4) & 0x01) + << 4; + + data->alarms = + LM87_read_value(client, + LM87_REG_INT1_STAT) + + (LM87_read_value(client, LM87_REG_INT2_STAT) << + 8); + data->analog_out = + LM87_read_value(client, LM87_REG_ANALOG_OUT); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +/* The next few functions are the call-back functions of the /proc/sys and + sysctl files. Which function is used is defined in the ctl_table in + the extra1 field. + Each function must return the magnitude (power of 10 to divide the date + with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must + put a maximum of *nrels elements in results reflecting the data of this + file, and set *nrels to the number it actually put in it, if operation== + SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from + results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. + Note that on SENSORS_PROC_REAL_READ, I do not check whether results is + large enough (by checking the incoming value of *nrels). This is not very + good practice, but as long as you put less than about 5 values in results, + you can assume it is large enough. */ +void LM87_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + + /************************************************************ + * These values represent 2.5V, Vccp1, 3.3V, 5V, 12V & Vccp2 + * The 2.5V is 50% sampled for our application, so check + * against 1.25V value. + ************************************************************/ + int scales[6] = { 260, 260, 344, 520, 1250, 260 }; + + struct LM87_data *data = client->data; + int nr = ctl_name - LM87_SYSCTL_IN0; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = + IN_FROM_REG(data->in_min[nr], nr) * scales[nr] / 192; + results[1] = + IN_FROM_REG(data->in_max[nr], nr) * scales[nr] / 192; + results[2] = + IN_FROM_REG(data->in[nr], nr) * scales[nr] / 192; + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->in_min[nr] = + IN_TO_REG((results[0] * 192) / scales[nr], nr); + LM87_write_value(client, LM87_REG_IN_MIN(nr), + data->in_min[nr]); + } + if (*nrels_mag >= 2) { + data->in_max[nr] = + IN_TO_REG((results[1] * 192) / scales[nr], nr); + LM87_write_value(client, LM87_REG_IN_MAX(nr), + data->in_max[nr]); + } + } +} + +void LM87_fan(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + int nr = ctl_name - LM87_SYSCTL_FAN + 1; /* not sure +1 needed */ + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = FAN_FROM_REG(data->fan_min, + DIV_FROM_REG(data->fan_div)); + results[1] = FAN_FROM_REG(data->fan, + DIV_FROM_REG(data->fan_div)); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 0) { + data->fan_min = FAN_TO_REG(results[0], + DIV_FROM_REG + (data->fan_div)); + LM87_write_value(client, LM87_REG_FAN2_AIN2_LIMIT, + data->fan_min); + } + } +} + + +void LM87_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) + { + LM87_update_client(client); + + /* find out which temp. is being requested */ + if (ctl_name == LM87_SYSCTL_FRNT_TEMP) + { + results[0] = TEMP_LIMIT_FROM_REG(data->front_amb_temp_max); + results[1] = TEMP_LIMIT_FROM_REG(data->front_amb_temp_min); + results[2] = TEMP_FROM_REG(data->int_temp); + } + else if(ctl_name == LM87_SYSCTL_CPU_TEMP) + { + results[0] = TEMP_LIMIT_FROM_REG(data->cpu_temp_max); + results[1] = TEMP_LIMIT_FROM_REG(data->cpu_temp_min); + results[2] = TEMP_FROM_REG(data->cpu_temp); + } + else if(ctl_name == LM87_SYSCTL_INT_TEMP) + { + results[0] = TEMP_LIMIT_FROM_REG(data->int_temp_max); + results[1] = TEMP_LIMIT_FROM_REG(data->int_temp_min); + results[2] = TEMP_FROM_REG(data->int_temp); + } + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + if (ctl_name == LM87_SYSCTL_FRNT_TEMP) { + data->front_amb_temp_max = TEMP_LIMIT_TO_REG(results[0]); + LM87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_HIGH, + data->front_amb_temp_max); + } + if (ctl_name == LM87_SYSCTL_CPU_TEMP) { + data->cpu_temp_max = TEMP_LIMIT_TO_REG(results[0]); + LM87_write_value(client, LM87_REG_EXT_TEMP_1_HIGH, + data->int_temp_max); + } + if (ctl_name == LM87_SYSCTL_INT_TEMP) { + data->int_temp_max = TEMP_LIMIT_TO_REG(results[0]); + LM87_write_value(client, LM87_REG_INT_TEMP_HIGH, + data->int_temp_max); + } + } + if (*nrels_mag >= 2) { + if (ctl_name == LM87_SYSCTL_FRNT_TEMP) { + data->front_amb_temp_min = TEMP_LIMIT_TO_REG(results[0]); + LM87_write_value(client, LM87_REG_2_5V_EXT_TEMP_2_LOW, + data->front_amb_temp_min); + } + if (ctl_name == LM87_SYSCTL_CPU_TEMP) { + data->cpu_temp_min = TEMP_LIMIT_TO_REG(results[0]); + LM87_write_value(client, LM87_REG_EXT_TEMP_1_LOW, + data->int_temp_min); + } + if (ctl_name == LM87_SYSCTL_INT_TEMP) { + data->int_temp_min = TEMP_LIMIT_TO_REG(results[1]); + LM87_write_value(client, LM87_REG_INT_TEMP_LOW, + data->int_temp_min); + } + } + } +} + +void LM87_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = ALARMS_FROM_REG(data->alarms); + *nrels_mag = 1; + } +} + +void LM87_fan_div(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + int old; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = DIV_FROM_REG(data->fan_div); + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + old = LM87_read_value(client, LM87_REG_VID_FAN_DIV); + if (*nrels_mag >= 2) { + data->fan_div = DIV_TO_REG(results[1]); + old = (old & 0x3f) | (data->fan_div << 6); + } + if (*nrels_mag >= 1) { + data->fan_div = DIV_TO_REG(results[0]); + old = (old & 0xcf) | (data->fan_div << 4); + LM87_write_value(client, LM87_REG_VID_FAN_DIV, old); + } + } +} + +void LM87_analog_out(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = data->analog_out; + *nrels_mag = 1; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->analog_out = results[0]; + LM87_write_value(client, LM87_REG_ANALOG_OUT, + data->analog_out); + } + } +} + +void LM87_vid(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct LM87_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + LM87_update_client(client); + results[0] = VID_FROM_REG(data->vid); + *nrels_mag = 1; + } +} + +int __init sensors_LM87_init(void) +{ + int res; + + printk("LM87.o version %s (%s)\n", LM_VERSION, LM_DATE); + LM87_initialized = 0; + + if ((res = i2c_add_driver(&LM87_driver))) { + printk + ("LM87.o: Driver registration failed, module not inserted.\n"); + LM87_cleanup(); + return res; + } + LM87_initialized++; + return 0; +} + +int __init LM87_cleanup(void) +{ + int res; + + if (LM87_initialized >= 1) { + if ((res = i2c_del_driver(&LM87_driver))) { + printk + ("LM87.o: Driver deregistration failed, module not removed.\n"); + return res; + } + LM87_initialized--; + } + return 0; +} + +EXPORT_NO_SYMBOLS; + +#ifdef MODULE + +MODULE_AUTHOR +("Frodo Looijaard and Philip Edelbrock "); +MODULE_DESCRIPTION("LM87 driver"); + +int init_module(void) +{ + return sensors_LM87_init(); +} + +int cleanup_module(void) +{ + return LM87_cleanup(); +} + +#endif /* MODULE */ diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index f810ea09..ad9b455c 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -376,6 +376,7 @@ extern inline int SENSORS_LIMIT(long value, long low, long high) #define I2C_DRIVERID_DDCMON 1018 #define I2C_DRIVERID_VIA686A 1019 #define I2C_DRIVERID_ADM1025 1020 +#define I2C_DRIVERID_LM87 1021 /* Sysctl IDs */ #ifdef DEV_HWMON @@ -723,5 +724,30 @@ struct sensors_chips_data { #define DDCMON_SYSCTL_TIMINGS 1013 #define DDCMON_SYSCTL_SERIAL 1014 +#define LM87_SYSCTL_IN0 1000 /* Volts * 100 */ +#define LM87_SYSCTL_IN1 1001 +#define LM87_SYSCTL_IN2 1002 +#define LM87_SYSCTL_IN3 1003 +#define LM87_SYSCTL_IN4 1004 +#define LM87_SYSCTL_IN5 1005 +#define LM87_SYSCTL_FAN 1102 +#define LM87_SYSCTL_FRNT_TEMP 1250 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_CPU_TEMP 1251 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_INT_TEMP 1252 /* Degrees Celcius * 100 */ +#define LM87_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */ +#define LM87_SYSCTL_ALARMS 2001 /* bitvector */ +#define LM87_SYSCTL_ANALOG_OUT 2002 +#define LM87_SYSCTL_VID 2003 + +#define LM87_ALARM_IN0 0x0001 +#define LM87_ALARM_IN1 0x0002 +#define LM87_ALARM_IN2 0x0004 +#define LM87_ALARM_IN3 0x0008 +#define LM87_ALARM_IN4 0x0100 +#define LM87_ALARM_IN5 0x0200 +#define LM87_ALARM_AMB_TEMP 0x0040 +#define LM87_ALARM_FAN2 0x0080 +#define LM87_ALARM_INT_TEMP 0x0010 +#define LM87_ALARM_CHAS 0x1000 #endif /* def SENSORS_SENSORS_H */ diff --git a/lib/chips.c b/lib/chips.c index f6caaf1f..06dfe2a2 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -1774,6 +1774,89 @@ static sensors_chip_feature eeprom_features[] = { 0 } }; +static sensors_chip_feature lm87_features[] = + { + { SENSORS_LM87_IN0, "2.5V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN0, VALUE(2), 2 }, + { SENSORS_LM87_IN1, "Vccp1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN1, VALUE(3), 2 }, + { SENSORS_LM87_IN2, "3.3V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN2, VALUE(3), 2 }, + { SENSORS_LM87_IN3, "5V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN3, VALUE(3), 2 }, + { SENSORS_LM87_IN4, "12V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN4, VALUE(3), 2 }, + { SENSORS_LM87_IN5, "Vccp2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_IN5, VALUE(3), 2 }, + { SENSORS_LM87_IN0_MIN, "AmbTemp_min", SENSORS_LM87_IN0, + SENSORS_LM87_IN0, SENSORS_MODE_RW, + LM87_SYSCTL_IN0, VALUE(1), 2 }, + { SENSORS_LM87_IN1_MIN, "Vccp1_min", SENSORS_LM87_IN1, + SENSORS_LM87_IN1, SENSORS_MODE_RW, + LM87_SYSCTL_IN1, VALUE(1), 2 }, + { SENSORS_LM87_IN2_MIN, "3.3V_min", SENSORS_LM87_IN2, + SENSORS_LM87_IN2, SENSORS_MODE_RW, + LM87_SYSCTL_IN2, VALUE(1), 2 }, + { SENSORS_LM87_IN3_MIN, "5V_min", SENSORS_LM87_IN3, + SENSORS_LM87_IN3, SENSORS_MODE_RW, + LM87_SYSCTL_IN3, VALUE(1), 2 }, + { SENSORS_LM87_IN4_MIN, "12V_min", SENSORS_LM87_IN4, + SENSORS_LM87_IN4, SENSORS_MODE_RW, + LM87_SYSCTL_IN4, VALUE(1), 2 }, + { SENSORS_LM87_IN5_MIN, "Vccp2_min", SENSORS_LM87_IN5, + SENSORS_LM87_IN5, SENSORS_MODE_RW, + LM87_SYSCTL_IN5, VALUE(1), 2 }, + { SENSORS_LM87_IN0_MAX, "AmbTemp_max", SENSORS_LM87_IN0, + SENSORS_LM87_IN0, SENSORS_MODE_RW, + LM87_SYSCTL_IN0, VALUE(2), 2 }, + { SENSORS_LM87_IN1_MAX, "Vccp1_max", SENSORS_LM87_IN1, + SENSORS_LM87_IN1, SENSORS_MODE_RW, + LM87_SYSCTL_IN1, VALUE(2), 2 }, + { SENSORS_LM87_IN2_MAX, "3.3V_max", SENSORS_LM87_IN2, + SENSORS_LM87_IN2, SENSORS_MODE_RW, + LM87_SYSCTL_IN2, VALUE(2), 2 }, + { SENSORS_LM87_IN3_MAX, "5V_max", SENSORS_LM87_IN3, + SENSORS_LM87_IN3, SENSORS_MODE_RW, + LM87_SYSCTL_IN3, VALUE(2), 2 }, + { SENSORS_LM87_IN4_MAX, "12V_max", SENSORS_LM87_IN4, + SENSORS_LM87_IN4, SENSORS_MODE_RW, + LM87_SYSCTL_IN4, VALUE(2), 2 }, + { SENSORS_LM87_IN5_MAX, "Vccp2_max", SENSORS_LM87_IN5, + SENSORS_LM87_IN5, SENSORS_MODE_RW, + LM87_SYSCTL_IN5, VALUE(2), 2 }, + { SENSORS_LM87_FAN2_AIN2, "fan", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_FAN, VALUE(2), 0 }, + { SENSORS_LM87_FAN1_AIN1_LIMIT, "fan1/ain1_limit", SENSORS_LM87_FAN1_AIN1, + SENSORS_LM87_FAN1_AIN1, SENSORS_MODE_RW, + LM87_SYSCTL_FAN, VALUE(1), 0 }, + { SENSORS_LM87_FAN2_AIN2_LIMIT, "fan2/ain2_limit", SENSORS_LM87_FAN2_AIN2, + SENSORS_LM87_FAN2_AIN2, SENSORS_MODE_RW, + LM87_SYSCTL_FAN, VALUE(1), 0 }, + { SENSORS_LM87_FRONT_TEMP, "frnt_amb_temp", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_FRNT_TEMP, VALUE(3), 1 }, + { SENSORS_LM87_CPU_TEMP, "CPU_Temp", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_CPU_TEMP, VALUE(3), 1 }, + { SENSORS_LM87_INT_TEMP, "int_temp", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_INT_TEMP, VALUE(3), 1 }, + { SENSORS_LM87_INT_TEMP_HYST, "temp_hyst", SENSORS_LM87_INT_TEMP, + SENSORS_LM87_INT_TEMP, SENSORS_MODE_RW, + LM87_SYSCTL_INT_TEMP, VALUE(2), 1 }, + { SENSORS_LM87_INT_TEMP_OVER, "temp_over", SENSORS_LM87_INT_TEMP, + SENSORS_LM87_INT_TEMP, SENSORS_MODE_RW, + LM87_SYSCTL_INT_TEMP, VALUE(1), 1 }, + { SENSORS_LM87_VID, "vid", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_VID, VALUE(1), 2 }, + { SENSORS_LM87_FAN_DIV, "fan_div", SENSORS_LM87_FAN2_AIN2, + SENSORS_NO_MAPPING, SENSORS_MODE_RW, + LM87_SYSCTL_FAN_DIV, VALUE(1), 0 }, + { SENSORS_LM87_ALARMS, "alarms", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING, + SENSORS_MODE_R, LM87_SYSCTL_ALARMS, VALUE(1), 0 }, + { SENSORS_LM87_ANALOG_OUT, "analog_out", SENSORS_NO_MAPPING, + SENSORS_NO_MAPPING, SENSORS_MODE_RW, + LM87_SYSCTL_ANALOG_OUT, VALUE(1), 0 }, + { 0 } + }; + sensors_chip_features sensors_chip_features_list[] = { { SENSORS_LM78_PREFIX, lm78_features }, @@ -1814,6 +1897,7 @@ sensors_chip_features sensors_chip_features_list[] = { SENSORS_VIA686A_PREFIX, via686a_features }, { SENSORS_DDCMON_PREFIX, ddcmon_features }, { SENSORS_EEPROM_PREFIX, eeprom_features }, + { SENSORS_LM87_PREFIX, lm87_features }, { 0 } }; diff --git a/lib/chips.h b/lib/chips.h index e4cbf930..a1afc8db 100644 --- a/lib/chips.h +++ b/lib/chips.h @@ -817,4 +817,41 @@ #define SENSORS_EEPROM_NUMROWS 14 #define SENSORS_EEPROM_BANKS 15 + +/* Analog Devices LM87 chips */ + +#define SENSORS_LM87_PREFIX "LM87" + +#define SENSORS_LM87_IN0 1 /* R */ +#define SENSORS_LM87_IN1 2 /* R */ +#define SENSORS_LM87_IN2 3 /* R */ +#define SENSORS_LM87_IN3 4 /* R */ +#define SENSORS_LM87_IN4 5 /* R */ +#define SENSORS_LM87_IN5 6 /* R */ +#define SENSORS_LM87_IN0_MIN 11 /* RW */ +#define SENSORS_LM87_IN1_MIN 12 /* RW */ +#define SENSORS_LM87_IN2_MIN 13 /* RW */ +#define SENSORS_LM87_IN3_MIN 14 /* RW */ +#define SENSORS_LM87_IN4_MIN 15 /* RW */ +#define SENSORS_LM87_IN5_MIN 16 /* RW */ +#define SENSORS_LM87_IN0_MAX 21 /* RW */ +#define SENSORS_LM87_IN1_MAX 22 /* RW */ +#define SENSORS_LM87_IN2_MAX 23 /* RW */ +#define SENSORS_LM87_IN3_MAX 24 /* RW */ +#define SENSORS_LM87_IN4_MAX 25 /* RW */ +#define SENSORS_LM87_IN5_MAX 26 /* RW */ +#define SENSORS_LM87_FAN1_AIN1 31 /* R */ +#define SENSORS_LM87_FAN2_AIN2 32 /* R */ +#define SENSORS_LM87_FAN1_AIN1_LIMIT 41 /* RW */ +#define SENSORS_LM87_FAN2_AIN2_LIMIT 42 /* RW */ +#define SENSORS_LM87_FRONT_TEMP 51 /* R */ +#define SENSORS_LM87_CPU_TEMP 52 /* R */ +#define SENSORS_LM87_INT_TEMP 53 /* R */ +#define SENSORS_LM87_INT_TEMP_HYST 54 /* RW */ +#define SENSORS_LM87_INT_TEMP_OVER 55 /* RW */ +#define SENSORS_LM87_VID 61 /* R */ +#define SENSORS_LM87_FAN_DIV 71 /* RW */ +#define SENSORS_LM87_ALARMS 81 /* R */ +#define SENSORS_LM87_ANALOG_OUT 82 /* RW */ + #endif /* def LIB_SENSORS_CHIPS_H */