2
0
mirror of https://github.com/lm-sensors/lm-sensors synced 2025-08-30 22:05:11 +00:00

(mds) add ds1621 driver from Christian Zuckschwerdt (zany@triq.net)

git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@935 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Mark D. Studebaker
2000-11-26 23:07:17 +00:00
parent bd1b923045
commit bb4b723e68
14 changed files with 694 additions and 6 deletions

View File

@@ -20,17 +20,18 @@ ask CVS about it:
2.5.5 (2000????)
Chip modules (all): Update mutex definition (works now for new 2.2 kernels)
File sensors.conf.eg: Add mtp008 entries
Library: Add mtp008 support
Library: Add ds1621, mtp008 support
Module adm1021: Add support for adm1021a / adm1023
Module i2c-ali1535: Enhance error checking and recovery; add mutex
Module ddcmon: allow force and force_ddcmon parameters
Module ds1621: new
Module i2c-ali1535: Enhance error checking and recovery; add mutex
Module lm87: update voltage calculations
Module mtp008: new
Module pcf8574: change update time to 5 seconds
Module w83781d: fix beep setting via /proc
Program mkpatch.pl: more fixes
Program sensors: Add mtp008 support, add -f (Fahrenheit) option
Program sensors-detect: Add mtp008 detection
Program sensors: Add ds1621, mtp008 support, add -f (Fahrenheit) option
Program sensors-detect: Add ds1621, mtp008 detection
2.5.4 (20001012)
Module i2c-viapro: Add support for Via 596B (0x3051)

2
README
View File

@@ -51,7 +51,7 @@ At least the following hardware sensor chips are supported:
Analog Devices ADM1021, ADM1021A, ADM1022,
ADM1023, ADM1025, and ADM9240
Asus AS99127F
Dallas Semiconductor DS1780, DS75, and DS1775
Dallas Semiconductor DS75, DS1621, DS1775, and DS1780
Hewlett Packard Maxilife (several revisions including '99 NBA)
Genesys Logic GL518SM (rev 00, 80), GL520SM, GL523SM
Intel Xeon processor embedded sensors

View File

@@ -56,6 +56,9 @@ adm9240
ds1780 1 6 2 1 dac yes no
lm81 1 6 2 1 dac yes no
ds1621
ds1621 1 - - - yes no
gl518sm
gl518sm (r00) 1 1-4 2 - yes no
gl518sm (r80) 1 4 2 - yes no

68
doc/chips/ds1621 Normal file
View File

@@ -0,0 +1,68 @@
Kernel driver `ds1621.o'
=====================
Status: Complete and tested, alarms experimental
Supported chips:
* Dallas Semiconductor DS1621
Prefix: `ds1621'
Addresses scanned: I2C 0x48 - 0x4f (inclusive)
Datasheet: Publicly available at the Dallas Semiconductor website
http://www.dalsemi.com
Author: Christian W. Zuckschwerdt <zany@triq.net>
Module Parameters
-----------------
* force: short array (min = 1, max = 48)
List of adapter,address pairs to boldly assume to be present
* force_ds1621: short array (min = 1, max = 48)
List of adapter,address pairs which are unquestionably assumed to contain
a `ds1621' chip
* ignore: short array (min = 1, max = 48)
List of adapter,address pairs not to scan
* ignore_range: short array (min = 1, max = 48)
List of adapter,start-addr,end-addr triples not to scan
* probe: short array (min = 1, max = 48)
List of adapter,address pairs to scan additionally
* probe_range: short array (min = 1, max = 48)
List of adapter,start-addr,end-addr triples to scan additionally
Description
-----------
The DS1621 implements one temperature sensor. Limits can be set through the
Overtemperature register and Hysteresis register. Each value can be
set and read to half-degree accuracy.
An alarm is issued when the temperature gets higher then the Overtemperature
value; or drops below the Hysteresis value.
It stays on until reset by the kernel module.
All temperatures are in degrees Celcius, and are guaranteed within a
range of -55 to +125 degrees.
The DS1621 supplies the temperature data in a format common with chips
like the LM75, LM77 and DS75, DS1775.
While the DS1621 has three additional bits of accuracy
(12 vs. 9 for the LM75), the additional bits are not supported.
Chip Features
-------------
Chip `ds1621'
LABEL LABEL CLASS COMPUTE CLASS ACCESS MAGNITUDE
temp NONE NONE R 1
temp_hyst temp temp RW 1
temp_over temp temp RW 1
alarms NONE NONE R 0
LABEL FEATURE SYMBOL SYSCTL FILE:OFFSET
temp SENSORS_DS1621_TEMP temp:3
temp_hyst SENSORS_DS1621_TEMP_HYST temp:2
temp_over SENSORS_DS1621_TEMP_OVER temp:1
alarms SENSORS_DS1621_ALARMS alarms:1

View File

@@ -37,6 +37,9 @@ endif
ifneq ($(shell if grep -q '^CONFIG_SENSORS_ADM9240=y' $(LINUX)/.config; then echo 1; fi),1)
KERNELCHIPSTARGETS += $(MODULE_DIR)/adm9240.o
endif
ifneq ($(shell if grep -q '^CONFIG_SENSORS_DS1621=y' $(LINUX)/.config; then echo 1; fi),1)
KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1621.o
endif
ifneq ($(shell if grep -q '^CONFIG_SENSORS_EEPROM=y' $(LINUX)/.config; then echo 1; fi),1)
KERNELCHIPSTARGETS += $(MODULE_DIR)/eeprom.o
endif

509
kernel/chips/ds1621.c Normal file
View File

@@ -0,0 +1,509 @@
/*
ds1621.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Christian W. Zuckschwerdt <zany@triq.net> 2000-11-23
based on lm75.c by Frodo Looijaard <frodol@dds.nl>
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 DS1621. See doc/chips/ds1621 for details */
#include <linux/version.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/i2c.h>
#include "sensors.h"
#include "i2c-isa.h"
#include "version.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[] = { 0x48, 0x4f, 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(ds1621);
/* Many DS1621 constants specified below - most aren't used */
/* Config register used for detection */
/* 7 6 5 4 3 2 1 0 */
/* |Done|THF |TLF |NVB | 1 | 0 |POL |1SHOT| */
#define DS1621_REG_CONFIG_MASK 0x0C
#define DS1621_REG_CONFIG_VAL 0x08
/* The DS1621 registers */
#define DS1621_REG_TEMP 0xAA /* word, RO */
#define DS1621_REG_TEMP_OVER 0xA1 /* word, RW */
#define DS1621_REG_TEMP_HYST 0xA2 /* word, RW -- it's a low temp trigger */
#define DS1621_REG_CONF 0xAC /* byte, RW */
#define DS1621_REG_TEMP_COUNTER 0xA8 /* byte, RO */
#define DS1621_REG_TEMP_SLOPE 0xA9 /* byte, RO */
#define DS1621_COM_START 0xEE /* no data */
#define DS1621_COM_STOP 0x22 /* no data */
/* 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 TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | \
((val & 0x8000)?-256:0))
#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0 ? (0x200+((val)/5))<<7 : \
(((val) + 2) / 5) << 7),0,0xffff))
#define ALARMS_FROM_REG(val) ((val) & \
(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
/* Initial values */
#define DS1621_INIT_TEMP_OVER 600
#define DS1621_INIT_TEMP_HYST 0 /* 500 would cause an alarm at room temp. */
/* Each client has this additional data */
struct ds1621_data {
int sysctl_id;
struct semaphore update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 temp, temp_over, temp_hyst; /* Register values */
u8 conf; /* Register encoding, combined */
};
#ifdef MODULE
extern int init_module(void);
extern int cleanup_module(void);
#endif /* MODULE */
#ifdef MODULE
static
#else
extern
#endif
int __init sensors_ds1621_init(void);
static int __init ds1621_cleanup(void);
static int ds1621_attach_adapter(struct i2c_adapter *adapter);
static int ds1621_detect(struct i2c_adapter *adapter, int address,
unsigned short flags, int kind);
static void ds1621_init_client(struct i2c_client *client);
static int ds1621_detach_client(struct i2c_client *client);
static int ds1621_command(struct i2c_client *client, unsigned int cmd,
void *arg);
static void ds1621_inc_use(struct i2c_client *client);
static void ds1621_dec_use(struct i2c_client *client);
static u16 swap_bytes(u16 val);
static int ds1621_read_value(struct i2c_client *client, u8 reg);
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value);
static void ds1621_temp(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void ds1621_alarms(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void ds1621_enable(struct i2c_client *client, int operation,
int ctl_name, int *nrels_mag, long *results);
static void ds1621_update_client(struct i2c_client *client);
/* This is the driver that will be inserted */
static struct i2c_driver ds1621_driver = {
/* name */ "DS1621 sensor driver",
/* id */ I2C_DRIVERID_DS1621,
/* flags */ I2C_DF_NOTIFY,
/* attach_adapter */ &ds1621_attach_adapter,
/* detach_client */ &ds1621_detach_client,
/* command */ &ds1621_command,
/* inc_use */ &ds1621_inc_use,
/* dec_use */ &ds1621_dec_use
};
/* These files are created for each detected DS1621. 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 ds1621_dir_table_template[] = {
{DS1621_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &sensors_proc_real,
&sensors_sysctl_real, NULL, &ds1621_temp},
{DS1621_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL,
&sensors_proc_real, &sensors_sysctl_real, NULL, &ds1621_alarms},
{DS1621_SYSCTL_ENABLE, "enable", NULL, 0, 0644, NULL,
&sensors_proc_real, &sensors_sysctl_real, NULL, &ds1621_enable},
{0}
};
/* Used by init/cleanup */
static int __initdata ds1621_initialized = 0;
static int ds1621_id = 0;
int ds1621_attach_adapter(struct i2c_adapter *adapter)
{
return sensors_detect(adapter, &addr_data, ds1621_detect);
}
/* This function is called by sensors_detect */
int ds1621_detect(struct i2c_adapter *adapter, int address,
unsigned short flags, int kind)
{
int i, conf;
struct i2c_client *new_client;
struct ds1621_data *data;
int err = 0;
const char *type_name, *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
("ds1621.o: ds1621_detect called for an ISA bus adapter?!?\n");
return 0;
}
#endif
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_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 ds1621_{read,write}_value. */
if (!(new_client = kmalloc(sizeof(struct i2c_client) +
sizeof(struct ds1621_data),
GFP_KERNEL))) {
err = -ENOMEM;
goto ERROR0;
}
data = (struct ds1621_data *) (new_client + 1);
new_client->addr = address;
new_client->data = data;
new_client->adapter = adapter;
new_client->driver = &ds1621_driver;
new_client->flags = 0;
/* Now, we do the remaining detection. It is lousy. */
if (kind < 0) {
conf = i2c_smbus_read_byte_data(new_client,
DS1621_REG_CONF);
if ((conf & DS1621_REG_CONFIG_MASK)
!= DS1621_REG_CONFIG_VAL)
goto ERROR1;
}
/* Determine the chip type - only one kind supported! */
if (kind <= 0)
kind = ds1621;
if (kind == ds1621) {
type_name = "ds1621";
client_name = "DS1621 chip";
} else {
#ifdef DEBUG
printk("ds1621.o: Internal error: unknown kind (%d)?!?",
kind);
#endif
goto ERROR1;
}
/* Fill in remaining client fields and put it into the global list */
strcpy(new_client->name, client_name);
new_client->id = ds1621_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,
ds1621_dir_table_template,
THIS_MODULE)) < 0) {
err = i;
goto ERROR4;
}
data->sysctl_id = i;
ds1621_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 ds1621_detach_client(struct i2c_client *client)
{
int err;
#ifdef MODULE
if (MOD_IN_USE)
return -EBUSY;
#endif
sensors_deregister_entry(((struct ds1621_data *) (client->data))->
sysctl_id);
if ((err = i2c_detach_client(client))) {
printk
("ds1621.o: Client deregistration failed, client not detached.\n");
return err;
}
kfree(client);
return 0;
}
/* No commands defined yet */
int ds1621_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
return 0;
}
/* Nothing here yet */
void ds1621_inc_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
}
/* Nothing here yet */
void ds1621_dec_use(struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
u16 swap_bytes(u16 val)
{
return (val >> 8) | (val << 8);
}
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
the usual practice. */
int ds1621_read_value(struct i2c_client *client, u8 reg)
{
if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
|| (reg == DS1621_REG_TEMP_SLOPE))
return i2c_smbus_read_byte_data(client, reg);
else
return swap_bytes(i2c_smbus_read_word_data(client, reg));
}
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
the usual practice. */
int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if ((reg == DS1621_REG_CONF) || (reg == DS1621_REG_TEMP_COUNTER)
|| (reg == DS1621_REG_TEMP_SLOPE))
return i2c_smbus_write_byte_data(client, reg, value);
else
return i2c_smbus_write_word_data(client, reg,
swap_bytes(value));
}
void ds1621_init_client(struct i2c_client *client)
{
/* Initialize the DS1621 chip */
ds1621_write_value(client, DS1621_REG_TEMP_OVER,
TEMP_TO_REG(DS1621_INIT_TEMP_OVER));
ds1621_write_value(client, DS1621_REG_TEMP_HYST,
TEMP_TO_REG(DS1621_INIT_TEMP_HYST));
ds1621_write_value(client, DS1621_REG_CONF, 0);
/* perhaps we should start the continous conversion? For now */
/* you got to do that yourself using the "enable" in proc */
}
void ds1621_update_client(struct i2c_client *client)
{
struct ds1621_data *data = client->data;
u8 new_conf;
down(&data->update_lock);
if ((jiffies - data->last_updated > HZ + HZ / 2) ||
(jiffies < data->last_updated) || !data->valid) {
#ifdef DEBUG
printk("Starting ds1621 update\n");
#endif
data->conf = ds1621_read_value(client, DS1621_REG_CONF);
/* we should wait for the DONE bit... */
data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
data->temp_over = ds1621_read_value(client,
DS1621_REG_TEMP_OVER);
data->temp_hyst =
ds1621_read_value(client, DS1621_REG_TEMP_HYST);
/* reset alarms if neccessary */
new_conf = data->conf;
if (data->temp < data->temp_over)
new_conf &= ~DS1621_ALARM_TEMP_HIGH;
if (data->temp > data->temp_hyst)
new_conf &= ~DS1621_ALARM_TEMP_LOW;
if (data->conf != new_conf)
ds1621_write_value(client, DS1621_REG_CONF,
new_conf);
data->last_updated = jiffies;
data->valid = 1;
}
up(&data->update_lock);
}
void ds1621_temp(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct ds1621_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 1;
else if (operation == SENSORS_PROC_REAL_READ) {
ds1621_update_client(client);
results[0] = TEMP_FROM_REG(data->temp_over);
results[1] = TEMP_FROM_REG(data->temp_hyst);
results[2] = TEMP_FROM_REG(data->temp);
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
data->temp_over = TEMP_TO_REG(results[0]);
ds1621_write_value(client, DS1621_REG_TEMP_OVER,
data->temp_over);
}
if (*nrels_mag >= 2) {
data->temp_hyst = TEMP_TO_REG(results[1]);
ds1621_write_value(client, DS1621_REG_TEMP_HYST,
data->temp_hyst);
}
}
}
void ds1621_alarms(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
struct ds1621_data *data = client->data;
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
ds1621_update_client(client);
results[0] = ALARMS_FROM_REG(data->conf);
*nrels_mag = 1;
}
}
void ds1621_enable(struct i2c_client *client, int operation, int ctl_name,
int *nrels_mag, long *results)
{
/* If you really screw up your chip (like I did) this is */
/* sometimes needed to (re)start the continous conversion */
/* there is no data to read so this might hang your SMBus! */
if (operation == SENSORS_PROC_REAL_INFO)
*nrels_mag = 0;
else if (operation == SENSORS_PROC_REAL_READ) {
*nrels_mag = 0;
} else if (operation == SENSORS_PROC_REAL_WRITE) {
if (*nrels_mag >= 1) {
if (results[0]) {
ds1621_read_value(client, DS1621_COM_START);
} else {
ds1621_read_value(client, DS1621_COM_STOP);
}
} else {
ds1621_read_value(client, DS1621_COM_START);
}
}
}
int __init sensors_ds1621_init(void)
{
int res;
printk("ds1621.o version %s (%s)\n", LM_VERSION, LM_DATE);
ds1621_initialized = 0;
if ((res = i2c_add_driver(&ds1621_driver))) {
printk
("ds1621.o: Driver registration failed, module not inserted.\n");
ds1621_cleanup();
return res;
}
ds1621_initialized++;
return 0;
}
int __init ds1621_cleanup(void)
{
int res;
if (ds1621_initialized >= 1) {
if ((res = i2c_del_driver(&ds1621_driver))) {
printk
("ds1621.o: Driver deregistration failed, module not removed.\n");
return res;
}
ds1621_initialized--;
}
return 0;
}
EXPORT_NO_SYMBOLS;
#ifdef MODULE
MODULE_AUTHOR("Christian W. Zuckschwerdt <zany@triq.net>");
MODULE_DESCRIPTION("DS1621 driver");
int init_module(void)
{
return sensors_ds1621_init();
}
int cleanup_module(void)
{
return ds1621_cleanup();
}
#endif /* MODULE */

