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

📄 w83781d.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
		device_create_file_pwm(new_client, 3);		device_create_file_pwm(new_client, 4);	}	if (kind != as99127f && kind != w83781d) {		device_create_file_sensor(new_client, 1);		device_create_file_sensor(new_client, 2);		if (kind != w83783s && kind != w83697hf)			device_create_file_sensor(new_client, 3);	}#ifdef W83781D_RT	if (kind == w83781d) {		device_create_file_rt(new_client, 1);		device_create_file_rt(new_client, 2);		device_create_file_rt(new_client, 3);	}#endif	return 0;ERROR3:	i2c_detach_client(new_client);ERROR2:	kfree(data);ERROR1:	if (is_isa)		release_region(address, W83781D_EXTENT);ERROR0:	return err;}static intw83781d_detach_client(struct i2c_client *client){	int err;	if (i2c_is_isa_client(client))		release_region(client->addr, W83781D_EXTENT);	if ((err = i2c_detach_client(client))) {		dev_err(&client->dev,		       "Client deregistration failed, client not detached.\n");		return err;	}	if (i2c_get_clientdata(client)==NULL) {		/* subclients */		kfree(client);	} else {		/* main client */		kfree(i2c_get_clientdata(client));	}	return 0;}/* The SMBus locks itself, usually, but nothing may access the Winbond between   bank switches. ISA access must always be locked explicitly!    We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks,   would slow down the W83781D access and should not be necessary.    There are some ugly typecasts here, but the good news is - they should   nowhere else be necessary! */static intw83781d_read_value(struct i2c_client *client, u16 reg){	struct w83781d_data *data = i2c_get_clientdata(client);	int res, word_sized, bank;	struct i2c_client *cl;	down(&data->lock);	if (i2c_is_isa_client(client)) {		word_sized = (((reg & 0xff00) == 0x100)			      || ((reg & 0xff00) == 0x200))		    && (((reg & 0x00ff) == 0x50)			|| ((reg & 0x00ff) == 0x53)			|| ((reg & 0x00ff) == 0x55));		if (reg & 0xff00) {			outb_p(W83781D_REG_BANK,			       client->addr + W83781D_ADDR_REG_OFFSET);			outb_p(reg >> 8,			       client->addr + W83781D_DATA_REG_OFFSET);		}		outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);		res = inb_p(client->addr + W83781D_DATA_REG_OFFSET);		if (word_sized) {			outb_p((reg & 0xff) + 1,			       client->addr + W83781D_ADDR_REG_OFFSET);			res =			    (res << 8) + inb_p(client->addr +					       W83781D_DATA_REG_OFFSET);		}		if (reg & 0xff00) {			outb_p(W83781D_REG_BANK,			       client->addr + W83781D_ADDR_REG_OFFSET);			outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);		}	} else {		bank = (reg >> 8) & 0x0f;		if (bank > 2)			/* switch banks */			i2c_smbus_write_byte_data(client, W83781D_REG_BANK,						  bank);		if (bank == 0 || bank > 2) {			res = i2c_smbus_read_byte_data(client, reg & 0xff);		} else {			/* switch to subclient */			cl = data->lm75[bank - 1];			/* convert from ISA to LM75 I2C addresses */			switch (reg & 0xff) {			case 0x50:	/* TEMP */				res = swab16(i2c_smbus_read_word_data(cl, 0));				break;			case 0x52:	/* CONFIG */				res = i2c_smbus_read_byte_data(cl, 1);				break;			case 0x53:	/* HYST */				res = swab16(i2c_smbus_read_word_data(cl, 2));				break;			case 0x55:	/* OVER */			default:				res = swab16(i2c_smbus_read_word_data(cl, 3));				break;			}		}		if (bank > 2)			i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);	}	up(&data->lock);	return res;}static intw83781d_write_value(struct i2c_client *client, u16 reg, u16 value){	struct w83781d_data *data = i2c_get_clientdata(client);	int word_sized, bank;	struct i2c_client *cl;	down(&data->lock);	if (i2c_is_isa_client(client)) {		word_sized = (((reg & 0xff00) == 0x100)			      || ((reg & 0xff00) == 0x200))		    && (((reg & 0x00ff) == 0x53)			|| ((reg & 0x00ff) == 0x55));		if (reg & 0xff00) {			outb_p(W83781D_REG_BANK,			       client->addr + W83781D_ADDR_REG_OFFSET);			outb_p(reg >> 8,			       client->addr + W83781D_DATA_REG_OFFSET);		}		outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET);		if (word_sized) {			outb_p(value >> 8,			       client->addr + W83781D_DATA_REG_OFFSET);			outb_p((reg & 0xff) + 1,			       client->addr + W83781D_ADDR_REG_OFFSET);		}		outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET);		if (reg & 0xff00) {			outb_p(W83781D_REG_BANK,			       client->addr + W83781D_ADDR_REG_OFFSET);			outb_p(0, client->addr + W83781D_DATA_REG_OFFSET);		}	} else {		bank = (reg >> 8) & 0x0f;		if (bank > 2)			/* switch banks */			i2c_smbus_write_byte_data(client, W83781D_REG_BANK,						  bank);		if (bank == 0 || bank > 2) {			i2c_smbus_write_byte_data(client, reg & 0xff,						  value & 0xff);		} else {			/* switch to subclient */			cl = data->lm75[bank - 1];			/* convert from ISA to LM75 I2C addresses */			switch (reg & 0xff) {			case 0x52:	/* CONFIG */				i2c_smbus_write_byte_data(cl, 1, value & 0xff);				break;			case 0x53:	/* HYST */				i2c_smbus_write_word_data(cl, 2, swab16(value));				break;			case 0x55:	/* OVER */				i2c_smbus_write_word_data(cl, 3, swab16(value));				break;			}		}		if (bank > 2)			i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0);	}	up(&data->lock);	return 0;}/* Called when we have found a new W83781D. It should set limits, etc. */static voidw83781d_init_client(struct i2c_client *client){	struct w83781d_data *data = i2c_get_clientdata(client);	int i, p;	int type = data->type;	u8 tmp;	if (init && type != as99127f) {	/* this resets registers we don't have					   documentation for on the as99127f */		/* save these registers */		i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG);		p = w83781d_read_value(client, W83781D_REG_PWMCLK12);		/* Reset all except Watchdog values and last conversion values		   This sets fan-divs to 2, among others */		w83781d_write_value(client, W83781D_REG_CONFIG, 0x80);		/* Restore the registers and disable power-on abnormal beep.		   This saves FAN 1/2/3 input/output values set by BIOS. */		w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);		w83781d_write_value(client, W83781D_REG_PWMCLK12, p);		/* Disable master beep-enable (reset turns it on).		   Individual beep_mask should be reset to off but for some reason		   disabling this bit helps some people not get beeped */		w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0);	}	data->vrm = 82;	if ((type != w83781d) && (type != as99127f)) {		tmp = w83781d_read_value(client, W83781D_REG_SCFG1);		for (i = 1; i <= 3; i++) {			if (!(tmp & BIT_SCFG1[i - 1])) {				data->sens[i - 1] = W83781D_DEFAULT_BETA;			} else {				if (w83781d_read_value				    (client,				     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])					data->sens[i - 1] = 1;				else					data->sens[i - 1] = 2;			}			if ((type == w83783s || type == w83697hf) && (i == 2))				break;		}	}#ifdef W83781D_RT/*   Fill up the RT Tables.   We assume that they are 32 bytes long, in order for temp 1-3.   Data sheet documentation is sparse.   We also assume that it is only for the 781D although I suspect   that the others support it as well....*/	if (init && type == w83781d) {		u16 k = 0;/*    Auto-indexing doesn't seem to work...    w83781d_write_value(client,W83781D_REG_RT_IDX,0);*/		for (i = 0; i < 3; i++) {			int j;			for (j = 0; j < 32; j++) {				w83781d_write_value(client,						    W83781D_REG_RT_IDX, k++);				data->rt[i][j] =				    w83781d_read_value(client,						       W83781D_REG_RT_VAL);			}		}	}#endif				/* W83781D_RT */	if (init) {		if (type != w83783s && type != w83697hf) {			w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG,					    0x00);		}		if (type != w83781d) {			/* enable comparator mode for temp2 and temp3 so			   alarm indication will work correctly */			i = w83781d_read_value(client, W83781D_REG_IRQ);			if (!(i & 0x40))				w83781d_write_value(client, W83781D_REG_IRQ,						    i | 0x40);		}	}	/* Start monitoring */	w83781d_write_value(client, W83781D_REG_CONFIG,			    (w83781d_read_value(client,						W83781D_REG_CONFIG) & 0xf7)			    | 0x01);}static struct w83781d_data *w83781d_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct w83781d_data *data = i2c_get_clientdata(client);	int i;	down(&data->update_lock);	if (time_after	    (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2))	    || time_before(jiffies, data->last_updated) || !data->valid) {		pr_debug("Starting device update\n");		for (i = 0; i <= 8; i++) {			if ((data->type == w83783s || data->type == w83697hf)			    && (i == 1))				continue;	/* 783S has no in1 */			data->in[i] =			    w83781d_read_value(client, W83781D_REG_IN(i));			data->in_min[i] =			    w83781d_read_value(client, W83781D_REG_IN_MIN(i));			data->in_max[i] =			    w83781d_read_value(client, W83781D_REG_IN_MAX(i));			if ((data->type != w83782d) && (data->type != w83697hf)			    && (data->type != w83627hf) && (i == 6))				break;		}		for (i = 1; i <= 3; i++) {			data->fan[i - 1] =			    w83781d_read_value(client, W83781D_REG_FAN(i));			data->fan_min[i - 1] =			    w83781d_read_value(client, W83781D_REG_FAN_MIN(i));		}		if (data->type != w83781d && data->type != as99127f) {			for (i = 1; i <= 4; i++) {				data->pwm[i - 1] =				    w83781d_read_value(client,						       W83781D_REG_PWM(i));				if ((data->type != w83782d				     || i2c_is_isa_client(client))				    && i == 2)					break;			}			/* Only PWM2 can be disabled */			data->pwmenable[1] = (w83781d_read_value(client,					      W83781D_REG_PWMCLK12) & 0x08) >> 3;		}		data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1));		data->temp_max =		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(1));		data->temp_max_hyst =		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(1));		data->temp_add[0] =		    w83781d_read_value(client, W83781D_REG_TEMP(2));		data->temp_max_add[0] =		    w83781d_read_value(client, W83781D_REG_TEMP_OVER(2));		data->temp_max_hyst_add[0] =		    w83781d_read_value(client, W83781D_REG_TEMP_HYST(2));		if (data->type != w83783s && data->type != w83697hf) {			data->temp_add[1] =			    w83781d_read_value(client, W83781D_REG_TEMP(3));			data->temp_max_add[1] =			    w83781d_read_value(client,					       W83781D_REG_TEMP_OVER(3));			data->temp_max_hyst_add[1] =			    w83781d_read_value(client,					       W83781D_REG_TEMP_HYST(3));		}		i = w83781d_read_value(client, W83781D_REG_VID_FANDIV);		if (data->type != w83697hf) {			data->vid = i & 0x0f;			data->vid |=			    (w83781d_read_value(client, W83781D_REG_CHIPID) &			     0x01)			    << 4;		}		data->fan_div[0] = (i >> 4) & 0x03;		data->fan_div[1] = (i >> 6) & 0x03;		if (data->type != w83697hf) {			data->fan_div[2] = (w83781d_read_value(client,							       W83781D_REG_PIN)					    >> 6) & 0x03;		}		if ((data->type != w83781d) && (data->type != as99127f)) {			i = w83781d_read_value(client, W83781D_REG_VBAT);			data->fan_div[0] |= (i >> 3) & 0x04;			data->fan_div[1] |= (i >> 4) & 0x04;			if (data->type != w83697hf)				data->fan_div[2] |= (i >> 5) & 0x04;		}		data->alarms =		    w83781d_read_value(client,				       W83781D_REG_ALARM1) +		    (w83781d_read_value(client, W83781D_REG_ALARM2) << 8);		if ((data->type == w83782d) || (data->type == w83627hf)) {			data->alarms |=			    w83781d_read_value(client,					       W83781D_REG_ALARM3) << 16;		}		i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2);		data->beep_enable = i >> 7;		data->beep_mask = ((i & 0x7f) << 8) +		    w83781d_read_value(client, W83781D_REG_BEEP_INTS1);		if ((data->type != w83781d) && (data->type != as99127f)) {			data->beep_mask |=			    w83781d_read_value(client,					       W83781D_REG_BEEP_INTS3) << 16;		}		data->last_updated = jiffies;		data->valid = 1;	}	up(&data->update_lock);	return data;}static int __initsensors_w83781d_init(void){	return i2c_add_driver(&w83781d_driver);}static void __exitsensors_w83781d_exit(void){	i2c_del_driver(&w83781d_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "	      "Philip Edelbrock <phil@netroedge.com>, "	      "and Mark Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("W83781D driver");MODULE_LICENSE("GPL");module_init(sensors_w83781d_init);module_exit(sensors_w83781d_exit);

⌨️ 快捷键说明

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