2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-08-31 14:25:39 +00:00

Initial checkin of adm1024 driver and support in libsensors,

sensors, sensors-detect.


git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1090 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Mark D. Studebaker
2001-05-15 03:18:18 +00:00
parent 01bf598239
commit d431a88833
14 changed files with 1337 additions and 5 deletions

View File

@@ -33,9 +33,10 @@ ask CVS about it:
Include file i2c-isa.h: No longer required, moved to i2c.h in i2c package
Include file sensors.h: Most contents moved to i2c-proc.h in i2c package
Library: Fix/standardize some lm87 and mtp008 entries; add sis5595 in4;
Add support for maxilife-nba.
Add support for maxilife-nba and amd1024.
Chip Modules (all ISA): Remove #include "i2c-isa.h"
Module adm1021: Fix lm84 and gl523sm support
Module adm1024: new
Module i2c-i801: Chip detection cleanup
Module i2c-i810: Fixed i2c_i810_init() not found in patched kernel
Module i2c-sis5595: Allow force_addr=0xaddr; enable if not enabled.
@@ -60,11 +61,11 @@ ask CVS about it:
Program sensors: Change reported version from 1.3 to the lm_sensors version;
Fix swapped limit and hysteresis on 9240, 5595, 686a;
Change mtp008 temps from max/min to limit/hyst;
Add maxilife-nba support.
Add maxilife-nba and adm1024 support.
Program sensors-detect: Recognize lm78 with chipid=0x20;
Recognize SMSC Victory66 South Bridge;
Add devfs /dev/i2c/x support;
Add thinkpad warning.
Add adm1024 support; Add thinkpad warning.
Program tellerstats: new
2.5.5 (20010115)

View File

@@ -56,3 +56,5 @@ problems.
Author of the adm1025 driver.
* Kris Van Hees <aedil@alchar.org>
Author of the mtp008 chip driver.
* Ken Bowley <ken@opnix.com>
Author of the adm1024 driver

2
README
View File

