From bd3d2501592797f83180580791dd6342616cb1ed Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 24 May 2004 20:25:13 +0000 Subject: [PATCH] Initial MAX1619 support, contributed by Alexey Fisher. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2564 7894878c-1315-0410-8ee3-d5d059ff63e0 --- CONTRIBUTORS | 7 +- doc/chips/SUMMARY | 8 + doc/chips/max1619 | 73 ++++++ etc/sensors.conf.eg | 15 ++ kernel/chips/Module.mk | 1 + kernel/chips/max1619.c | 499 +++++++++++++++++++++++++++++++++++++ lib/chips.c | 27 ++ lib/chips.h | 12 + prog/detect/sensors-detect | 2 +- prog/sensors/chips.c | 56 +++++ prog/sensors/chips.h | 1 + 11 files changed, 697 insertions(+), 4 deletions(-) create mode 100644 doc/chips/max1619 create mode 100644 kernel/chips/max1619.c diff --git a/CONTRIBUTORS b/CONTRIBUTORS index c949456e..d3a95864 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -81,7 +81,7 @@ problems. Author of the decode-vaio.pl Vaio EEPROM decoder. Author of the decode-edid.pl EDID data decoder. Perl scripts maintainer, tester, bug fixer, general support. - Author of the lm83 and lm90 chip drivers. + Author of the lm83, lm90, pca9540 and pc87360 chip drivers. * Vojtech Pavlik Author of the i2c-amd8111 bus driver. Added support for amd8111 SMBus 1.0 controller to i2c-amd756. @@ -90,8 +90,9 @@ problems. Author of the ADM1026 chip driver. * Sascha Volkenandt Author of the SAA1064 chip driver. -* John Morris (john.morris@spirentcom.com) +* John Morris Author of the MAX6650 chip driver. * Reinhard Nissl Author of the fscher driver. - +* Alexey Fisher + Author of the max1619 chip driver. diff --git a/doc/chips/SUMMARY b/doc/chips/SUMMARY index ba68b562..2797752d 100644 --- a/doc/chips/SUMMARY +++ b/doc/chips/SUMMARY @@ -149,6 +149,14 @@ lm92 (lm76 needs force parameter) lm76 1 - - - yes no +max1619 + max1619 2 - - - yes no + +max6650 + (all are reported as a "max6650") + max6650 - - 1 1 pwm yes no + max6651 - - 4 1 pwm yes no + maxilife maxilife-as 5 4 3 - yes no maxilife-co 5 4 3 - yes no diff --git a/doc/chips/max1619 b/doc/chips/max1619 new file mode 100644 index 00000000..1336fe7c --- /dev/null +++ b/doc/chips/max1619 @@ -0,0 +1,73 @@ +Kernel driver `max1619.o' +========================= + +Status: New + +Supported chips: + * Maxim MAX1619 + Prefix: `max1619' + Addresses scanned: I2C 0x18-0x1a, 0x29-0x2b, 0x4c-0x4e (inclusive) + Datasheet: Publicly available at the Maxim website + http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + +Author: Alexey Fisher + +License: GPL + + +Module Parameters +----------------- + +* force: short array (min = 1, max = 48) + List of adapter,address pairs to boldly assume to be present +* force_max1619: short array (min = 1, max = 48) + List of adapter,address pairs which are unquestionably assumed to contain + a `max1619' chip +* 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 +* 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 + + +Description +----------- + +The MAX1619 is a digital temperature sensor. It senses its own temperature as +well as the temperature of up to one external diode. + +All temperature values are given in degrees Celcius. Resolution +is 1.0 degree for the local temperature and for the remote temperature. + +Only the external sensor has high and low limits. + +The max1619 driver will not update its values more frequently than every +other second; reading them more often will do no harm, but will return +'old' values. + + +Chip Features +------------- + +Chips 'max1619' + +LABEL LABEL CLASS COMPUTE CLASS MODE MAGN +temp1 - - R- 0 +temp2 - - R- 0 +temp2_max temp2 temp2 RW 0 +temp2_min temp2 temp2 RW 0 +temp2_crit temp2 temp2 RW 0 +temp2_hyst temp2 temp2 RW 0 +alarms - - R- 0 + +LABEL FEATURE SYMBOL SYSCTL FILE:N +temp1 SENSORS_MAX1619_LOCAL_TEMP temp1:1 +temp2 SENSORS_MAX1619_REMOTE_TEMP temp2:3 +temp2_max SENSORS_MAX1619_REMOTE_HIGH temp2:1 +temp2_min SENSORS_MAX1619_REMOTE_LOW temp2:2 +temp2_crit SENSORS_MAX1619_REMOTE_HYST temp2_crit:1 +temp2_hyst SENSORS_MAX1619_REMOTE_MAX temp2_crit:2 +alarms SENSORS_MAX1619_ALARMS alarms:1 diff --git a/etc/sensors.conf.eg b/etc/sensors.conf.eg index ce048c77..1993ad7d 100644 --- a/etc/sensors.conf.eg +++ b/etc/sensors.conf.eg @@ -1718,6 +1718,21 @@ chip "lm83-*" # should be higher than each of the high limits above # set tcrit 85 + +chip "max1619-*" + + label temp1 "M/B Temp" + label temp2 "CPU Temp" + +# change high and low limits to fit your needs + set temp2_min 10 + set temp2_max 100 + +# change critical limit and hysteresis to fit your needs + set temp2_crit 55 + set temp2_hyst 50 + + chip "lm90-*" "adm1032-*" label temp1 "M/B Temp" diff --git a/kernel/chips/Module.mk b/kernel/chips/Module.mk index 0c92647a..0d99d46f 100644 --- a/kernel/chips/Module.mk +++ b/kernel/chips/Module.mk @@ -31,6 +31,7 @@ endif KERNELCHIPSTARGETS += $(MODULE_DIR)/ds1307.o KERNELCHIPSTARGETS += $(MODULE_DIR)/lm83.o KERNELCHIPSTARGETS += $(MODULE_DIR)/lm90.o +KERNELCHIPSTARGETS += $(MODULE_DIR)/max1619.o KERNELCHIPSTARGETS += $(MODULE_DIR)/max6650.o KERNELCHIPSTARGETS += $(MODULE_DIR)/saa1064.o KERNELCHIPSTARGETS += $(MODULE_DIR)/smartbatt.o diff --git a/kernel/chips/max1619.c b/kernel/chips/max1619.c new file mode 100644 index 00000000..9f19ce6a --- /dev/null +++ b/kernel/chips/max1619.c @@ -0,0 +1,499 @@ +/* + * max1619.c - Part of lm_sensors, Linux kernel modules for hardware + * monitoring + * Copyright (C) 2004 Alexey Fisher + * Jean Delvare + * + * Copied from lm90.c: + * Copyright (C) 2003-2004 Jean Delvare + * + * The MAX1619 is a sensor chip made by Maxim. It reports up to two + * temperatures (its own plus up to one external one). + * Complete datasheet can be obtained from Maxim's website at: + * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include "version.h" + +/* + * Addresses to scan + */ + +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = {0x18, 0x1a, 0x29, 0x2b, + 0x4c, 0x4e, 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(max1619); + +/* + * The max1619 registers + */ + +#define MAX1619_REG_R_CONFIG 0x03 +#define MAX1619_REG_W_CONFIG 0x09 +#define MAX1619_REG_R_CONVRATE 0x04 +#define MAX1619_REG_W_CONVRATE 0x0A +#define MAX1619_REG_R_STATUS 0x02 +#define MAX1619_REG_R_LOCAL_TEMP 0x00 +#define MAX1619_REG_R_REMOTE_TEMP 0x01 +#define MAX1619_REG_R_REMOTE_THIGH 0x07 +#define MAX1619_REG_W_REMOTE_THIGH 0x0d +#define MAX1619_REG_R_REMOTE_TLOW 0x08 +#define MAX1619_REG_W_REMOTE_TLOW 0x0E +#define MAX1619_REG_R_REMOTE_TMAX 0x10 +#define MAX1619_REG_W_REMOTE_TMAX 0x12 +#define MAX1619_REG_R_REMOTE_THYST 0x11 +#define MAX1619_REG_W_REMOTE_THYST 0x13 +#define MAX1619_REG_R_MAN_ID 0xFE +#define MAX1619_REG_R_CHIP_ID 0xFF + +/* + * Conversions and various macros + */ + +#define TEMP_FROM_REG(val) ((val) & 0x80 ? (val)-0x100 : (val)) +#define TEMP_TO_REG(val) ((val) < 0 ? (val)+0x100 : (val)) + +/* + * Functions declaration + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter); +static int max1619_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind); +static void max1619_init_client(struct i2c_client *client); +static int max1619_detach_client(struct i2c_client *client); +static void max1619_local_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void max1619_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void max1619_remote_crit(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); +static void max1619_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results); + +/* + * Driver data (common to all clients) + */ + +static struct i2c_driver max1619_driver = { + .owner = THIS_MODULE, + .name = "MAX1619 sensor driver", + .flags = I2C_DF_NOTIFY, + .attach_adapter = max1619_attach_adapter, + .detach_client = max1619_detach_client +}; + +/* + * Client data (each client gets its own) + */ + +struct max1619_data { + struct i2c_client client; + int sysctl_id; + + struct semaphore update_lock; + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + /* register values */ + u8 local_temp; + u8 remote_temp, remote_high, remote_low; + u8 remote_hyst, remote_max; + u8 alarms; +}; + +/* + * Proc entries + * These files are created for each detected max1619. + */ + +/* -- SENSORS SYSCTL START -- */ + +#define MAX1619_SYSCTL_LOCAL_TEMP 1200 +#define MAX1619_SYSCTL_REMOTE_TEMP 1201 +#define MAX1619_SYSCTL_REMOTE_CRIT 1202 +#define MAX1619_SYSCTL_ALARMS 1203 + +#define MAX1619_ALARM_REMOTE_THIGH 0x10 +#define MAX1619_ALARM_REMOTE_TLOW 0x08 +#define MAX1619_ALARM_REMOTE_OPEN 0x04 +#define MAX1619_ALARM_REMOTE_OVERT 0x02 + +/* -- SENSORS SYSCTL END -- */ + + +static ctl_table max1619_dir_table_template[] = +{ + {MAX1619_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_local_temp}, + {MAX1619_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_temp}, + {MAX1619_SYSCTL_REMOTE_CRIT,"temp2_crit", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_crit}, + {MAX1619_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_alarms}, + {0} +}; + +/* + * Internal variables + */ + +static int max1619_id = 0; + +/* + * Real code + */ + +static int max1619_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, max1619_detect); +} + +/* + * The following function does more than just detection. If detection + * succeeds, it also registers the new chip. + */ +static int max1619_detect(struct i2c_adapter *adapter, int address, + unsigned short flags, int kind) +{ + struct i2c_client *new_client; + struct max1619_data *data; + int err = 0; + const char *type_name = ""; + const char *client_name = ""; + +#ifdef DEBUG + if (i2c_is_isa_adapter(adapter)) { + printk(KERN_DEBUG "max1619.o: Called for an ISA bus " + "adapter, aborting.\n"); + return 0; + } +#endif + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { +#ifdef DEBUG + printk(KERN_DEBUG "max1619.o: I2C bus doesn't support " + "byte read mode, skipping.\n"); +#endif + return 0; + } + + if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { + printk(KERN_ERR "max1619.o: Out of memory in " + "max1619_detect (new_client).\n"); + return -ENOMEM; + } + + /* + * The common I2C client data is placed right before the + * MAX1619-specific data. The MAX1619-specific data is pointed to + * by the data field from the I2C client da1ta. + */ + + new_client = &data->client; + new_client->addr = address; + new_client->data = data; + new_client->adapter = adapter; + new_client->driver = &max1619_driver; + new_client->flags = 0; + + /* + * Now we do the remaining detection. A negative kind means that + * the driver was loaded with no force parameter (default), so we + * must both detect and identify the chip. A zero kind means that + * the driver was loaded with the force parameter, the detection + * step shall be skipped. A positive kind means that the driver + * was loaded with the force parameter and a given kind of chip is + * requested, so both the detection and the identification steps + * are skipped. + */ + + if (kind < 0) { + u8 reg_config, reg_convrate, reg_status; + + reg_config = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONFIG); + reg_convrate = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CONVRATE); + reg_status = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_STATUS); + + if ((reg_config & 0x03) != 0x00 + || reg_convrate > 0x07 + || (reg_status & 0x61) != 0x00) { +#ifdef DEBUG + printk(KERN_DEBUG "max1619.o: Detection failed at " + "0x%02x.\n", address); +#endif + goto ERROR1; + } + } + + if (kind <= 0) { + u8 man_id, chip_id; + + man_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_MAN_ID); + chip_id = i2c_smbus_read_byte_data(new_client, + MAX1619_REG_R_CHIP_ID); + + if ((man_id == 0x4D) && (chip_id == 0x04)) { + kind = max1619; + } + } + + if (kind <= 0) { + printk(KERN_INFO "max1619.o: Unsupported chip.\n"); + goto ERROR1; + } + + if (kind == max1619) { + type_name = "max1619"; + client_name = "MAX1619 chip"; + } else { + printk(KERN_ERR "max1619.o: Unknown kind %d.\n", kind); + goto ERROR1; + } + + /* + * OK, we got a valid chip so we can fill in the remaining client + * fields. + */ + + strcpy(new_client->name, client_name); + new_client->id = max1619_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))) { + printk(KERN_ERR "max1619.o: Failed attaching client.\n"); + goto ERROR1; + } + + /* + * Register a new directory entry. + */ + + if ((err = i2c_register_entry(new_client, type_name, + max1619_dir_table_template)) < 0) { + printk(KERN_ERR "max1619.o: Failed registering directory " + "entry.\n"); + goto ERROR2; + } + data->sysctl_id = err; + + /* + * Initialize the MAX1619 chip. + */ + + max1619_init_client(new_client); + return 0; + +ERROR2: + i2c_detach_client(new_client); +ERROR1: + kfree(data); + return err; +} + +static void max1619_init_client(struct i2c_client *client) +{ + u8 config; + + /* + * Start the conversions. + */ + + /* Set conversion rate to 2 Hz */ + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 5); + + /* Start monitoring */ + config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); + if (config & 0x40) + i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, + config & 0xBF); +} + + +static int max1619_detach_client(struct i2c_client *client) +{ + int err; + + i2c_deregister_entry(((struct max1619_data *) + (client->data))->sysctl_id); + if ((err = i2c_detach_client(client))) { + printk(KERN_ERR "max1619.o: Client deregistration failed, " + "client not detached.\n"); + return err; + } + + kfree(client->data); + return 0; +} + +static void max1619_update_client(struct i2c_client *client) +{ + struct max1619_data *data = client->data; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ * 2) || + (jiffies < data->last_updated) || !data->valid) { +#ifdef DEBUG + printk(KERN_DEBUG "max1619.o: Updating data.\n"); +#endif + + data->local_temp = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_LOCAL_TEMP); + data->remote_temp = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TEMP); + data->remote_high = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_THIGH); + data->remote_low = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TLOW); + data->remote_max = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_TMAX); + data->remote_hyst = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_REMOTE_THYST); + data->alarms = i2c_smbus_read_byte_data(client, + MAX1619_REG_R_STATUS); + + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + +static void max1619_local_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct max1619_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; /* magnitude */ + else if (operation == SENSORS_PROC_REAL_READ) { + max1619_update_client(client); + results[0] = TEMP_FROM_REG(data->local_temp); + *nrels_mag = 1; + } + +} + +static void max1619_remote_temp(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct max1619_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; /* magnitude */ + else if (operation == SENSORS_PROC_REAL_READ) { + max1619_update_client(client); + results[0] = TEMP_FROM_REG(data->remote_high); + results[1] = TEMP_FROM_REG(data->remote_low); + results[2] = TEMP_FROM_REG(data->remote_temp); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->remote_high = TEMP_TO_REG(results[0]); + i2c_smbus_write_byte_data(client, + MAX1619_REG_W_REMOTE_THIGH, data->remote_high); + } + if (*nrels_mag >= 2) { + data->remote_low = TEMP_TO_REG(results[1]); + i2c_smbus_write_byte_data(client, + MAX1619_REG_W_REMOTE_TLOW, data->remote_low); + + } + } +} + +static void max1619_remote_crit(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct max1619_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; /* magnitude */ + else if (operation == SENSORS_PROC_REAL_READ) { + max1619_update_client(client); + results[0] = TEMP_FROM_REG(data->remote_max); + results[1] = TEMP_FROM_REG(data->remote_hyst); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->remote_max = TEMP_TO_REG(results[0]); + i2c_smbus_write_byte_data(client, + MAX1619_REG_W_REMOTE_TMAX, data->remote_max); + } + if (*nrels_mag >= 2) { + data->remote_hyst = TEMP_TO_REG(results[1]); + i2c_smbus_write_byte_data(client, + MAX1619_REG_W_REMOTE_THYST, data->remote_hyst); + } + } +} + +static void max1619_alarms(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct max1619_data *data = client->data; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; /* magnitude */ + else if (operation == SENSORS_PROC_REAL_READ) { + max1619_update_client(client); + results[0] = data->alarms; + *nrels_mag = 1; + } +} + + +static int __init sm_max1619_init(void) +{ + printk(KERN_INFO "max1619.o version %s (%s)\n", LM_VERSION, LM_DATE); + return i2c_add_driver(&max1619_driver); +} + +static void __exit sm_max1619_exit(void) +{ + i2c_del_driver(&max1619_driver); +} + +MODULE_AUTHOR("Alexey Fisher "); +MODULE_DESCRIPTION("MAX1619 sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(sm_max1619_init); +module_exit(sm_max1619_exit); diff --git a/lib/chips.c b/lib/chips.c index 8f8227c9..794ff087 100644 --- a/lib/chips.c +++ b/lib/chips.c @@ -4969,6 +4969,32 @@ static sensors_chip_feature xeontemp_features[] = { 0 } }; +static sensors_chip_feature max1619_features[] = + { + { SENSORS_MAX1619_LOCAL_TEMP, "temp1", + NOMAP, NOMAP, + R, MAX1619_SYSCTL_LOCAL_TEMP, VALUE(1), 0 }, + { SENSORS_MAX1619_REMOTE_TEMP, "temp2", + NOMAP, NOMAP, + R, MAX1619_SYSCTL_REMOTE_TEMP, VALUE(3), 0 }, + { SENSORS_MAX1619_REMOTE_HIGH, "temp2_min", + NOMAP,NOMAP, + RW, MAX1619_SYSCTL_REMOTE_TEMP, VALUE(2), 0 }, + { SENSORS_MAX1619_REMOTE_LOW, "temp2_max", + NOMAP, NOMAP, + RW, MAX1619_SYSCTL_REMOTE_TEMP, VALUE(1), 0 }, + { SENSORS_MAX1619_REMOTE_MAX, "temp2_crit", + NOMAP,NOMAP, + RW, MAX1619_SYSCTL_REMOTE_CRIT, VALUE(1), 0 }, + { SENSORS_MAX1619_REMOTE_HYST, "temp2_hyst", + NOMAP, NOMAP, + RW, MAX1619_SYSCTL_REMOTE_CRIT, VALUE(2), 0 }, + { SENSORS_MAX1619_ALARMS, "alarms", + NOMAP, NOMAP, + R, MAX1619_SYSCTL_ALARMS, VALUE(1), 0 }, + { 0 } + }; + static sensors_chip_feature max6650_features[] = { { SENSORS_MAX6650_FAN1_TACH, "fan1", NOMAP, @@ -5071,6 +5097,7 @@ sensors_chip_features sensors_chip_features_list[] = { SENSORS_LM90_PREFIX, lm90_features }, { SENSORS_ADM1032_PREFIX, lm90_features }, { SENSORS_LM99_PREFIX, lm90_features }, + { SENSORS_MAX1619_PREFIX, max1619_features }, { SENSORS_XEONTEMP_PREFIX, xeontemp_features }, { SENSORS_MAX6650_PREFIX, max6650_features }, { 0 } diff --git a/lib/chips.h b/lib/chips.h index a36bd4a5..c5865fc2 100644 --- a/lib/chips.h +++ b/lib/chips.h @@ -1855,6 +1855,18 @@ #define SENSORS_XEONTEMP_REMOTE_TEMP_OVER 56 /* RW */ #define SENSORS_XEONTEMP_ALARMS 81 /* R */ +/* MAX1619 chip */ + +#define SENSORS_MAX1619_PREFIX "max1619" + +#define SENSORS_MAX1619_LOCAL_TEMP 51 /* R */ +#define SENSORS_MAX1619_REMOTE_TEMP 52 /* R */ +#define SENSORS_MAX1619_REMOTE_LOW 53 /* RW */ +#define SENSORS_MAX1619_REMOTE_HIGH 54 /* RW */ +#define SENSORS_MAX1619_REMOTE_MAX 55 /* RW */ +#define SENSORS_MAX1619_REMOTE_HYST 56 /* RW */ +#define SENSORS_MAX1619_ALARMS 81 /* R */ + /* MAX6650 / 1 chips */ #define SENSORS_MAX6650_PREFIX "max6650" diff --git a/prog/detect/sensors-detect b/prog/detect/sensors-detect index d4159e24..772b23a7 100755 --- a/prog/detect/sensors-detect +++ b/prog/detect/sensors-detect @@ -1163,7 +1163,7 @@ use subs qw(mtp008_detect lm78_detect lm78_isa_detect lm78_alias_detect }, { name => "Maxim MAX1619", - driver => "to-be-written", + driver => "max1619", i2c_addrs => [0x18..0x1a, 0x29..0x2b, 0x4c..0x4e], i2c_detect => sub { max1619_detect 0, @_ }, }, diff --git a/prog/sensors/chips.c b/prog/sensors/chips.c index 218c7d96..992c0bc4 100644 --- a/prog/sensors/chips.c +++ b/prog/sensors/chips.c @@ -4770,6 +4770,62 @@ void print_xeontemp(const sensors_chip_name *name) free_the_label(&label); } + +void print_max1619(const sensors_chip_name *name) +{ + char *label; + double cur, high, low; + int valid, alarms; + + if (!sensors_get_feature(*name, SENSORS_MAX1619_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_MAX1619_LOCAL_TEMP, + &label, &valid) + && !sensors_get_feature(*name, SENSORS_MAX1619_LOCAL_TEMP, &cur)) { + if (valid) { + print_label(label, 10); + print_temp_info(cur,0 ,0 ,SINGLE , 0, 0); + printf("\n"); + } + } else + printf("ERROR: Can't get local temperature data!\n"); + free_the_label(&label); + + if (!sensors_get_label_and_valid(*name, SENSORS_MAX1619_REMOTE_TEMP, + &label, &valid) + && !sensors_get_feature(*name, SENSORS_MAX1619_REMOTE_TEMP, &cur) + && !sensors_get_feature(*name, SENSORS_MAX1619_REMOTE_LOW, &low) + && !sensors_get_feature(*name, SENSORS_MAX1619_REMOTE_HIGH, &high)) { + if (valid) { + print_label(label, 10); + print_temp_info(cur, low, high, MINMAX, 0, 0); + printf(" %s\n", + alarms&MAX1619_ALARM_REMOTE_OPEN?"DISCONNECT": + alarms&(MAX1619_ALARM_REMOTE_THIGH|MAX1619_ALARM_REMOTE_TLOW)?"ALARM":""); + } + } else + printf("ERROR: Can't get remote temperature data!\n"); + free_the_label(&label); + + if (!sensors_get_label_and_valid(*name, SENSORS_MAX1619_REMOTE_MAX, + &label, &valid) + && !sensors_get_feature(*name, SENSORS_MAX1619_REMOTE_MAX, &high) + && !sensors_get_feature(*name, SENSORS_MAX1619_REMOTE_HYST, &low)) { + if (valid) { + print_label(label, 10); + print_temp_info(high, low, 0, HYSTONLY, 0, 0); + printf("\n"); + } + } else + printf("ERROR: Can't get remote temperature max data!\n"); + free_the_label(&label); +} + void print_max6650(const sensors_chip_name *name) { char *label = NULL; diff --git a/prog/sensors/chips.h b/prog/sensors/chips.h index 360049e8..6efde09d 100644 --- a/prog/sensors/chips.h +++ b/prog/sensors/chips.h @@ -60,6 +60,7 @@ extern void print_vt8231(const sensors_chip_name *name); extern void print_bmc(const sensors_chip_name *name); extern void print_lm83(const sensors_chip_name *name); extern void print_lm90(const sensors_chip_name *name); +extern void print_max1619(const sensors_chip_name *name); extern void print_xeontemp(const sensors_chip_name *name); extern void print_max6650(const sensors_chip_name *name);