View File

@@ -402,6 +402,7 @@ extern inline int SENSORS_LIMIT(long value, long low, long high)
#define I2C_DRIVERID_LM87 1021
#define I2C_DRIVERID_PCF8574 1022
#define I2C_DRIVERID_MTP008 1023
#define I2C_DRIVERID_DS1621 1024
/* Sysctl IDs */
#ifdef DEV_HWMON
@@ -815,5 +816,11 @@ struct sensors_chips_data {
#define MTP008_ALARM_TEMP2 0x0100
#define MTP008_ALARM_TEMP3 0x0200
#define DS1621_SYSCTL_TEMP 1200 /* Degrees Celcius * 10 */
#define DS1621_SYSCTL_ALARMS 2001 /* bitvector */
#define DS1621_ALARM_TEMP_HIGH 0x40
#define DS1621_ALARM_TEMP_LOW 0x20
#define DS1621_SYSCTL_ENABLE 2002
#endif /* def SENSORS_SENSORS_H */

View File

@@ -922,6 +922,9 @@ extern int sensors_adm1021_init(void);
#ifdef CONFIG_SENSORS_ADM9240
extern int sensors_adm9024_init(void);
#endif
#ifdef CONFIG_SENSORS_DS1621
extern int sensors_ds1621_init(void);
#endif
#ifdef CONFIG_SENSORS_GL518SM
extern int sensors_gl518sm_init(void);
#endif
@@ -956,6 +959,9 @@ int __init sensors_init_all(void)
#ifdef CONFIG_SENSORS_ADM9024
sensors_adm9024_init();
#endif
#ifdef CONFIG_SENSORS_DS1621
sensors_ds1621_init();
#endif
#ifdef CONFIG_SENSORS_GL518SM
sensors_gl518sm_init();
#endif

View File

@@ -1972,6 +1972,21 @@ static sensors_chip_feature mtp008_features[] =
{ 0 }
};
static sensors_chip_feature ds1621_features[] =
{
{ SENSORS_DS1621_TEMP, "temp", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, DS1621_SYSCTL_TEMP, VALUE(3), 1 },
{ SENSORS_DS1621_TEMP_HYST, "temp_hyst", SENSORS_DS1621_TEMP,
SENSORS_DS1621_TEMP, SENSORS_MODE_RW,
DS1621_SYSCTL_TEMP, VALUE(2), 1 },
{ SENSORS_DS1621_TEMP_OVER, "temp_over", SENSORS_DS1621_TEMP,
SENSORS_DS1621_TEMP, SENSORS_MODE_RW,
DS1621_SYSCTL_TEMP, VALUE(1), 1 },
{ SENSORS_DS1621_ALARMS, "alarms", SENSORS_NO_MAPPING, SENSORS_NO_MAPPING,
SENSORS_MODE_R, DS1621_SYSCTL_ALARMS, VALUE(1), 0 },
{ 0 }
};
sensors_chip_features sensors_chip_features_list[] =
{
{ SENSORS_LM78_PREFIX, lm78_features },
@@ -2014,5 +2029,6 @@ sensors_chip_features sensors_chip_features_list[] =
{ SENSORS_EEPROM_PREFIX, eeprom_features },
{ SENSORS_LM87_PREFIX, lm87_features },
{ SENSORS_MTP008_PREFIX, mtp008_features },
{ SENSORS_DS1621_PREFIX, ds1621_features },
{ 0 }
};