@@ -46,7 +46,7 @@ At least the following I2C/SMBus adapters are supported:
At least the following hardware sensor chips are supported:
Analog Devices ADM1021, ADM1021A, ADM1022,
ADM1023, ADM1025, and ADM9240
ADM1023, ADM1024, ADM1025, and ADM9240
Asus AS99127F
Dallas Semiconductor DS75, DS1621, DS1625, DS1775, and DS1780
Hewlett Packard Maxilife (several revisions including '99 NBA)

12
doc/chips/adm1024 Normal file
View File

@@ -0,0 +1,12 @@
Kernel driver `adm1024.o'
=========================
Status: Complete; Alpha.
Supported chips:
* Analog Devices ADM1024
Prefix `adm1024'
Addresses scanned: I2C 0x2c - 0x2e (inclusive)
Datasheet: Publicly available at the Analog Devices website
Author: Ken Bowley <ken@opnix.com>

View File

@@ -924,3 +924,16 @@ chip "adm9240-*" "ds1780-*" "lm81-*"
# compute "12V" xxx
# compute Vccp2 xxx
# compute temp xxx
chip "adm1024-*"
#
# These settings work for me, adjust for your system
#
label fan1 "CPU1 fan"
label fan2 "CPU2 fan"
label temp "SYS Temp"
label temp1 "CPU2 Temp"
label temp2 "CPU1 Temp"
ignore "2.5V" # This register is also used for temp2
ignore "Vccp1"
ignore "Vccp2"

View File

@@ -29,6 +29,7 @@ KERNELCHIPSTARGETS := $(MODULE_DIR)/bt869.o $(MODULE_DIR)/gl520sm.o \
$(MODULE_DIR)/via686a.o \
$(MODULE_DIR)/ddcmon.o \
$(MODULE_DIR)/adm1025.o \
$(MODULE_DIR)/adm1024.o \
$(MODULE_DIR)/lm87.o \
$(MODULE_DIR)/mtp008.o
ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM1021=y' $(LINUX)/.config; then echo 1; fi),1)

932
kernel/chips/adm1024.c Normal file
View File

@@ -0,0 +1,932 @@
/*
adm1024.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Add by Ken Bowley <ken@opnix.com> from the adm1025.c written by
Gordon Wu <gwu@esoft.com> and from adm9240.c written by
Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl>
and Philip Edelbrock <phil@netroedge.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports the Analog Devices ADM1024. See doc/chips/adm1024 for details */
#include <linux/version.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
#include <linux/sysctl.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include "version.h"
#include "sensors.h"
#include <linux/init.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18)) || \
(LINUX_VERSION_CODE == KERNEL_VERSION(2,3,0))
#define init_MUTEX(s) do { *(s) = MUTEX; } while(0)
#endif
#ifndef THIS_MODULE
#define THIS_MODULE NULL
#endif
/* Addresses to scan */
static unsigned short normal_i2c[] = { SENSORS_I2C_END };
static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, 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(adm1024);
/* Many ADM1024 constants specified below */
#define ADM1024_REG_IN_MAX(nr) (0x2b + (nr) * 2)
#define ADM1024_REG_IN_MIN(nr) (0x2c + (nr) * 2)
#define ADM1024_REG_IN(nr) (0x20 + (nr))
/* The ADM1024 registers */
#define ADM1024_REG_INT_TEMP_TRIP_SET 0x13
#define ADM1024_REG_EXT_TEMP_TRIP_SET 0x14
#define ADM1024_REG_TEST 0x15
#define ADM1024_REG_CHANNEL_MODE 0x16
#define ADM1024_REG_INT_TEMP_TRIP 0x17 /* read only */
#define ADM1024_REG_EXT_TEMP_TRIP 0x18 /* read only */
#define ADM1024_REG_ANALOG_OUT 0x19
#define ADM1024_REG_AIN1_LOW_LIMIT 0x1A
#define ADM1024_REG_AIN2_LOW_LIMIT 0x1B
/* These are all read-only */
#define ADM1024_REG_2_5V 0x20 /* 2.5V Measured Value/EXT Temp 2 */
#define ADM1024_REG_VCCP1 0x21
#define ADM1024_REG_3_3V 0x22 /* VCC Measured Value */
#define ADM1024_REG_5V 0x23
#define ADM1024_REG_12V 0x24
#define ADM1024_REG_VCCP2 0x25
#define ADM1024_REG_EXT_TEMP1 0x26
#define ADM1024_REG_TEMP 0x27
#define ADM1024_REG_FAN1 0x28 /* FAN1/AIN1 Value */
#define ADM1024_REG_FAN2 0x29 /* FAN2/AIN2 Value */
#define ADM1024_REG_COMPANY_ID 0x3E /* 0x41 for ADM1024 */
#define ADM1024_REG_DIE_REV 0x3F
/* These are read/write */
#define ADM1024_REG_2_5V_HIGH 0x2B /* 2.5V/Ext Temp2 High Limit */
#define ADM1024_REG_2_5V_LOW 0x2C /* 2.5V/Ext Temp2 Low Limit */
#define ADM1024_REG_VCCP1_HIGH 0x2D
#define ADM1024_REG_VCCP1_LOW 0x2E
#define ADM1024_REG_3_3V_HIGH 0x2F /* VCC High Limit */
#define ADM1024_REG_3_3V_LOW 0x30 /* VCC Low Limit */
#define ADM1024_REG_5V_HIGH 0x31
#define ADM1024_REG_5V_LOW 0x32
#define ADM1024_REG_12V_HIGH 0x33
#define ADM1024_REG_12V_LOW 0x34
#define ADM1024_REG_VCCP2_HIGH 0x35
#define ADM1024_REG_VCCP2_LOW 0x36
#define ADM1024_REG_EXT_TEMP1_HIGH 0x37
#define ADM1024_REG_EXT_TEMP1_LOW 0x38
#define ADM1024_REG_TOS 0x39
#define ADM1024_REG_THYST 0x3A
#define ADM1024_REG_FAN1_MIN 0x3B
#define ADM1024_REG_FAN2_MIN 0x3C
#define ADM1024_REG_CONFIG 0x40
#define ADM1024_REG_INT1_STAT 0x41
#define ADM1024_REG_INT2_STAT 0x42
#define ADM1024_REG_INT1_MASK 0x43
#define ADM1024_REG_INT2_MASK 0x44
#define ADM1024_REG_CHASSIS_CLEAR 0x46
#define ADM1024_REG_VID_FAN_DIV 0x47
#define ADM1024_REG_I2C_ADDR 0x48
#define ADM1024_REG_VID4 0x49
#define ADM1024_REG_CONFIG2 0x4A
#define ADM1024_REG_TEMP_CONFIG 0x4B
#define ADM1024_REG_EXTMODE1 0x4C /* Interupt Status Register Mirror No. 1 */
#define ADM1024_REG_EXTMODE2 0x4D /* Interupt Status Register Mirror No. 2 */
/* 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)<256?((((temp)&0x1fe) >> 1) * 10) + ((temp) & 1) * 5: \
((((temp)&0x1fe) >> 1) -255) * 10 - ((temp) & 1) * 5) \
#define EXT_TEMP_FROM_REG(temp) (((temp)>0x80?(temp)-0x100:(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)
#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 ADM1024_INIT_IN_0 190
#define ADM1024_INIT_IN_1 190
#define ADM1024_INIT_IN_2 190
#define ADM1024_INIT_IN_3 190
#define ADM1024_INIT_IN_4 190
#define ADM1024_INIT_IN_5 190
#define ADM1024_INIT_IN_PERCENTAGE 10
#define ADM1024_INIT_IN_MIN_0 \
(ADM1024_INIT_IN_0 - ADM1024_INIT_IN_0 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_0 \
(ADM1024_INIT_IN_0 + ADM1024_INIT_IN_0 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MIN_1 \
(ADM1024_INIT_IN_1 - ADM1024_INIT_IN_1 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_1 \
(ADM1024_INIT_IN_1 + ADM1024_INIT_IN_1 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MIN_2 \
(ADM1024_INIT_IN_2 - ADM1024_INIT_IN_2 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_2 \
(ADM1024_INIT_IN_2 + ADM1024_INIT_IN_2 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MIN_3 \
(ADM1024_INIT_IN_3 - ADM1024_INIT_IN_3 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_3 \
(ADM1024_INIT_IN_3 + ADM1024_INIT_IN_3 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MIN_4 \
(ADM1024_INIT_IN_4 - ADM1024_INIT_IN_4 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_4 \
(ADM1024_INIT_IN_4 + ADM1024_INIT_IN_4 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MIN_5 \
(ADM1024_INIT_IN_5 - ADM1024_INIT_IN_5 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_IN_MAX_5 \
(ADM1024_INIT_IN_5 + ADM1024_INIT_IN_5 * ADM1024_INIT_IN_PERCENTAGE / 100)
#define ADM1024_INIT_FAN_MIN_1 3000
#define ADM1024_INIT_FAN_MIN_2 3000
#define ADM1024_INIT_TEMP_OS_MAX 600
#define ADM1024_INIT_TEMP_OS_HYST 500
#define ADM1024_INIT_TEMP_HOT_MAX 700
#define ADM1024_INIT_TEMP_HOT_HYST 600
#ifdef MODULE
extern int init_module(void);
extern int cleanup_module(void);
#endif /* MODULE */
/* For each registered ADM1024, we need to keep some data in memory. That
data is pointed to by adm1024_list[NR]->data. The structure itself is
dynamically allocated, at the same time when a new adm1024 client is
allocated. */
struct adm1024_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[2]; /* Register value */
u8 fan_min[2]; /* Register value */
u8 fan_div[2]; /* Register encoding, shifted right */
int temp; /* Temp, shifted right */
u8 temp_os_max; /* Register value */
u8 temp_os_hyst; /* Register value */
int temp1; /* Ext Temp 1 */
u8 temp1_os_max;
u8 temp1_os_hyst;
int temp2; /* Ext Temp 2 */
u8 temp2_os_max;
u8 temp2_os_hyst;
u16 alarms; /* Register encoding, combined */
u8 analog_out; /* Register value */
u8 vid; /* Register value combined */
};
#ifdef MODULE
static
#else
extern
#endif
int __init sensors_adm1024_init(void);
static int __init adm1024_cleanup(void);
static int adm1024_attach_adapter(struct i2c_adapter *adapter);
static int adm1024_detect(struct i2c_adapter *adapter, int address,
unsigned short flags, int kind);
static int adm1024_detach_client(struct i2c_client *client);
static int adm1024_command(struct i2c_client *client, unsigned int cmd,
void *arg);
static void adm1024_inc_use(struct i2c_client *client);
static void adm1024_dec_use(struct i2c_client *client);
static int adm1024_read_value(struct i2c_client *client, u8 register);
static int adm1024_write_value(struct i2c_client *client, u8 register,
u8 value);
static void adm1024_update_client(struct i2c_client *client);
static void adm1024_init_client(struct i2c_client *client);
static void adm1024_in(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_fan(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_temp(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_temp1(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_temp2(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_alarms(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_fan_div(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void adm1024_analog_out(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag,
long *results);
static void adm1024_vid(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
/* I choose here for semi-static ADM1024 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 adm1024_id = 0;
static struct i2c_driver adm1024_driver = {
/* name */ "ADM1024 sensor driver",
/* id */ I2C_DRIVERID_ADM1024,
/* flags */ I2C_DF_NOTIFY,
/* attach_adapter */ &adm1024_attach_adapter,
/* detach_client */ &adm1024_detach_client,
/* command */ &adm1024_command,
/* inc_use */ &adm1024_inc_use,
/* dec_use */ &adm1024_dec_use
};
/* Used by adm1024_init/cleanup */
static int __initdata adm1024_initialized = 0;
/* The /proc/sys entries */
/* These files are created for each detected ADM1024. 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 adm1024_dir_table_template[] = {
{ADM1024_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_IN5, "in5", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_in},
{ADM1024_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_fan},
{ADM1024_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_fan},
{ADM1024_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_temp},
{ADM1024_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_temp1},
{ADM1024_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_temp2},
{ADM1024_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_fan_div},
{ADM1024_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_alarms},
{ADM1024_SYSCTL_ANALOG_OUT, "analog_out", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_analog_out},
{ADM1024_SYSCTL_VID, "vid", NULL, 0, 0444, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &adm1024_vid},
{0}
};
int adm1024_attach_adapter(struct i2c_adapter *adapter)
{
return sensors_detect(adapter, &addr_data, adm1024_detect);
}
static int adm1024_detect(struct i2c_adapter *adapter, int address,
unsigned short flags, int kind)
{
int i;
struct i2c_client *new_client;
struct adm1024_data *data;
int err = 0;
const char *type_name = "";
const char *client_name = "";
/* Make sure we aren't probing the ISA bus!! This is just a safety check
at this moment; sensors_detect really won't call us. */
#ifdef DEBUG
if (i2c_is_isa_adapter(adapter)) {
printk
("adm1024.o: adm1024_detect called for an ISA bus adapter?!?\n");
return 0;
}
#endif
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 adm1024_{read,write}_value. */
if (!(new_client = kmalloc(sizeof(struct i2c_client) +
sizeof(struct adm1024_data),
GFP_KERNEL))) {
err = -ENOMEM;
goto ERROR0;
}
data = (struct adm1024_data *) (new_client + 1);
new_client->addr = address;
new_client->data = data;
new_client->adapter = adapter;
new_client->driver = &adm1024_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. */
if (kind < 0) {
if((adm1024_read_value(new_client, ADM1024_REG_CONFIG) & 0x80) != 0x00)
goto ERROR1;
}
/* Determine the chip type. */
if (kind <= 0) {
i = adm1024_read_value(new_client, ADM1024_REG_COMPANY_ID);
if (i == 0x41)
kind = adm1024;
else {
if (kind == 0)
printk
("adm1024.o: Ignoring 'force' parameter for unknown chip at "
"adapter %d, address 0x%02x\n",
i2c_adapter_id(adapter), address);
goto ERROR1;
}
}
if (kind == adm1024) {
type_name = "adm1024";
client_name = "ADM1024 chip";
} else {
#ifdef DEBUG
printk("adm1024.o: Internal error: unknown kind (%d)?!?",
kind);
#endif
goto ERROR1;
}
/* Fill in the remaining client fields and put it into the global list */
strcpy(new_client->name, client_name);
data->type = kind;
new_client->id = adm1024_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,
adm1024_dir_table_template,
THIS_MODULE)) < 0) {
err = i;
goto ERROR4;
}
data->sysctl_id = i;
/* Initialize the ADM1024 chip */
adm1024_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 adm1024_detach_client(struct i2c_client *client)
{
int err;
sensors_deregister_entry(((struct adm1024_data *) (client->data))->
sysctl_id);
if ((err = i2c_detach_client(client))) {
printk
("adm1024.o: Client deregistration failed, client not detached.\n");
return err;
}
kfree(client);
return 0;
}
/* No commands defined yet */
int adm1024_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
return 0;
}
void adm1024_inc_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
void adm1024_dec_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
int adm1024_read_value(struct i2c_client *client, u8 reg)
{
return 0xFF & i2c_smbus_read_byte_data(client, reg);
}
int adm1024_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 ADM1024. It should set limits, etc. */
void adm1024_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 */
adm1024_write_value(client, ADM1024_REG_CONFIG, 0x80);
adm1024_write_value(client, ADM1024_REG_IN_MIN(0),
IN_TO_REG(ADM1024_INIT_IN_MIN_0, 0));
adm1024_write_value(client, ADM1024_REG_IN_MAX(0),
IN_TO_REG(ADM1024_INIT_IN_MAX_0, 0));
adm1024_write_value(client, ADM1024_REG_IN_MIN(1),
IN_TO_REG(ADM1024_INIT_IN_MIN_1, 1));
adm1024_write_value(client, ADM1024_REG_IN_MAX(1),
IN_TO_REG(ADM1024_INIT_IN_MAX_1, 1));
adm1024_write_value(client, ADM1024_REG_IN_MIN(2),
IN_TO_REG(ADM1024_INIT_IN_MIN_2, 2));
adm1024_write_value(client, ADM1024_REG_IN_MAX(2),
IN_TO_REG(ADM1024_INIT_IN_MAX_2, 2));
adm1024_write_value(client, ADM1024_REG_IN_MIN(3),
IN_TO_REG(ADM1024_INIT_IN_MIN_3, 3));
adm1024_write_value(client, ADM1024_REG_IN_MAX(3),
IN_TO_REG(ADM1024_INIT_IN_MAX_3, 3));
adm1024_write_value(client, ADM1024_REG_IN_MIN(4),
IN_TO_REG(ADM1024_INIT_IN_MIN_4, 4));
adm1024_write_value(client, ADM1024_REG_IN_MAX(4),
IN_TO_REG(ADM1024_INIT_IN_MAX_4, 4));
adm1024_write_value(client, ADM1024_REG_IN_MIN(5),
IN_TO_REG(ADM1024_INIT_IN_MIN_5, 5));
adm1024_write_value(client, ADM1024_REG_IN_MAX(5),
IN_TO_REG(ADM1024_INIT_IN_MAX_5, 5));
adm1024_write_value(client, ADM1024_REG_FAN1_MIN,
FAN_TO_REG(ADM1024_INIT_FAN_MIN_1, 2));
adm1024_write_value(client, ADM1024_REG_FAN2_MIN,
FAN_TO_REG(ADM1024_INIT_FAN_MIN_2, 2));
adm1024_write_value(client, ADM1024_REG_TOS,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_MAX));
adm1024_write_value(client, ADM1024_REG_THYST,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_HYST));
adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_HIGH,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_MAX));
adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_LOW,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_HYST));
adm1024_write_value(client, ADM1024_REG_2_5V_HIGH,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_MAX));
adm1024_write_value(client, ADM1024_REG_2_5V_LOW,
TEMP_LIMIT_TO_REG(ADM1024_INIT_TEMP_OS_HYST));
adm1024_write_value(client, ADM1024_REG_TEMP_CONFIG, 0x00);
/* Enable temperature channel 2 */
adm1024_write_value(client, ADM1024_REG_CHANNEL_MODE, adm1024_read_value(client, ADM1024_REG_CHANNEL_MODE) | 0x04);
/* Start monitoring */
adm1024_write_value(client, ADM1024_REG_CONFIG, 0x07);
}
void adm1024_update_client(struct i2c_client *client)
{
struct adm1024_data *data = client->data;
u8 i;
down(&data->update_lock);
if (
(jiffies - data->last_updated >
(data->type == adm1024 ? HZ / 2 : HZ * 2))
|| (jiffies < data->last_updated) || !data->valid) {
#ifdef DEBUG
printk("Starting adm1024 update\n");
#endif
for (i = 0; i <= 5; i++) {
data->in[i] =
adm1024_read_value(client, ADM1024_REG_IN(i));
data->in_min[i] =
adm1024_read_value(client,
ADM1024_REG_IN_MIN(i));
data->in_max[i] =
adm1024_read_value(client,
ADM1024_REG_IN_MAX(i));
}
data->fan[0] =
adm1024_read_value(client, ADM1024_REG_FAN1);
data->fan_min[0] =
adm1024_read_value(client, ADM1024_REG_FAN1_MIN);
data->fan[1] =
adm1024_read_value(client, ADM1024_REG_FAN2);
data->fan_min[1] =
adm1024_read_value(client, ADM1024_REG_FAN2_MIN);
data->temp =
(adm1024_read_value(client, ADM1024_REG_TEMP) << 1) +
((adm1024_read_value
(client, ADM1024_REG_TEMP_CONFIG) & 0x80) >> 7);
data->temp_os_max =
adm1024_read_value(client, ADM1024_REG_TOS);
data->temp_os_hyst =
adm1024_read_value(client, ADM1024_REG_THYST);
data->temp1 =
adm1024_read_value(client, ADM1024_REG_EXT_TEMP1);
data->temp1_os_max =
adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_HIGH);
data->temp1_os_hyst =
adm1024_read_value(client, ADM1024_REG_EXT_TEMP1_LOW);
data->temp2 =
adm1024_read_value(client, ADM1024_REG_2_5V);
data->temp2_os_max =
adm1024_read_value(client, ADM1024_REG_2_5V_HIGH);
data->temp2_os_hyst =
adm1024_read_value(client, ADM1024_REG_2_5V_LOW);
i = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
data->vid = i & 0x0f;
data->vid |=
(adm1024_read_value(client, ADM1024_REG_VID4) & 0x01)
<< 4;
data->alarms =
adm1024_read_value(client,
ADM1024_REG_INT1_STAT) +
(adm1024_read_value(client, ADM1024_REG_INT2_STAT) <<
8);
data->analog_out =
adm1024_read_value(client, ADM1024_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 adm1024_in(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
int scales[6] = { 250, 225, 330, 500, 1200, 270 };
struct adm1024_data *data = client->data;
int nr = ctl_name - ADM1024_SYSCTL_IN0;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 2;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_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);
adm1024_write_value(client, ADM1024_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);
adm1024_write_value(client, ADM1024_REG_IN_MAX(nr),
data->in_max[nr]);
}
}
}
void adm1024_fan(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
int nr = ctl_name - ADM1024_SYSCTL_FAN1 + 1;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = FAN_FROM_REG(data->fan_min[nr - 1],
DIV_FROM_REG(data->
fan_div[nr - 1]));
results[1] =
FAN_FROM_REG(data->fan[nr - 1],
DIV_FROM_REG(data->fan_div[nr - 1]));
*nrels_mag = 2;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->fan_min[nr - 1] = FAN_TO_REG(results[0],
DIV_FROM_REG
(data->
fan_div[nr -
1]));
adm1024_write_value(client,
nr ==
1 ? ADM1024_REG_FAN1_MIN :
ADM1024_REG_FAN2_MIN,
data->fan_min[nr - 1]);
}
}
}
void adm1024_temp(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 1;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = TEMP_LIMIT_FROM_REG(data->temp_os_max);
results[1] = TEMP_LIMIT_FROM_REG(data->temp_os_hyst);
results[2] = TEMP_FROM_REG(data->temp);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->temp_os_max = TEMP_LIMIT_TO_REG(results[0]);
adm1024_write_value(client, ADM1024_REG_TOS,
data->temp_os_max);
}
if (*nrels_mag >= 2) {
data->temp_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
adm1024_write_value(client, ADM1024_REG_THYST,
data->temp_os_hyst);
}
}
}
void adm1024_temp1(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 1;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = TEMP_LIMIT_FROM_REG(data->temp1_os_max);
results[1] = TEMP_LIMIT_FROM_REG(data->temp1_os_hyst);
results[2] = EXT_TEMP_FROM_REG(data->temp1);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->temp1_os_max = TEMP_LIMIT_TO_REG(results[0]);
adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_HIGH,
data->temp1_os_max);
}
if (*nrels_mag >= 2) {
data->temp1_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
adm1024_write_value(client, ADM1024_REG_EXT_TEMP1_LOW,
data->temp1_os_hyst);
}
}
}
void adm1024_temp2(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 1;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = TEMP_LIMIT_FROM_REG(data->temp2_os_max);
results[1] = TEMP_LIMIT_FROM_REG(data->temp2_os_hyst);
results[2] = EXT_TEMP_FROM_REG(data->temp2);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->temp2_os_max = TEMP_LIMIT_TO_REG(results[0]);
adm1024_write_value(client, ADM1024_REG_2_5V_HIGH,
data->temp2_os_max);
}
if (*nrels_mag >= 2) {
data->temp2_os_hyst = TEMP_LIMIT_TO_REG(results[1]);
adm1024_write_value(client, ADM1024_REG_2_5V_LOW,
data->temp2_os_hyst);
}
}
}
void adm1024_alarms(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = ALARMS_FROM_REG(data->alarms);
*nrels_mag = 1;
}
}
void adm1024_fan_div(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
int old;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = DIV_FROM_REG(data->fan_div[0]);
results[1] = DIV_FROM_REG(data->fan_div[1]);
*nrels_mag = 2;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
old = adm1024_read_value(client, ADM1024_REG_VID_FAN_DIV);
if (*nrels_mag >= 2) {
data->fan_div[1] = DIV_TO_REG(results[1]);
old = (old & 0x3f) | (data->fan_div[1] << 6);
}
if (*nrels_mag >= 1) {
data->fan_div[0] = DIV_TO_REG(results[0]);
old = (old & 0xcf) | (data->fan_div[0] << 4);
adm1024_write_value(client,
ADM1024_REG_VID_FAN_DIV, old);
}
}
}
void adm1024_analog_out(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_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];
adm1024_write_value(client, ADM1024_REG_ANALOG_OUT,
data->analog_out);
}
}
}
void adm1024_vid(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct adm1024_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 2;
else if (operation == SENSORS_PROC_REAL_READ) {
adm1024_update_client(client);
results[0] = VID_FROM_REG(data->vid);
*nrels_mag = 1;
}
}
int __init sensors_adm1024_init(void)
{
int res;
printk("adm1024.o version %s (%s)\n", LM_VERSION, LM_DATE);
adm1024_initialized = 0;
if ((res = i2c_add_driver(&adm1024_driver))) {
printk
("adm1024.o: Driver registration failed, module not inserted.\n");
adm1024_cleanup();
return res;
}
adm1024_initialized++;
return 0;
}
int __init adm1024_cleanup(void)
{
int res;
if (adm1024_initialized >= 1) {
if ((res = i2c_del_driver(&adm1024_driver))) {
printk
("adm1024.o: Driver deregistration failed, module not removed.\n");
return res;
}
adm1024_initialized--;
}
return 0;
}
EXPORT_NO_SYMBOLS;
#ifdef MODULE
MODULE_AUTHOR
("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
MODULE_DESCRIPTION("ADM1024 driver");
int init_module(void)
{
return sensors_adm1024_init();
}
int cleanup_module(void)
{
return adm1024_cleanup();
}
#endif /* MODULE */

View File

@@ -209,6 +209,35 @@
#define ADM9240_ALARM_TEMP 0x0010
#define ADM9240_ALARM_CHAS 0x1000
#define ADM1024_SYSCTL_IN0 1000 /* Volts * 100 */
#define ADM1024_SYSCTL_IN1 1001
#define ADM1024_SYSCTL_IN2 1002
#define ADM1024_SYSCTL_IN3 1003
#define ADM1024_SYSCTL_IN4 1004
#define ADM1024_SYSCTL_IN5 1005
#define ADM1024_SYSCTL_FAN1 1101 /* Rotations/min */
#define ADM1024_SYSCTL_FAN2 1102
#define ADM1024_SYSCTL_TEMP 1250 /* Degrees Celcius * 100 */
#define ADM1024_SYSCTL_TEMP1 1290 /* Degrees Celcius */
#define ADM1024_SYSCTL_TEMP2 1295 /* Degrees Celcius */
#define ADM1024_SYSCTL_FAN_DIV 2000 /* 1, 2, 4 or 8 */
#define ADM1024_SYSCTL_ALARMS 2001 /* bitvector */
#define ADM1024_SYSCTL_ANALOG_OUT 2002
#define ADM1024_SYSCTL_VID 2003
#define ADM1024_ALARM_IN0 0x0001
#define ADM1024_ALARM_IN1 0x0002
#define ADM1024_ALARM_IN2 0x0004
#define ADM1024_ALARM_IN3 0x0008
#define ADM1024_ALARM_IN4 0x0100
#define ADM1024_ALARM_IN5 0x0200
#define ADM1024_ALARM_FAN1 0x0040
#define ADM1024_ALARM_FAN2 0x0080
#define ADM1024_ALARM_TEMP 0x0010
#define ADM1024_ALARM_TEMP1 0x0020
#define ADM1024_ALARM_TEMP2 0x0001
#define ADM1024_ALARM_CHAS 0x1000
#define ADM1025_SYSCTL_IN0 1000 /* Volts * 100 */
#define ADM1025_SYSCTL_IN1 1001
#define ADM1025_SYSCTL_IN2 1002

View File

@@ -1099,6 +1099,107 @@ static sensors_chip_feature adm9240_features[] =
{ 0 }
};
static sensors_chip_feature adm1024_features[] =
{
{ SENSORS_ADM1024_IN0, "2.5V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN0, VALUE(3), 2 },
{ SENSORS_ADM1024_IN1, "Vccp1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN1, VALUE(3), 2 },
{ SENSORS_ADM1024_IN2, "3.3V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN2, VALUE(3), 2 },
{ SENSORS_ADM1024_IN3, "5V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN3, VALUE(3), 2 },
{ SENSORS_ADM1024_IN4, "12V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN4, VALUE(3), 2 },
{ SENSORS_ADM1024_IN5, "Vccp2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_IN5, VALUE(3), 2 },
{ SENSORS_ADM1024_IN0_MIN, "2.5V_min", SENSORS_ADM1024_IN0,
SENSORS_ADM1024_IN0, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN0, VALUE(1), 2 },
{ SENSORS_ADM1024_IN1_MIN, "Vccp1_min", SENSORS_ADM1024_IN1,
SENSORS_ADM1024_IN1, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN1, VALUE(1), 2 },
{ SENSORS_ADM1024_IN2_MIN, "3.3V_min", SENSORS_ADM1024_IN2,
SENSORS_ADM1024_IN2, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN2, VALUE(1), 2 },
{ SENSORS_ADM1024_IN3_MIN, "5V_min", SENSORS_ADM1024_IN3,
SENSORS_ADM1024_IN3, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN3, VALUE(1), 2 },
{ SENSORS_ADM1024_IN4_MIN, "12V_min", SENSORS_ADM1024_IN4,
SENSORS_ADM1024_IN4, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN4, VALUE(1), 2 },
{ SENSORS_ADM1024_IN5_MIN, "Vccp2_min", SENSORS_ADM1024_IN5,
SENSORS_ADM1024_IN5, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN5, VALUE(1), 2 },
{ SENSORS_ADM1024_IN0_MAX, "2.5V_max", SENSORS_ADM1024_IN0,
SENSORS_ADM1024_IN0, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN0, VALUE(2), 2 },
{ SENSORS_ADM1024_IN1_MAX, "Vccp1_max", SENSORS_ADM1024_IN1,
SENSORS_ADM1024_IN1, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN1, VALUE(2), 2 },
{ SENSORS_ADM1024_IN2_MAX, "3.3V_max", SENSORS_ADM1024_IN2,
SENSORS_ADM1024_IN2, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN2, VALUE(2), 2 },
{ SENSORS_ADM1024_IN3_MAX, "5V_max", SENSORS_ADM1024_IN3,
SENSORS_ADM1024_IN3, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN3, VALUE(2), 2 },
{ SENSORS_ADM1024_IN4_MAX, "12V_max", SENSORS_ADM1024_IN4,
SENSORS_ADM1024_IN4, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN4, VALUE(2), 2 },
{ SENSORS_ADM1024_IN5_MAX, "Vccp2_max", SENSORS_ADM1024_IN5,
SENSORS_ADM1024_IN5, SENSORS_MODE_RW,
ADM1024_SYSCTL_IN5, VALUE(2), 2 },
{ SENSORS_ADM1024_FAN1, "fan1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_FAN1, VALUE(2), 0 },
{ SENSORS_ADM1024_FAN2, "fan2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_FAN2, VALUE(2), 0 },
{ SENSORS_ADM1024_FAN1_MIN, "fan1_min", SENSORS_ADM1024_FAN1,
SENSORS_ADM1024_FAN1, SENSORS_MODE_RW,
ADM1024_SYSCTL_FAN1, VALUE(1), 0 },
{ SENSORS_ADM1024_FAN2_MIN, "fan2_min", SENSORS_ADM1024_FAN2,
SENSORS_ADM1024_FAN2, SENSORS_MODE_RW,
ADM1024_SYSCTL_FAN2, VALUE(1), 0 },
{ SENSORS_ADM1024_TEMP, "temp", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_TEMP, VALUE(3), 1 },
{ SENSORS_ADM1024_TEMP1, "temp1", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_TEMP1, VALUE(3), 1 },
{ SENSORS_ADM1024_TEMP2, "temp2", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_TEMP2, VALUE(3), 1 },
{ SENSORS_ADM1024_TEMP_HYST, "temp_hyst", SENSORS_ADM1024_TEMP,
SENSORS_ADM1024_TEMP, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP, VALUE(2), 1 },
{ SENSORS_ADM1024_TEMP_OVER, "temp_over", SENSORS_ADM1024_TEMP,
SENSORS_ADM1024_TEMP, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP, VALUE(1), 1 },
{ SENSORS_ADM1024_TEMP1_HYST, "temp1_hyst", SENSORS_ADM1024_TEMP1,
SENSORS_ADM1024_TEMP1, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP1, VALUE(2), 1 },
{ SENSORS_ADM1024_TEMP1_OVER, "temp1_over", SENSORS_ADM1024_TEMP1,
SENSORS_ADM1024_TEMP1, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP1, VALUE(1), 1 },
{ SENSORS_ADM1024_TEMP2_HYST, "temp2_hyst", SENSORS_ADM1024_TEMP2,
SENSORS_ADM1024_TEMP2, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP2, VALUE(2), 1 },
{ SENSORS_ADM1024_TEMP2_OVER, "temp2_over", SENSORS_ADM1024_TEMP2,
SENSORS_ADM1024_TEMP2, SENSORS_MODE_RW,
ADM1024_SYSCTL_TEMP2, VALUE(1), 1 },
{ SENSORS_ADM1024_VID, "vid", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_VID, VALUE(1), 2 },
{ SENSORS_ADM1024_FAN1_DIV, "fan1_div", SENSORS_ADM1024_FAN1,
SENSORS_NO_MAPPING, SENSORS_MODE_RW,
ADM1024_SYSCTL_FAN_DIV, VALUE(1), 0 },
{ SENSORS_ADM1024_FAN2_DIV, "fan2_div", SENSORS_ADM1024_FAN2,
SENSORS_NO_MAPPING, SENSORS_MODE_RW,
ADM1024_SYSCTL_FAN_DIV, VALUE(2), 0 },
{ SENSORS_ADM1024_ALARMS, "alarms", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, ADM1024_SYSCTL_ALARMS, VALUE(1), 0 },
{ SENSORS_ADM1024_ANALOG_OUT, "analog_out", SENSORS_NO_MAPPING,
SENSORS_NO_MAPPING, SENSORS_MODE_RW,
ADM1024_SYSCTL_ANALOG_OUT, VALUE(1), 0 },
{ 0 }
};
static sensors_chip_feature ds1780_features[] =
{
{ SENSORS_DS1780_IN0, "2.5V", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
@@ -2072,5 +2173,6 @@ sensors_chip_features sensors_chip_features_list[] =
{ SENSORS_LM87_PREFIX, lm87_features },
{ SENSORS_MTP008_PREFIX, mtp008_features },
{ SENSORS_DS1621_PREFIX, ds1621_features },
{ SENSORS_ADM1024_PREFIX, adm1024_features },
{ 0 }
};

View File

@@ -925,4 +925,45 @@
#define SENSORS_DS1621_TEMP_OVER 53 /* RW */
#define SENSORS_DS1621_ALARMS 81 /* R */
/* ADM1024 chip */
#define SENSORS_ADM1024_PREFIX "adm1024"
#define SENSORS_ADM1024_IN0 1 /* R */
#define SENSORS_ADM1024_IN1 2 /* R */
#define SENSORS_ADM1024_IN2 3 /* R */
#define SENSORS_ADM1024_IN3 4 /* R */
#define SENSORS_ADM1024_IN4 5 /* R */
#define SENSORS_ADM1024_IN5 6 /* R */
#define SENSORS_ADM1024_IN0_MIN 11 /* RW */
#define SENSORS_ADM1024_IN1_MIN 12 /* RW */
#define SENSORS_ADM1024_IN2_MIN 13 /* RW */
#define SENSORS_ADM1024_IN3_MIN 14 /* RW */
#define SENSORS_ADM1024_IN4_MIN 15 /* RW */
#define SENSORS_ADM1024_IN5_MIN 16 /* RW */
#define SENSORS_ADM1024_IN0_MAX 21 /* RW */
#define SENSORS_ADM1024_IN1_MAX 22 /* RW */
#define SENSORS_ADM1024_IN2_MAX 23 /* RW */
#define SENSORS_ADM1024_IN3_MAX 24 /* RW */
#define SENSORS_ADM1024_IN4_MAX 25 /* RW */
#define SENSORS_ADM1024_IN5_MAX 26 /* RW */
#define SENSORS_ADM1024_FAN1 31 /* R */
#define SENSORS_ADM1024_FAN2 32 /* R */
#define SENSORS_ADM1024_FAN1_MIN 41 /* RW */
#define SENSORS_ADM1024_FAN2_MIN 42 /* RW */
#define SENSORS_ADM1024_TEMP 51 /* R */
#define SENSORS_ADM1024_TEMP1 52 /* R */
#define SENSORS_ADM1024_TEMP2 53 /* R */
#define SENSORS_ADM1024_TEMP_HYST 61 /* RW */
#define SENSORS_ADM1024_TEMP_OVER 62 /* RW */
#define SENSORS_ADM1024_TEMP1_HYST 63 /* RW */
#define SENSORS_ADM1024_TEMP1_OVER 64 /* RW */
#define SENSORS_ADM1024_TEMP2_HYST 65 /* RW */
#define SENSORS_ADM1024_TEMP2_OVER 66 /* RW */
#define SENSORS_ADM1024_VID 71 /* R */
#define SENSORS_ADM1024_FAN1_DIV 81 /* RW */
#define SENSORS_ADM1024_FAN2_DIV 82 /* RW */
#define SENSORS_ADM1024_ALARMS 91 /* R */
#define SENSORS_ADM1024_ANALOG_OUT 92 /* RW */
#endif /* def LIB_SENSORS_CHIPS_H */

View File

@@ -376,7 +376,7 @@ use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect
adm9240_detect adm1021_detect sis5595_isa_detect eeprom_detect
via686a_isa_detect adm1022_detect ltc1710_detect gl525sm_detect
lm87_detect ite_detect ite_isa_detect ite_alias_detect
ddcmonitor_detect ds1621_detect);
ddcmonitor_detect ds1621_detect adm1024_detect);
# This is a list of all recognized chips.
# Each entry must have the following fields:
@@ -560,6 +560,12 @@ use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect
i2c_addrs => [0x2c..0x2e],
i2c_detect => sub { adm1025_detect 0, @_ }
},
{
name => "Analog Devices ADM1024",
driver => "adm1024",
i2c_addrs => [0x2c..0x2e],
i2c_detect => sub { adm1024_detect 0, @_ }
},
{
name => "Analog Devices ADM1021",
driver => "adm1021",
@@ -1865,6 +1871,26 @@ sub adm1025_detect
return (8);
}
# $_[0]: Chip to detect (0 = ADM1024)
# $_[1]: A reference to the file descriptor to access this chip.
# We may assume an i2c_set_slave_addr was already done.
# $_[2]: Address
# Returns: undef if not detected, (8) if detected.
# Registers used:
# 0x3e: Company ID
# 0x3f: Revision
# 0x40: Configuration
sub adm1024_detect
{
my $reg;
my ($chip, $file,$addr) = @_;
$reg = i2c_smbus_read_byte_data($file,0x3e);
return unless ($reg == 0x41);
return unless (i2c_smbus_read_byte_data($file,0x40) & 0x80) == 0x00;
return unless (i2c_smbus_read_byte_data($file,0x3f) & 0xe0) == 0x20;
return (8);
}
# $_[0]: Chip to detect
# (0 = ADM1021, 1 = MAX1617, 2 = MAX1617A, 3 = THMC10, 4 = LM84, 5 = GL523)
# $_[1]: A reference to the file descriptor to access this chip.

View File

@@ -392,6 +392,176 @@ void print_adm9240(const sensors_chip_name *name)
free_the_label(&label);
}
void print_adm1024(const sensors_chip_name *name)
{
char *label = NULL;
double cur,min,max,fdiv;
int alarms;
int valid;
if (!sensors_get_feature(*name,SENSORS_ADM1024_ALARMS,&cur))
alarms = cur + 0.5;
else {
printf("ERROR: Can't get alarm data!\n");
alarms = 0;
}
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN0,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN0,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN0_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN0_MAX,&max)) {
if (valid) {
print_label(label,10);
printf( "%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN0?"ALARM":"");
}
} else
printf("ERROR: Can't get IN0 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN1,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN1,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN1_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN1_MAX,&max)) {
if (valid) {
print_label(label,10);
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN1?"ALARM":"");
}
} else
printf("ERROR: Can't get IN1 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN2,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN2,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN2_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN2_MAX,&max)) {
if (valid) {
print_label(label,10);
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN2?"ALARM":"");
}
} else
printf("ERROR: Can't get IN2 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN3,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN3,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN3_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN3_MAX,&max)) {
if (valid) {
print_label(label,10);
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN3?"ALARM":"");
}
} else
printf("ERROR: Can't get IN3 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN4,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN4,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN4_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN4_MAX,&max)) {
if (valid) {
print_label(label,10);
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN4?"ALARM":"");
}
} else
printf("ERROR: Can't get IN4 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_IN5,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN5,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN5_MIN,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_IN5_MAX,&max)) {
if (valid) {
print_label(label,10);
printf("%+6.2f V (min = %+6.2f V, max = %+6.2f V) %s\n",
cur,min,max,alarms&ADM1024_ALARM_IN5?"ALARM":"");
}
} else
printf("ERROR: Can't get IN5 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_FAN1,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN1,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN1_DIV,&fdiv) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN1_MIN,&min)) {
if (valid) {
print_label(label,10);
printf("%4.0f RPM (min = %4.0f RPM, div = %1.0f) %s\n",
cur,min,fdiv, alarms&ADM1024_ALARM_FAN1?"ALARM":"");
}
} else
printf("ERROR: Can't get FAN1 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_FAN2,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN2,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN2_DIV,&fdiv) &&
!sensors_get_feature(*name,SENSORS_ADM1024_FAN2_MIN,&min)) {
if (valid) {
print_label(label,10);
printf("%4.0f RPM (min = %4.0f RPM, div = %1.0f) %s\n",
cur,min,fdiv, alarms&ADM1024_ALARM_FAN2?"ALARM":"");
}
} else
printf("ERROR: Can't get FAN2 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_TEMP,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP_HYST,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP_OVER,&max)) {
if (valid) {
print_label(label,10);
print_temp_info( cur, min, max, HYST );
printf( " %s\n", alarms & ADM1024_ALARM_TEMP ? "ALARM" : "" );
}
} else
printf("ERROR: Can't get TEMP data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_TEMP1,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP1,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP1_HYST,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP1_OVER,&max)) {
if (valid) {
print_label(label,10);
print_temp_info( cur, min, max, HYST );
printf( " %s\n", alarms & ADM1024_ALARM_TEMP1 ? "ALARM" : "" );
}
} else
printf("ERROR: Can't get TEMP1 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_TEMP2,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP2,&cur) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP2_HYST,&min) &&
!sensors_get_feature(*name,SENSORS_ADM1024_TEMP2_OVER,&max)) {
if (valid) {
print_label(label,10);
print_temp_info( cur, min, max, HYST );
printf( " %s\n", alarms & ADM1024_ALARM_TEMP2 ? "ALARM" : "" );
}
} else
printf("ERROR: Can't get TEMP2 data!\n");
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_VID,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_ADM1024_VID,&cur)) {
if (valid) {
print_label(label,10);
printf("%+5.2f V\n",cur);
}
}
free_the_label(&label);
if (!sensors_get_label_and_valid(*name,SENSORS_ADM1024_ALARMS,&label,&valid)) {
if (valid) {
print_label(label,10);
printf("Chassis intrusion detection %s\n",
alarms & ADM1024_ALARM_CHAS?"ALARM":" ");
}
}
free_the_label(&label);
}
void print_sis5595(const sensors_chip_name *name)
{
char *label = NULL;

View File

@@ -29,6 +29,7 @@ extern void print_mtp008(const sensors_chip_name *name);
extern void print_lm75(const sensors_chip_name *name);
extern void print_adm1021(const sensors_chip_name *name);
extern void print_adm1025(const sensors_chip_name *name);
extern void print_adm1024(const sensors_chip_name *name);
extern void print_adm9240(const sensors_chip_name *name);
extern void print_lm78(const sensors_chip_name *name);
extern void print_sis5595(const sensors_chip_name *name);

View File

@@ -310,6 +310,8 @@ void do_a_print(sensors_chip_name name)
print_gl518(&name);
else if (!strcmp(name.prefix,"adm1025"))
print_adm1025(&name);
else if (!strcmp(name.prefix,"adm1024"))
print_adm1024(&name);
else if ((!strcmp(name.prefix,"w83781d")) ||
(!strcmp(name.prefix,"w83782d")) ||
(!strcmp(name.prefix,"w83783s")) ||