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

Support for National Semiconductor LM92 Temperature sensor.

git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1419 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
Abraham van der Merwe
2002-07-04 14:27:29 +00:00
parent 1707919009
commit e3c2328a04
2 changed files with 420 additions and 0 deletions

View File

@@ -109,6 +109,9 @@ endif
ifneq ($(shell if grep -q '^CONFIG_SENSORS_VIA686A=y' $(LINUX)/.config; then echo 1; fi),1)
KERNELCHIPSTARGETS += $(MODULE_DIR)/via686a.o
endif
ifneq ($(shell if grep -q '^CONFIG_SENSORS_LM92=y' $(LINUX)/.config; then echo 1; fi),1)
KERNELCHIPSTARGETS += $(MODULE_DIR)/lm92.o
endif
# Include all dependency files
INCLUDEFILES += $(KERNELCHIPSTARGETS:.o=.d)

417
kernel/chips/lm92.c Normal file
View File

@@ -0,0 +1,417 @@
/*
* LM92 - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
*
* Author: Abraham van der Merwe <abraham@2d3d.co.za>
*
* Linux support for the National Semiconductor LM92 Temperature
* Sensor.
*
* Based on code from the lm-sensors project which is available
* at http://www.lm-sensors.nu/. lm87.c have been particularly
* helpful (:
*
* This source code is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/i2c-proc.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
#include <asm/semaphore.h>
/* if defined, 4 faults must occur consecutively to set alarm flags */
/* #define ENABLE_FAULT_QUEUE */
#include "sensors.h"
#define LM92_REG_TEMPERATURE 0x00 /* ro, 16-bit */
#define LM92_REG_CONFIGURATION 0x01 /* rw, 8-bit */
#define LM92_REG_TRIP_HYSTERISIS 0x02 /* rw, 16-bit */
#define LM92_REG_TRIP_CRITICAL 0x03 /* rw, 16-bit */
#define LM92_REG_TRIP_LOW 0x04 /* rw, 16-bit */
#define LM92_REG_TRIP_HIGH 0x05 /* rw, 16-bit */
#define LM92_REG_MANUFACTURER 0x07 /* ro, 16-bit */
#define LM92_MANUFACTURER_ID 0x8001
#define TEMP_MIN (-4096)
#define TEMP_MAX 4095
#define LIMIT(x) do { \
if ((x) < TEMP_MIN) (x) = TEMP_MIN; \
if ((x) > TEMP_MAX) (x) = TEMP_MAX; \
} while (0)
#define CELSIUS(x) ((x) * 16)
#define ENTRY(name,proc,callback) \
{ \
ctl_name: name, \
procname: proc, \
data: NULL, \
maxlen: 0, \
mode: 0644, \
child: NULL, \
proc_handler: &i2c_proc_real, \
strategy: &i2c_sysctl_real, \
de: NULL, \
extra1: callback, \
extra2: NULL \
}
/* NOTE: all temperatures are degrees centigrade * 16 */
typedef struct {
int sysctl_id;
unsigned long timestamp;
struct {
long high;
long low;
long crit;
long hyst;
long input;
} temp;
struct {
long low;
long high;
long crit;
} alarms;
} lm92_t;
/* this is needed for each client driver method */
static struct i2c_driver lm92_driver;
/* ensure exclusive access to chip and static variables */
static DECLARE_MUTEX (mutex);
/* addresses to scan */
static unsigned short normal_i2c[] = { SENSORS_I2C_END };
static unsigned short normal_i2c_range[] = { 0x48, 0x49, 0x4a, 0x4b, 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 (lm92);
static inline int lm92_write8 (struct i2c_client *client,u8 reg,u8 value)
{
return (i2c_smbus_write_byte_data (client,reg,value) < 0 ? -EIO : 0);
}
static inline int lm92_read16 (struct i2c_client *client,u8 reg,u16 *value)
{
s32 tmp = i2c_smbus_read_word_data (client,reg);
if (tmp < 0) return (-EIO);
/* convert the data to little endian format */
*value = ((u16) tmp >> 8) | (u16) ((u16) tmp << 8);
return (0);
}
static inline int lm92_write16 (struct i2c_client *client,u8 reg,u16 value)
{
/* convert the data to big endian format */
u16 be = (value >> 8) | (u16) (value << 8);
return (i2c_smbus_write_word_data (client,reg,be) < 0 ? -EIO : 0);
}
static int lm92_read (struct i2c_client *client)
{
lm92_t *data = (lm92_t *) client->data;
u16 value[5];
if ((jiffies - data->timestamp) > HZ) {
if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 ||
lm92_read16 (client,LM92_REG_TRIP_HYSTERISIS,value + 1) < 0 ||
lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 ||
lm92_read16 (client,LM92_REG_TRIP_LOW,value + 3) < 0 ||
lm92_read16 (client,LM92_REG_TRIP_HIGH,value + 4) < 0)
return (-EIO);
data->temp.input = (s16) value[0] >> 3;
data->temp.hyst = (s16) value[1] >> 3;
data->temp.crit = (s16) value[2] >> 3;
data->temp.low = (s16) value[3] >> 3;
data->temp.high = (s16) value[4] >> 3;
data->alarms.low = value[0] & 1;
data->alarms.high = (value[0] & 2) >> 1;
data->alarms.crit = (value[0] & 4) >> 2;
data->timestamp = jiffies;
}
return (0);
}
static int lm92_write (struct i2c_client *client)
{
lm92_t *data = (lm92_t *) client->data;
LIMIT (data->temp.hyst);
LIMIT (data->temp.crit);
LIMIT (data->temp.low);
LIMIT (data->temp.high);
if (lm92_write16 (client,LM92_REG_TRIP_HYSTERISIS,((s16) data->temp.hyst << 3)) < 0 ||
lm92_write16 (client,LM92_REG_TRIP_CRITICAL,((s16) data->temp.crit << 3)) < 0 ||
lm92_write16 (client,LM92_REG_TRIP_LOW,((s16) data->temp.low << 3)) < 0 ||
lm92_write16 (client,LM92_REG_TRIP_HIGH,((s16) data->temp.high << 3)) < 0)
return (-EIO);
return (0);
}
static void lm92_temp (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results)
{
if (!down_interruptible (&mutex)) {
lm92_t *data = (lm92_t *) client->data;
if (operation == SENSORS_PROC_REAL_READ) {
lm92_read (client);
results[0] = data->temp.high;
results[1] = data->temp.low;
results[2] = data->temp.crit;
results[3] = data->temp.hyst;
results[4] = data->temp.input;
*nrels_mag = 5;
} else if (operation == SENSORS_PROC_REAL_WRITE && *nrels_mag == 4) {
data->temp.high = results[0];
data->temp.low = results[1];
data->temp.crit = results[2];
data->temp.hyst = results[3];
lm92_write (client);
} else if (operation == SENSORS_PROC_REAL_INFO) {
*nrels_mag = 0;
}
up (&mutex);
}
}
static void lm92_alarms (struct i2c_client *client,int operation,int ctl_name,int *nrels_mag,long *results)
{
if (!down_interruptible (&mutex)) {
lm92_t *data = (lm92_t *) client->data;
if (operation == SENSORS_PROC_REAL_READ) {
lm92_read (client);
results[0] = data->alarms.high;
results[1] = data->alarms.low;
results[2] = data->alarms.crit;
*nrels_mag = 3;
} else if (operation == SENSORS_PROC_REAL_INFO) {
*nrels_mag = 0;
}
up (&mutex);
}
}
static int lm92_init_client (struct i2c_client *client)
{
lm92_t *data = (lm92_t *) client->data;
u8 value = 0;
int result;
/* force reads to query the chip */
data->timestamp = 0;
/* setup the configuration register */
#ifdef ENABLE_FAULT_QUEUE
value |= 0x10;
#endif /* #ifdef ENABLE_FAULT_QUEUE */
if (lm92_write8 (client,LM92_REG_CONFIGURATION,value) < 0)
return (-ENODEV);
/* set default alarm trigger values */
data->temp.high = CELSIUS (64);
data->temp.low = CELSIUS (10);
data->temp.crit = CELSIUS (80);
data->temp.hyst = CELSIUS (2);
if ((result = lm92_write (client)) < 0)
return (result);
/* read everything once so that our cached data is updated */
if ((result = lm92_read (client)) < 0)
return (result);
return (0);
}
static int lm92_detect (struct i2c_adapter *adapter,int address,unsigned short flags,int kind)
{
static ctl_table dir_table[] = {
ENTRY (LM92_SYSCTL_TEMP,"temp",&lm92_temp),
ENTRY (LM92_SYSCTL_ALARMS,"alarms",&lm92_alarms),
{ 0 }
};
static int id = 0;
struct i2c_client *client;
lm92_t *data;
int result;
u16 manufacturer;
if (!i2c_check_functionality (adapter,I2C_FUNC_SMBUS_BYTE_DATA))
return (-ENODEV);
if ((client = kmalloc (sizeof (struct i2c_client) + sizeof (lm92_t),GFP_KERNEL)) == NULL)
return (-ENOMEM);
data = (lm92_t *) (client + 1);
client->addr = address;
client->data = data;
client->adapter = adapter;
client->driver = &lm92_driver;
client->flags = 0;
strcpy (client->name,lm92_driver.name);
if (down_interruptible (&mutex)) {
kfree (client);
return (-ERESTARTSYS);
}
if ((kind < 0 && lm92_read16 (client,LM92_REG_MANUFACTURER,&manufacturer) < 0) ||
manufacturer != LM92_MANUFACTURER_ID) {
kfree (client);
up (&mutex);
return (-ENODEV);
}
if ((result = i2c_attach_client (client))) {
kfree (client);
up (&mutex);
return (result);
}
if ((result = i2c_register_entry (client,client->name,dir_table,THIS_MODULE)) < 0) {
i2c_detach_client (client);
kfree (client);
up (&mutex);
return (result);
}
data->sysctl_id = result;
if ((result = lm92_init_client (client)) < 0) {
i2c_deregister_entry (data->sysctl_id);
i2c_detach_client (client);
kfree (client);
up (&mutex);
return (result);
}
client->id = id++;
up (&mutex);
return (0);
}
static int lm92_attach_adapter (struct i2c_adapter *adapter)
{
int result;
struct i2c_client_address_data lm92_client_data = {
normal_i2c: addr_data.normal_i2c,
normal_i2c_range: addr_data.normal_i2c_range,
probe: addr_data.probe,
probe_range: addr_data.probe_range,
ignore: addr_data.ignore,
ignore_range: addr_data.ignore_range,
force: addr_data.forces->force
};
if (!(result = i2c_probe (adapter,&lm92_client_data,lm92_detect)))
result = i2c_detect (adapter,&addr_data,lm92_detect);
return (result);
}
static int lm92_detach_client (struct i2c_client *client)
{
int result;
i2c_deregister_entry (((lm92_t *) (client->data))->sysctl_id);
if ((result = i2c_detach_client (client)))
return (result);
kfree (client);
return (0);
}
static int lm92_command (struct i2c_client *client,unsigned int cmd,void *arg)
{
return (0);
}
static void lm92_inc_use (struct i2c_client *client)
{
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif /* #ifdef MODULE */
}
static void lm92_dec_use (struct i2c_client *client)
{
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif /* #ifdef MODULE */
}
static struct i2c_driver lm92_driver = {
name: "lm92",
id: I2C_DRIVERID_LM92,
flags: I2C_DF_NOTIFY,
attach_adapter: lm92_attach_adapter,
detach_client: lm92_detach_client,
command: lm92_command,
inc_use: lm92_inc_use,
dec_use: lm92_dec_use
};
static int __init lm92_init (void)
{
int result;
if ((result = i2c_add_driver (&lm92_driver)))
return (result);
printk ("National Semiconductor LM92 Temperature Sensor (V0.01)\n");
return (0);
}
static void __exit lm92_exit (void)
{
i2c_del_driver (&lm92_driver);
}
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
MODULE_DESCRIPTION ("Linux support for LM92 Temperature Sensor");
MODULE_LICENSE ("GPL");
module_init (lm92_init);
module_exit (lm92_exit);