View File

@@ -901,4 +901,13 @@
#define SENSORS_MTP008_ALARMS 81 /* R */
#define SENSORS_MTP008_BEEP 82 /* RW */
/* DS1621 chips. */
#define SENSORS_DS1621_PREFIX "ds1621"
#define SENSORS_DS1621_TEMP 51 /* R */
#define SENSORS_DS1621_TEMP_HYST 52 /* RW */
#define SENSORS_DS1621_TEMP_OVER 53 /* RW */
#define SENSORS_DS1621_ALARMS 81 /* R */
#endif /* def LIB_SENSORS_CHIPS_H */

View File

@@ -360,7 +360,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);
ddcmonitor_detect ds1621_detect);
# This is a list of all recognized chips.
# Each entry must have the following fields:
@@ -520,6 +520,12 @@ use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect
i2c_addrs => [0x2c..0x2f],
i2c_detect => sub { adm9240_detect 0, @_ }
},
{
name => "Dallas Semiconductor DS1621",
driver => "ds1621",
i2c_addrs => [0x48..0x4f],
i2c_detect => sub { ds1621_detect @_},
} ,
{
name => "Dallas Semiconductor DS1780",
driver => "adm9240",
@@ -1566,6 +1572,26 @@ sub lm75_detect
return (3);
}
# $_[0]: A reference to the file descriptor to access this chip.
# We may assume an i2c_set_slave_addr was already done.
# $_[1]: Address
# Returns: undef if not detected, (3) if detected,
# (6) or (9) if even more bits match.
# Registers used:
# 0xAC: Configuration
# Detection is weak. We check if Bit 3 is set and Bit 2 is clear.
# The DS1621 will aways have a config like 0x????10??. A even better
# match would be 0x0??01000.
sub ds1621_detect
{
my $i;
my ($file,$addr) = @_;
my $conf = i2c_smbus_read_byte_data($file,0xAC);
return (9) if ($conf & 0x9F) == 0x98;
return (6) if ($conf & 0x0F) == 0x08;
return (3) if ($conf & 0x0C) == 0x08;
return ;
}
# $_[0]: A reference to the file descriptor to access this chip.
# We may assume an i2c_set_slave_addr was already done.

View File

@@ -105,6 +105,43 @@ int sensors_get_label_and_valid(sensors_chip_name name, int feature, char **labe
return err;
}
void print_ds1621(const sensors_chip_name *name)
{
char *label;
double cur,hyst,over;
int alarms, valid;
if (!sensors_get_feature(*name,SENSORS_LM78_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_DS1621_TEMP,&label,&valid) &&
!sensors_get_feature(*name,SENSORS_DS1621_TEMP,&cur) &&
!sensors_get_feature(*name,SENSORS_DS1621_TEMP_HYST,&hyst) &&
!sensors_get_feature(*name,SENSORS_DS1621_TEMP_OVER,&over)) {
if (valid) {
print_label(label,10);
printf("%6.1f C (high limit: %6.1f C, low limit: %6.1f C) ",
cur,over,hyst);
if (alarms & (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW)) {
printf("ALARM (");
if (alarms & DS1621_ALARM_TEMP_LOW) {
printf("LOW");
}
if (alarms & DS1621_ALARM_TEMP_HIGH)
printf("%sHIGH",(alarms & DS1621_ALARM_TEMP_LOW)?",":"");
printf(")");
}
printf("\n");
}
} else
printf("ERROR: Can't get temperature data!\n");
free_the_label(&label);
}
void print_lm75(const sensors_chip_name *name)
{
char *label;

View File

@@ -24,6 +24,7 @@
extern void print_unknown_chip(const sensors_chip_name *name);
extern void print_ds1621(const sensors_chip_name *name);
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);

View File

@@ -260,6 +260,8 @@ void do_a_print(sensors_chip_name name)
printf(" ERROR: Can't get adapter or algorithm?!?\n");
if (do_unknown)
print_unknown_chip(&name);
else if (!strcmp(name.prefix,"ds1621"))
print_ds1621(&name);
else if (!strcmp(name.prefix,"lm75"))
print_lm75(&name);
else if (!strcmp(name.prefix,"adm1021") || !strcmp(name.prefix,"max1617") ||