diff --git a/CHANGES b/CHANGES index 1e0e2e8a..af2bceea 100644 --- a/CHANGES +++ b/CHANGES @@ -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) diff --git a/README b/README index 06401516..3649ac67 100644 --- a/README +++ b/README @@ -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 diff --git a/doc/chips/SUMMARY b/doc/chips/SUMMARY index 900c89a7..14beb7cc 100644 --- a/doc/chips/SUMMARY +++ b/doc/chips/SUMMARY @@ -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 diff --git a/doc/chips/ds1621 b/doc/chips/ds1621 new file mode 100644 index 00000000..f4fc23c2 --- /dev/null +++ b/doc/chips/ds1621 @@ -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 + + +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 diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk index 866046e4..1813a7e0 100644 --- a/kernel/chips/Module.mk +++ b/kernel/chips/Module.mk @@ -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 diff --git a/kernel/chips/ds1621.c b/kernel/chips/ds1621.c new file mode 100644 index 00000000..cc6f3e46 --- /dev/null +++ b/kernel/chips/ds1621.c @@ -0,0 +1,509 @@ +/* + ds1621.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Christian W. Zuckschwerdt 2000-11-23 + based on lm75.c by Frodo Looijaard + + 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 +#include +#include +#include +#include "sensors.h" +#include "i2c-isa.h" +#include "version.h" +#include + + +#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 "); +MODULE_DESCRIPTION("DS1621 driver"); + +int init_module(void) +{ + return sensors_ds1621_init(); +} + +int cleanup_module(void) +{ + return ds1621_cleanup(); +} + +#endif /* MODULE */ diff --git a/kernel/include/sensors.h b/kernel/include/sensors.h index dbd5a90d..200d1f3b 100644 --- a/kernel/include/sensors.h +++ b/kernel/include/sensors.h @@ -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 */ diff --git a/kernel/sensors.c b/kernel/sensors.c index 57b50ef1..763d1652 100644 --- a/kernel/sensors.c +++ b/kernel/sensors.c @@ -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 diff --git a/lib/chips.c b/lib/chips.c index 03bf91c1..9d536913 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -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 } }; diff --git a/lib/chips.h b/lib/chips.h index f41c219b..d06ee9b5 100644 --- a/lib/chips.h +++ b/lib/chips.h @@ -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 */ diff --git a/prog/detect/sensors-detect b/prog/detect/sensors-detect index b5e1dcb3..13b2160a 100755 --- a/prog/detect/sensors-detect +++ b/prog/detect/sensors-detect @@ -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. diff --git a/prog/sensors/chips.c b/prog/sensors/chips.c index 060adc55..1c0c02b5 100644 --- a/prog/sensors/chips.c +++ b/prog/sensors/chips.c @@ -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; diff --git a/prog/sensors/chips.h b/prog/sensors/chips.h index 5355423a..e1d5d308 100644 --- a/prog/sensors/chips.h +++ b/prog/sensors/chips.h @@ -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); diff --git a/prog/sensors/main.c b/prog/sensors/main.c index d452e89c..ae8c9862 100644 --- a/prog/sensors/main.c +++ b/prog/sensors/main.c @@ -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") ||