⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dme1737.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * dme1737.c - Driver for the SMSC DME1737, Asus A8000, and SMSC SCH311x *             Super-I/O chips integrated hardware monitoring features. * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com> * * This driver is an I2C/ISA hybrid, meaning that it uses the I2C bus to access * the chip registers if a DME1737 (or A8000) is found and the ISA bus if a * SCH311x chip is found. Both types of chips have very similar hardware * monitoring capabilities but differ in the way they can be accessed. * * 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/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/jiffies.h>#include <linux/i2c.h>#include <linux/platform_device.h>#include <linux/hwmon.h>#include <linux/hwmon-sysfs.h>#include <linux/hwmon-vid.h>#include <linux/err.h>#include <linux/mutex.h>#include <asm/io.h>/* ISA device, if found */static struct platform_device *pdev;/* Module load parameters */static int force_start;module_param(force_start, bool, 0);MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");/* Addresses to scan */static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};/* Insmod parameters */I2C_CLIENT_INSMOD_1(dme1737);/* --------------------------------------------------------------------- * Registers * * The sensors are defined as follows: * * Voltages                          Temperatures * --------                          ------------ * in0   +5VTR (+5V stdby)           temp1   Remote diode 1 * in1   Vccp  (proc core)           temp2   Internal temp * in2   VCC   (internal +3.3V)      temp3   Remote diode 2 * in3   +5V * in4   +12V * in5   VTR   (+3.3V stby) * in6   Vbat * * --------------------------------------------------------------------- *//* Voltages (in) numbered 0-6 (ix) */#define	DME1737_REG_IN(ix)		((ix) < 5 ? 0x20 + (ix) \						  : 0x94 + (ix))#define	DME1737_REG_IN_MIN(ix)		((ix) < 5 ? 0x44 + (ix) * 2 \						  : 0x91 + (ix) * 2)#define	DME1737_REG_IN_MAX(ix)		((ix) < 5 ? 0x45 + (ix) * 2 \						  : 0x92 + (ix) * 2)/* Temperatures (temp) numbered 0-2 (ix) */#define DME1737_REG_TEMP(ix)		(0x25 + (ix))#define DME1737_REG_TEMP_MIN(ix)	(0x4e + (ix) * 2)#define DME1737_REG_TEMP_MAX(ix)	(0x4f + (ix) * 2)#define DME1737_REG_TEMP_OFFSET(ix)	((ix) == 0 ? 0x1f \						   : 0x1c + (ix))/* Voltage and temperature LSBs * The LSBs (4 bits each) are stored in 5 registers with the following layouts: *    IN_TEMP_LSB(0) = [in5, in6] *    IN_TEMP_LSB(1) = [temp3, temp1] *    IN_TEMP_LSB(2) = [in4, temp2] *    IN_TEMP_LSB(3) = [in3, in0] *    IN_TEMP_LSB(4) = [in2, in1] */#define DME1737_REG_IN_TEMP_LSB(ix)	(0x84 + (ix))static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0};static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4};static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};/* Fans numbered 0-5 (ix) */#define DME1737_REG_FAN(ix)		((ix) < 4 ? 0x28 + (ix) * 2 \						  : 0xa1 + (ix) * 2)#define DME1737_REG_FAN_MIN(ix)		((ix) < 4 ? 0x54 + (ix) * 2 \						  : 0xa5 + (ix) * 2)#define DME1737_REG_FAN_OPT(ix)		((ix) < 4 ? 0x90 + (ix) \						  : 0xb2 + (ix))#define DME1737_REG_FAN_MAX(ix)		(0xb4 + (ix)) /* only for fan[4-5] *//* PWMs numbered 0-2, 4-5 (ix) */#define DME1737_REG_PWM(ix)		((ix) < 3 ? 0x30 + (ix) \						  : 0xa1 + (ix))#define DME1737_REG_PWM_CONFIG(ix)	(0x5c + (ix)) /* only for pwm[0-2] */#define DME1737_REG_PWM_MIN(ix)		(0x64 + (ix)) /* only for pwm[0-2] */#define DME1737_REG_PWM_FREQ(ix)	((ix) < 3 ? 0x5f + (ix) \						  : 0xa3 + (ix))/* The layout of the ramp rate registers is different from the other pwm * registers. The bits for the 3 PWMs are stored in 2 registers: *    PWM_RR(0) = [OFF3, OFF2,  OFF1,  RES,   RR1E, RR1-2, RR1-1, RR1-0] *    PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */#define DME1737_REG_PWM_RR(ix)		(0x62 + (ix)) /* only for pwm[0-2] *//* Thermal zones 0-2 */#define DME1737_REG_ZONE_LOW(ix)	(0x67 + (ix))#define DME1737_REG_ZONE_ABS(ix)	(0x6a + (ix))/* The layout of the hysteresis registers is different from the other zone * registers. The bits for the 3 zones are stored in 2 registers: *    ZONE_HYST(0) = [H1-3,  H1-2,  H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] *    ZONE_HYST(1) = [H3-3,  H3-2,  H3-1, H3-0, RES,  RES,  RES,  RES] */#define DME1737_REG_ZONE_HYST(ix)	(0x6d + (ix))/* Alarm registers and bit mapping * The 3 8-bit alarm registers will be concatenated to a single 32-bit * alarm value [0, ALARM3, ALARM2, ALARM1]. */#define DME1737_REG_ALARM1		0x41#define DME1737_REG_ALARM2		0x42#define DME1737_REG_ALARM3		0x83static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17};static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};/* Miscellaneous registers */#define DME1737_REG_DEVICE		0x3d#define DME1737_REG_COMPANY		0x3e#define DME1737_REG_VERSTEP		0x3f#define DME1737_REG_CONFIG		0x40#define DME1737_REG_CONFIG2		0x7f#define DME1737_REG_VID			0x43#define DME1737_REG_TACH_PWM		0x81/* --------------------------------------------------------------------- * Misc defines * --------------------------------------------------------------------- *//* Chip identification */#define DME1737_COMPANY_SMSC	0x5c#define DME1737_VERSTEP		0x88#define DME1737_VERSTEP_MASK	0xf8#define SCH311X_DEVICE		0x8c/* Length of ISA address segment */#define DME1737_EXTENT	2/* --------------------------------------------------------------------- * Data structures and manipulation thereof * --------------------------------------------------------------------- *//* For ISA chips, we abuse the i2c_client addr and name fields. We also use   the driver field to differentiate between I2C and ISA chips. */struct dme1737_data {	struct i2c_client client;	struct device *hwmon_dev;	struct mutex update_lock;	int valid;			/* !=0 if following fields are valid */	unsigned long last_update;	/* in jiffies */	unsigned long last_vbat;	/* in jiffies */	u8 vid;	u8 pwm_rr_en;	u8 has_pwm;	u8 has_fan;	/* Register values */	u16 in[7];	u8  in_min[7];	u8  in_max[7];	s16 temp[3];	s8  temp_min[3];	s8  temp_max[3];	s8  temp_offset[3];	u8  config;	u8  config2;	u8  vrm;	u16 fan[6];	u16 fan_min[6];	u8  fan_max[2];	u8  fan_opt[6];	u8  pwm[6];	u8  pwm_min[3];	u8  pwm_config[3];	u8  pwm_acz[3];	u8  pwm_freq[6];	u8  pwm_rr[2];	u8  zone_low[3];	u8  zone_abs[3];	u8  zone_hyst[2];	u32 alarms;};/* Nominal voltage values */static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300};/* Voltage input * Voltage inputs have 16 bits resolution, limit values have 8 bits * resolution. */static inline int IN_FROM_REG(int reg, int ix, int res){	return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2));}static inline int IN_TO_REG(int val, int ix){	return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) /			     IN_NOMINAL[ix], 0, 255);}/* Temperature input * The register values represent temperatures in 2's complement notation from * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit * values have 8 bits resolution. */static inline int TEMP_FROM_REG(int reg, int res){	return (reg * 1000) >> (res - 8);}static inline int TEMP_TO_REG(int val){	return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,			     -128, 127);}/* Temperature range */static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,				 10000, 13333, 16000, 20000, 26666, 32000,				 40000, 53333, 80000};static inline int TEMP_RANGE_FROM_REG(int reg){	return TEMP_RANGE[(reg >> 4) & 0x0f];}static int TEMP_RANGE_TO_REG(int val, int reg){	int i;	for (i = 15; i > 0; i--) {		if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) {			break;		}	}	return (reg & 0x0f) | (i << 4);}/* Temperature hysteresis * Register layout: *    reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0] *    reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */static inline int TEMP_HYST_FROM_REG(int reg, int ix){	return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;}static inline int TEMP_HYST_TO_REG(int val, int ix, int reg){	int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);	return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);}/* Fan input RPM */static inline int FAN_FROM_REG(int reg, int tpc){	return (reg == 0 || reg == 0xffff) ? 0 :		(tpc == 0) ? 90000 * 60 / reg : tpc * reg;}static inline int FAN_TO_REG(int val, int tpc){	return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,			     0, 0xffff);}/* Fan TPC (tach pulse count) * Converts a register value to a TPC multiplier or returns 0 if the tachometer * is configured in legacy (non-tpc) mode */static inline int FAN_TPC_FROM_REG(int reg){	return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);}/* Fan type * The type of a fan is expressed in number of pulses-per-revolution that it * emits */static inline int FAN_TYPE_FROM_REG(int reg){	int edge = (reg >> 1) & 0x03;	return (edge > 0) ? 1 << (edge - 1) : 0;}static inline int FAN_TYPE_TO_REG(int val, int reg){	int edge = (val == 4) ? 3 : val;	return (reg & 0xf9) | (edge << 1);}/* Fan max RPM */static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,			      0x11, 0x0f, 0x0e};static int FAN_MAX_FROM_REG(int reg){	int i;	for (i = 10; i > 0; i--) {		if (reg == FAN_MAX[i]) {			break;		}	}	return 1000 + i * 500;}static int FAN_MAX_TO_REG(int val){	int i;	for (i = 10; i > 0; i--) {		if (val > (1000 + (i - 1) * 500)) {			break;		}	}	return FAN_MAX[i];}/* PWM enable * Register to enable mapping: * 000:  2  fan on zone 1 auto * 001:  2  fan on zone 2 auto * 010:  2  fan on zone 3 auto * 011:  0  fan full on * 100: -1  fan disabled * 101:  2  fan on hottest of zones 2,3 auto * 110:  2  fan on hottest of zones 1,2,3 auto * 111:  1  fan in manual mode */static inline int PWM_EN_FROM_REG(int reg){	static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};	return en[(reg >> 5) & 0x07];}static inline int PWM_EN_TO_REG(int val, int reg){	int en = (val == 1) ? 7 : 3;	return (reg & 0x1f) | ((en & 0x07) << 5);}/* PWM auto channels zone * Register to auto channels zone mapping (ACZ is a bitfield with bit x * corresponding to zone x+1): * 000: 001  fan on zone 1 auto * 001: 010  fan on zone 2 auto * 010: 100  fan on zone 3 auto * 011: 000  fan full on * 100: 000  fan disabled * 101: 110  fan on hottest of zones 2,3 auto * 110: 111  fan on hottest of zones 1,2,3 auto * 111: 000  fan in manual mode */static inline int PWM_ACZ_FROM_REG(int reg){	static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};	return acz[(reg >> 5) & 0x07];}static inline int PWM_ACZ_TO_REG(int val, int reg){	int acz = (val == 4) ? 2 : val - 1;	return (reg & 0x1f) | ((acz & 0x07) << 5);}/* PWM frequency */static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,			       15000, 20000, 30000, 25000, 0, 0, 0, 0};static inline int PWM_FREQ_FROM_REG(int reg){	return PWM_FREQ[reg & 0x0f];}static int PWM_FREQ_TO_REG(int val, int reg){	int i;	/* the first two cases are special - stupid chip design! */	if (val > 27500) {		i = 10;	} else if (val > 22500) {		i = 11;	} else {		for (i = 9; i > 0; i--) {			if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) {				break;			}		}	}	return (reg & 0xf0) | i;}/* PWM ramp rate * Register layout: *    reg[0] = [OFF3,  OFF2,  OFF1,  RES,   RR1-E, RR1-2, RR1-1, RR1-0] *    reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};static inline int PWM_RR_FROM_REG(int reg, int ix){	int rr = (ix == 1) ? reg >> 4 : reg;	return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;}static int PWM_RR_TO_REG(int val, int ix, int reg){	int i;	for (i = 0; i < 7; i++) {		if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) {			break;		}	}	return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;}/* PWM ramp rate enable */static inline int PWM_RR_EN_FROM_REG(int reg, int ix)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -