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

📄 w83627hf.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*    w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware                monitoring    Copyright (c) 1998 - 2003  Frodo Looijaard <frodol@dds.nl>,    Philip Edelbrock <phil@netroedge.com>,    and Mark Studebaker <mdsxyz123@yahoo.com>    Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>    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 following chips:    Chip	#vin	#fanin	#pwm	#temp	wchipid	vendid	i2c	ISA    w83627hf	9	3	2	3	0x20	0x5ca3	no	yes(LPC)    w83627thf	7	3	3	3	0x90	0x5ca3	no	yes(LPC)    w83637hf	7	3	3	3	0x80	0x5ca3	no	yes(LPC)    w83697hf	8	2	2	2	0x60	0x5ca3	no	yes(LPC)    For other winbond chips, and for i2c support in the above chips,    use w83781d.c.    Note: automatic ("cruise") fan control for 697, 637 & 627thf not    supported yet.*/#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>#include "lm75.h"static int force_addr;MODULE_PARM(force_addr, "i");MODULE_PARM_DESC(force_addr,		 "Initialize the base address of the sensors");static int force_i2c = 0x1f;MODULE_PARM(force_i2c, "i");MODULE_PARM_DESC(force_i2c,		 "Initialize the i2c address of the sensors");/* Addresses to scan */static unsigned short normal_i2c[] = { I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned int normal_isa[] = { 0, I2C_CLIENT_ISA_END };static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };/* Insmod parameters */SENSORS_INSMOD_4(w83627hf, w83627thf, w83697hf, w83637hf);static int init = 1;MODULE_PARM(init, "i");MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization");/* modified from kernel/include/traps.c */#define	REG	0x2e	/* The register to read/write */#define	DEV	0x07	/* Register: Logical device select */#define	VAL	0x2f	/* The value to read/write *//* logical device numbers for superio_select (below) */#define W83627HF_LD_FDC		0x00#define W83627HF_LD_PRT		0x01#define W83627HF_LD_UART1	0x02#define W83627HF_LD_UART2	0x03#define W83627HF_LD_KBC		0x05#define W83627HF_LD_CIR		0x06 /* w83627hf only */#define W83627HF_LD_GAME	0x07#define W83627HF_LD_MIDI	0x07#define W83627HF_LD_GPIO1	0x07#define W83627HF_LD_GPIO5	0x07 /* w83627thf only */#define W83627HF_LD_GPIO2	0x08#define W83627HF_LD_GPIO3	0x09#define W83627HF_LD_GPIO4	0x09 /* w83627thf only */#define W83627HF_LD_ACPI	0x0a#define W83627HF_LD_HWM		0x0b#define	DEVID	0x20	/* Register: Device ID */#define W83627THF_GPIO5_IOSR	0xf3 /* w83627thf only */#define W83627THF_GPIO5_DR	0xf4 /* w83627thf only */#define W83627THF_GPIO5_INVR	0xf5 /* w83627thf only */static inline voidsuperio_outb(int reg, int val){	outb(reg, REG);	outb(val, VAL);}static inline intsuperio_inb(int reg){	outb(reg, REG);	return inb(VAL);}static inline voidsuperio_select(int ld){	outb(DEV, REG);	outb(ld, VAL);}static inline voidsuperio_enter(void){	outb(0x87, REG);	outb(0x87, REG);}static inline voidsuperio_exit(void){	outb(0xAA, REG);}#define W627_DEVID 0x52#define W627THF_DEVID 0x82#define W697_DEVID 0x60#define W637_DEVID 0x70#define WINB_ACT_REG 0x30#define WINB_BASE_REG 0x60/* Constants specified below *//* Length of ISA address segment */#define WINB_EXTENT 8/* Where are the ISA address/data registers relative to the base address */#define W83781D_ADDR_REG_OFFSET 5#define W83781D_DATA_REG_OFFSET 6/* The W83781D registers *//* The W83782D registers for nr=7,8 are in bank 5 */#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \					   (0x554 + (((nr) - 7) * 2)))#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \					   (0x555 + (((nr) - 7) * 2)))#define W83781D_REG_IN(nr)     ((nr < 7) ? (0x20 + (nr)) : \					   (0x550 + (nr) - 7))#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr))#define W83781D_REG_FAN(nr) (0x27 + (nr))#define W83781D_REG_TEMP2_CONFIG 0x152#define W83781D_REG_TEMP3_CONFIG 0x252#define W83781D_REG_TEMP(nr)		((nr == 3) ? (0x0250) : \					((nr == 2) ? (0x0150) : \					             (0x27)))#define W83781D_REG_TEMP_HYST(nr)	((nr == 3) ? (0x253) : \					((nr == 2) ? (0x153) : \					             (0x3A)))#define W83781D_REG_TEMP_OVER(nr)	((nr == 3) ? (0x255) : \					((nr == 2) ? (0x155) : \					             (0x39)))#define W83781D_REG_BANK 0x4E#define W83781D_REG_CONFIG 0x40#define W83781D_REG_ALARM1 0x41#define W83781D_REG_ALARM2 0x42#define W83781D_REG_ALARM3 0x450#define W83781D_REG_IRQ 0x4C#define W83781D_REG_BEEP_CONFIG 0x4D#define W83781D_REG_BEEP_INTS1 0x56#define W83781D_REG_BEEP_INTS2 0x57#define W83781D_REG_BEEP_INTS3 0x453#define W83781D_REG_VID_FANDIV 0x47#define W83781D_REG_CHIPID 0x49#define W83781D_REG_WCHIPID 0x58#define W83781D_REG_CHIPMAN 0x4F#define W83781D_REG_PIN 0x4B#define W83781D_REG_VBAT 0x5D#define W83627HF_REG_PWM1 0x5A#define W83627HF_REG_PWM2 0x5B#define W83627HF_REG_PWMCLK12 0x5C#define W83627THF_REG_PWM1		0x01	/* 697HF and 637HF too */#define W83627THF_REG_PWM2		0x03	/* 697HF and 637HF too */#define W83627THF_REG_PWM3		0x11	/* 637HF too */#define W83627THF_REG_VRM_OVT_CFG 	0x18	/* 637HF too */static const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 };static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,                             W83627THF_REG_PWM3 };#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \                                     regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])#define W83781D_REG_I2C_ADDR 0x48#define W83781D_REG_I2C_SUBADDR 0x4A/* Sensor selection */#define W83781D_REG_SCFG1 0x5Dstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 };#define W83781D_REG_SCFG2 0x59static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 };#define W83781D_DEFAULT_BETA 3435/* Conversions. 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 IN_TO_REG(val)  (SENSORS_LIMIT((((val) + 8)/16),0,255))#define IN_FROM_REG(val) ((val) * 16)static inline u8 FAN_TO_REG(long rpm, int div){	if (rpm == 0)		return 255;	rpm = SENSORS_LIMIT(rpm, 1, 1000000);	return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1,			     254);}#define TEMP_MIN (-128000)#define TEMP_MAX ( 127000)/* TEMP: 0.001C/bit (-128C to +127C)   REG: 1C/bit, two's complement */static u8 TEMP_TO_REG(int temp){        int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX);        ntemp += (ntemp<0 ? -500 : 500);        return (u8)(ntemp / 1000);}static int TEMP_FROM_REG(u8 reg){        return (s8)reg * 1000;}#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))#define BEEP_MASK_FROM_REG(val)		 (val)#define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)#define BEEP_ENABLE_TO_REG(val)		((val)?1:0)#define BEEP_ENABLE_FROM_REG(val)	((val)?1:0)#define DIV_FROM_REG(val) (1 << (val))static inline u8 DIV_TO_REG(long val){	int i;	val = SENSORS_LIMIT(val, 1, 128) >> 1;	for (i = 0; i < 6; i++) {		if (val == 0)			break;		val >>= 1;	}	return ((u8) i);}/* For each registered chip, we need to keep some data in memory. That   data is pointed to by w83627hf_list[NR]->data. The structure itself is   dynamically allocated, at the same time when a new client is allocated. */struct w83627hf_data {	struct i2c_client client;	struct semaphore lock;	enum chips type;	struct semaphore update_lock;	char valid;		/* !=0 if following fields are valid */	unsigned long last_updated;	/* In jiffies */	struct i2c_client *lm75;	/* for secondary I2C addresses */	/* pointer to array of 2 subclients */	u8 in[9];		/* Register value */	u8 in_max[9];		/* Register value */	u8 in_min[9];		/* Register value */	u8 fan[3];		/* Register value */	u8 fan_min[3];		/* Register value */	u8 temp;	u8 temp_max;		/* Register value */	u8 temp_max_hyst;	/* Register value */	u16 temp_add[2];	/* Register value */	u16 temp_max_add[2];	/* Register value */	u16 temp_max_hyst_add[2]; /* Register value */	u8 fan_div[3];		/* Register encoding, shifted right */	u8 vid;			/* Register encoding, combined */	u32 alarms;		/* Register encoding, combined */	u32 beep_mask;		/* Register encoding, combined */	u8 beep_enable;		/* Boolean */	u8 pwm[3];		/* Register value */	u8 pwmenable[3];	/* bool */	u16 sens[3];		/* 782D/783S only.				   1 = pentium diode; 2 = 3904 diode;				   3000-5000 = thermistor beta.				   Default = 3435.				   Other Betas unimplemented */	u8 vrm;	u8 vrm_ovt;		/* Register value, 627thf & 637hf only */};static int w83627hf_attach_adapter(struct i2c_adapter *adapter);static int w83627hf_detect(struct i2c_adapter *adapter, int address,			  int kind);static int w83627hf_detach_client(struct i2c_client *client);static int w83627hf_read_value(struct i2c_client *client, u16 register);static int w83627hf_write_value(struct i2c_client *client, u16 register,			       u16 value);static struct w83627hf_data *w83627hf_update_device(struct device *dev);static void w83627hf_init_client(struct i2c_client *client);static struct i2c_driver w83627hf_driver = {	.owner		= THIS_MODULE,	.name		= "w83627hf",	.id		= I2C_DRIVERID_W83627HF,	.flags		= I2C_DF_NOTIFY,	.attach_adapter	= w83627hf_attach_adapter,	.detach_client	= w83627hf_detach_client,};/* following are the sysfs callback functions */#define show_in_reg(reg) \static ssize_t show_##reg (struct device *dev, char *buf, int nr) \{ \	struct w83627hf_data *data = w83627hf_update_device(dev); \	return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \}show_in_reg(in)show_in_reg(in_min)show_in_reg(in_max)#define store_in_reg(REG, reg) \static ssize_t \store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \{ \	struct i2c_client *client = to_i2c_client(dev); \	struct w83627hf_data *data = i2c_get_clientdata(client); \	u32 val; \	 \	val = simple_strtoul(buf, NULL, 10); \	data->in_##reg[nr] = IN_TO_REG(val); \	w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \			    data->in_##reg[nr]); \	 \	return count; \}store_in_reg(MIN, min)store_in_reg(MAX, max)#define sysfs_in_offset(offset) \static ssize_t \show_regs_in_##offset (struct device *dev, char *buf) \{ \        return show_in(dev, buf, 0x##offset); \} \static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL);#define sysfs_in_reg_offset(reg, offset) \static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \{ \	return show_in_##reg (dev, buf, 0x##offset); \} \static ssize_t \store_regs_in_##reg##offset (struct device *dev, \			    const char *buf, size_t count) \{ \	return store_in_##reg (dev, buf, count, 0x##offset); \} \static DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \		  show_regs_in_##reg##offset, store_regs_in_##reg##offset);#define sysfs_in_offsets(offset) \sysfs_in_offset(offset) \sysfs_in_reg_offset(min, offset) \sysfs_in_reg_offset(max, offset)sysfs_in_offsets(1);sysfs_in_offsets(2);sysfs_in_offsets(3);sysfs_in_offsets(4);sysfs_in_offsets(5);sysfs_in_offsets(6);sysfs_in_offsets(7);sysfs_in_offsets(8);/* use a different set of functions for in0 */static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg){	long in0;	if ((data->vrm_ovt & 0x01) &&		(w83627thf == data->type || w83637hf == data->type))		/* use VRM9 calculation */		in0 = (long)((reg * 488 + 70000 + 50) / 100);	else		/* use VRM8 (standard) calculation */		in0 = (long)IN_FROM_REG(reg);	return sprintf(buf,"%ld\n", in0);}static ssize_t show_regs_in_0(struct device *dev, char *buf){	struct w83627hf_data *data = w83627hf_update_device(dev);	return show_in_0(data, buf, data->in[0]);}static ssize_t show_regs_in_min0(struct device *dev, char *buf){	struct w83627hf_data *data = w83627hf_update_device(dev);	return show_in_0(data, buf, data->in_min[0]);}static ssize_t show_regs_in_max0(struct device *dev, char *buf){	struct w83627hf_data *data = w83627hf_update_device(dev);	return show_in_0(data, buf, data->in_max[0]);}static ssize_t store_regs_in_min0(struct device *dev,	const char *buf, size_t count){	struct i2c_client *client = to_i2c_client(dev);	struct w83627hf_data *data = i2c_get_clientdata(client);	u32 val;	val = simple_strtoul(buf, NULL, 10);	if ((data->vrm_ovt & 0x01) &&		(w83627thf == data->type || w83637hf == data->type))		/* use VRM9 calculation */		data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488);	else		/* use VRM8 (standard) calculation */		data->in_min[0] = IN_TO_REG(val);	w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]);	return count;}static ssize_t store_regs_in_max0(struct device *dev,	const char *buf, size_t count){	struct i2c_client *client = to_i2c_client(dev);	struct w83627hf_data *data = i2c_get_clientdata(client);	u32 val;	val = simple_strtoul(buf, NULL, 10);	if ((data->vrm_ovt & 0x01) &&		(w83627thf == data->type || w83637hf == data->type))				/* use VRM9 calculation */		data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488);	else		/* use VRM8 (standard) calculation */		data->in_max[0] = IN_TO_REG(val);	w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]);	return count;}static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL);static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,	show_regs_in_min0, store_regs_in_min0);

⌨️ 快捷键说明

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