📄 lm85.c
字号:
/* lm85.c - Part of lm_sensors, Linux kernel modules for hardware monitoring Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com> Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de> Chip details at <http://www.national.com/ds/LM/LM85.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 <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/i2c-sensor.h>#include <linux/i2c-vid.h>/*#include <asm/io.h>*/#undef LM85EXTENDEDFUNC /* Extended functionality *//* Addresses to scan */static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };/* Insmod parameters */SENSORS_INSMOD_4(lm85b, lm85c, adm1027, adt7463);/* The LM85 registers */#define LM85_REG_IN(nr) (0x20 + (nr))#define LM85_REG_IN_MIN(nr) (0x44 + (nr) * 2)#define LM85_REG_IN_MAX(nr) (0x45 + (nr) * 2)#define LM85_REG_TEMP(nr) (0x25 + (nr))#define LM85_REG_TEMP_MIN(nr) (0x4e + (nr) * 2)#define LM85_REG_TEMP_MAX(nr) (0x4f + (nr) * 2)/* Fan speeds are LSB, MSB (2 bytes) */#define LM85_REG_FAN(nr) (0x28 + (nr) *2)#define LM85_REG_FAN_MIN(nr) (0x54 + (nr) *2)#define LM85_REG_PWM(nr) (0x30 + (nr))#define ADT7463_REG_OPPOINT(nr) (0x33 + (nr))#define ADT7463_REG_TMIN_CTL1 0x36#define ADT7463_REG_TMIN_CTL2 0x37#define LM85_REG_DEVICE 0x3d#define LM85_REG_COMPANY 0x3e#define LM85_REG_VERSTEP 0x3f/* These are the recognized values for the above regs */#define LM85_DEVICE_ADX 0x27#define LM85_COMPANY_NATIONAL 0x01#define LM85_COMPANY_ANALOG_DEV 0x41#define LM85_VERSTEP_GENERIC 0x60#define LM85_VERSTEP_LM85C 0x60#define LM85_VERSTEP_LM85B 0x62#define LM85_VERSTEP_ADM1027 0x60#define LM85_VERSTEP_ADT7463 0x62#define LM85_REG_CONFIG 0x40#define LM85_REG_ALARM1 0x41#define LM85_REG_ALARM2 0x42#define LM85_REG_VID 0x43/* Automated FAN control */#define LM85_REG_AFAN_CONFIG(nr) (0x5c + (nr))#define LM85_REG_AFAN_RANGE(nr) (0x5f + (nr))#define LM85_REG_AFAN_SPIKE1 0x62#define LM85_REG_AFAN_SPIKE2 0x63#define LM85_REG_AFAN_MINPWM(nr) (0x64 + (nr))#define LM85_REG_AFAN_LIMIT(nr) (0x67 + (nr))#define LM85_REG_AFAN_CRITICAL(nr) (0x6a + (nr))#define LM85_REG_AFAN_HYST1 0x6d#define LM85_REG_AFAN_HYST2 0x6e#define LM85_REG_TACH_MODE 0x74#define LM85_REG_SPINUP_CTL 0x75#define ADM1027_REG_TEMP_OFFSET(nr) (0x70 + (nr))#define ADM1027_REG_CONFIG2 0x73#define ADM1027_REG_INTMASK1 0x74#define ADM1027_REG_INTMASK2 0x75#define ADM1027_REG_EXTEND_ADC1 0x76#define ADM1027_REG_EXTEND_ADC2 0x77#define ADM1027_REG_CONFIG3 0x78#define ADM1027_REG_FAN_PPR 0x7b#define ADT7463_REG_THERM 0x79#define ADT7463_REG_THERM_LIMIT 0x7A#define LM85_ALARM_IN0 0x0001#define LM85_ALARM_IN1 0x0002#define LM85_ALARM_IN2 0x0004#define LM85_ALARM_IN3 0x0008#define LM85_ALARM_TEMP1 0x0010#define LM85_ALARM_TEMP2 0x0020#define LM85_ALARM_TEMP3 0x0040#define LM85_ALARM_ALARM2 0x0080#define LM85_ALARM_IN4 0x0100#define LM85_ALARM_RESERVED 0x0200#define LM85_ALARM_FAN1 0x0400#define LM85_ALARM_FAN2 0x0800#define LM85_ALARM_FAN3 0x1000#define LM85_ALARM_FAN4 0x2000#define LM85_ALARM_TEMP1_FAULT 0x4000#define LM85_ALARM_TEMP3_FAULT 0x8000/* 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. *//* IN are scaled 1.000 == 0xc0, mag = 3 */#define IN_TO_REG(val) (SENSORS_LIMIT((((val)*0xc0+500)/1000),0,255))#define INEXT_FROM_REG(val,ext) (((val)*1000 + (ext)*250 + 96)/0xc0)#define IN_FROM_REG(val) (INEXT_FROM_REG(val,0))/* IN are scaled acording to built-in resistors */static int lm85_scaling[] = { /* .001 Volts */ 2500, 2250, 3300, 5000, 12000 };#define SCALE(val,from,to) (((val)*(to) + ((from)/2))/(from))#define INS_TO_REG(n,val) (SENSORS_LIMIT(SCALE(val,lm85_scaling[n],192),0,255))#define INSEXT_FROM_REG(n,val,ext) (SCALE((val)*4 + (ext),192*4,lm85_scaling[n]))#define INS_FROM_REG(n,val) (INSEXT_FROM_REG(n,val,0))/* FAN speed is measured using 90kHz clock */#define FAN_TO_REG(val) (SENSORS_LIMIT( (val)<=0?0: 5400000/(val),0,65534))#define FAN_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:5400000/(val))/* Temperature is reported in .001 degC increments */#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)+500)/1000,-127,127))#define TEMPEXT_FROM_REG(val,ext) ((val)*1000 + (ext)*250)#define TEMP_FROM_REG(val) (TEMPEXT_FROM_REG(val,0))#define EXTTEMP_TO_REG(val) (SENSORS_LIMIT((val)/250,-127,127))#define PWM_TO_REG(val) (SENSORS_LIMIT(val,0,255))#define PWM_FROM_REG(val) (val)#define EXT_FROM_REG(val,sensor) (((val)>>(sensor * 2))&0x03)#ifdef LM85EXTENDEDFUNC /* Extended functionality *//* ZONEs have the following parameters: * Limit (low) temp, 1. degC * Hysteresis (below limit), 1. degC (0-15) * Range of speed control, .1 degC (2-80) * Critical (high) temp, 1. degC * * FAN PWMs have the following parameters: * Reference Zone, 1, 2, 3, etc. * Spinup time, .05 sec * PWM value at limit/low temp, 1 count * PWM Frequency, 1. Hz * PWM is Min or OFF below limit, flag * Invert PWM output, flag * * Some chips filter the temp, others the fan. * Filter constant (or disabled) .1 seconds *//* These are the zone temperature range encodings */static int lm85_range_map[] = { /* .1 degC */ 20, 25, 33, 40, 50, 66, 80, 100, 133, 160, 200, 266, 320, 400, 533, 800 };static int RANGE_TO_REG( int range ){ int i; if( range >= lm85_range_map[15] ) { return 15 ; } for( i = 0 ; i < 15 ; ++i ) if( range <= lm85_range_map[i] ) break ; return( i & 0x0f );}#define RANGE_FROM_REG(val) (lm85_range_map[(val)&0x0f])/* These are the Acoustic Enhancement, or Temperature smoothing encodings * NOTE: The enable/disable bit is INCLUDED in these encodings as the * MSB (bit 3, value 8). If the enable bit is 0, the encoded value * is ignored, or set to 0. */static int lm85_smooth_map[] = { /* .1 sec */ 350, 176, 118, 70, 44, 30, 16, 8/* 35.4 * 1/1, 1/2, 1/3, 1/5, 1/8, 1/12, 1/24, 1/48 */ };static int SMOOTH_TO_REG( int smooth ){ int i; if( smooth <= 0 ) { return 0 ; } /* Disabled */ for( i = 0 ; i < 7 ; ++i ) if( smooth >= lm85_smooth_map[i] ) break ; return( (i & 0x07) | 0x08 );}#define SMOOTH_FROM_REG(val) ((val)&0x08?lm85_smooth_map[(val)&0x07]:0)/* These are the fan spinup delay time encodings */static int lm85_spinup_map[] = { /* .1 sec */ 0, 1, 2, 4, 7, 10, 20, 40 };static int SPINUP_TO_REG( int spinup ){ int i; if( spinup >= lm85_spinup_map[7] ) { return 7 ; } for( i = 0 ; i < 7 ; ++i ) if( spinup <= lm85_spinup_map[i] ) break ; return( i & 0x07 );}#define SPINUP_FROM_REG(val) (lm85_spinup_map[(val)&0x07])/* These are the PWM frequency encodings */static int lm85_freq_map[] = { /* .1 Hz */ 100, 150, 230, 300, 380, 470, 620, 980 };static int FREQ_TO_REG( int freq ){ int i; if( freq >= lm85_freq_map[7] ) { return 7 ; } for( i = 0 ; i < 7 ; ++i ) if( freq <= lm85_freq_map[i] ) break ; return( i & 0x07 );}#define FREQ_FROM_REG(val) (lm85_freq_map[(val)&0x07])/* Since we can't use strings, I'm abusing these numbers * to stand in for the following meanings: * 1 -- PWM responds to Zone 1 * 2 -- PWM responds to Zone 2 * 3 -- PWM responds to Zone 3 * 23 -- PWM responds to the higher temp of Zone 2 or 3 * 123 -- PWM responds to highest of Zone 1, 2, or 3 * 0 -- PWM is always at 0% (ie, off) * -1 -- PWM is always at 100% * -2 -- PWM responds to manual control */#endif /* Extended functionality */static int lm85_zone_map[] = { 1, 2, 3, -1, 0, 23, 123, -2 };#define ZONE_FROM_REG(val) (lm85_zone_map[((val)>>5)&0x07])#ifdef LM85EXTENDEDFUNC /* Extended functionality */static int ZONE_TO_REG( int zone ){ int i; for( i = 0 ; i <= 7 ; ++i ) if( zone == lm85_zone_map[i] ) break ; if( i > 7 ) /* Not found. */ i = 3; /* Always 100% */ return( (i & 0x07)<<5 );}#endif /* Extended functionality */#define HYST_TO_REG(val) (SENSORS_LIMIT((-(val)+5)/10,0,15))#define HYST_FROM_REG(val) (-(val)*10)#define OFFSET_TO_REG(val) (SENSORS_LIMIT((val)/25,-127,127))#define OFFSET_FROM_REG(val) ((val)*25)#define PPR_MASK(fan) (0x03<<(fan *2))#define PPR_TO_REG(val,fan) (SENSORS_LIMIT((val)-1,0,3)<<(fan *2))#define PPR_FROM_REG(val,fan) ((((val)>>(fan * 2))&0x03)+1)/* i2c-vid.h defines vid_from_reg() */#define VID_FROM_REG(val,vrm) (vid_from_reg((val),(vrm)))#define ALARMS_FROM_REG(val) (val)/* Unlike some other drivers we DO NOT set initial limits. Use * the config file to set limits. Some users have reported * motherboards shutting down when we set limits in a previous * version of the driver. *//* Typically used with Pentium 4 systems v9.1 VRM spec */#define LM85_INIT_VRM 91/* Chip sampling rates * * Some sensors are not updated more frequently than once per second * so it doesn't make sense to read them more often than that. * We cache the results and return the saved data if the driver * is called again before a second has elapsed. * * Also, there is significant configuration data for this chip * given the automatic PWM fan control that is possible. There * are about 47 bytes of config data to only 22 bytes of actual * readings. So, we keep the config data up to date in the cache * when it is written and only sample it once every 1 *minute* */#define LM85_DATA_INTERVAL (HZ + HZ / 2)#define LM85_CONFIG_INTERVAL (1 * 60 * HZ)/* For each registered LM85, we need to keep some data in memory. That data is pointed to by lm85_list[NR]->data. The structure itself is dynamically allocated, at the same time when a new lm85 client is allocated. *//* LM85 can automatically adjust fan speeds based on temperature * This structure encapsulates an entire Zone config. There are * three zones (one for each temperature input) on the lm85 */struct lm85_zone { s8 limit; /* Low temp limit */ u8 hyst; /* Low limit hysteresis. (0-15) */ u8 range; /* Temp range, encoded */ s8 critical; /* "All fans ON" temp limit */};struct lm85_autofan { u8 config; /* Register value */ u8 freq; /* PWM frequency, encoded */ u8 min_pwm; /* Minimum PWM value, encoded */ u8 min_off; /* Min PWM or OFF below "limit", flag */};struct lm85_data { struct i2c_client client; struct semaphore lock; enum chips type; struct semaphore update_lock; int valid; /* !=0 if following fields are valid */ unsigned long last_reading; /* In jiffies */ unsigned long last_config; /* In jiffies */ u8 in[5]; /* Register value */ u8 in_max[5]; /* Register value */ u8 in_min[5]; /* Register value */ s8 temp[3]; /* Register value */ s8 temp_min[3]; /* Register value */ s8 temp_max[3]; /* Register value */ s8 temp_offset[3]; /* Register value */ u16 fan[4]; /* Register value */ u16 fan_min[4]; /* Register value */ u8 pwm[3]; /* Register value */ u8 spinup_ctl; /* Register encoding, combined */ u8 tach_mode; /* Register encoding, combined */ u16 extend_adc; /* Register value */ u8 fan_ppr; /* Register value */ u8 smooth[3]; /* Register encoding */ u8 vid; /* Register value */ u8 vrm; /* VRM version */ u8 syncpwm3; /* Saved PWM3 for TACH 2,3,4 config */ u8 oppoint[3]; /* Register value */ u16 tmin_ctl; /* Register value */ unsigned long therm_total; /* Cummulative therm count */ u8 therm_limit; /* Register value */ u16 alarms; /* Register encoding, combined */ struct lm85_autofan autofan[3]; struct lm85_zone zone[3];};static int lm85_attach_adapter(struct i2c_adapter *adapter);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -