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

📄 w83627hf.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	superio_exit();	return 0;}int w83627hf_detect(struct i2c_adapter *adapter, int address,		   int kind){	int val;	struct i2c_client *new_client;	struct w83627hf_data *data;	int err = 0;	const char *client_name = "";	if (!i2c_is_isa_adapter(adapter)) {		err = -ENODEV;		goto ERROR0;	}	if(force_addr)		address = force_addr & ~(WINB_EXTENT - 1);	if (!request_region(address, WINB_EXTENT, "w83627hf")) {		err = -EBUSY;		goto ERROR0;	}	if(force_addr) {		printk("w83627hf.o: forcing ISA address 0x%04X\n", address);		superio_enter();		superio_select(W83627HF_LD_HWM);		superio_outb(WINB_BASE_REG, address >> 8);		superio_outb(WINB_BASE_REG+1, address & 0xff);		superio_exit();	}	superio_enter();	val= superio_inb(DEVID);	if(val == W627_DEVID)		kind = w83627hf;	else if(val == W697_DEVID)		kind = w83697hf;	else if(val == W627THF_DEVID)		kind = w83627thf;	else if(val == W637_DEVID)		kind = w83637hf;	else {		dev_info(&adapter->dev,			 "Unsupported chip (dev_id=0x%02X).\n", val);		goto ERROR1;	}	superio_select(W83627HF_LD_HWM);	if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0)		superio_outb(WINB_ACT_REG, 1);	superio_exit();	/* OK. For now, we presume we have a valid client. We now create the	   client structure, even though we cannot fill it completely yet.	   But it allows us to access w83627hf_{read,write}_value. */	if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) {		err = -ENOMEM;		goto ERROR1;	}	memset(data, 0, sizeof(struct w83627hf_data));	new_client = &data->client;	i2c_set_clientdata(new_client, data);	new_client->addr = address;	init_MUTEX(&data->lock);	new_client->adapter = adapter;	new_client->driver = &w83627hf_driver;	new_client->flags = 0;	if (kind == w83627hf) {		client_name = "w83627hf";	} else if (kind == w83627thf) {		client_name = "w83627thf";	} else if (kind == w83697hf) {		client_name = "w83697hf";	} else if (kind == w83637hf) {		client_name = "w83637hf";	}	/* Fill in the remaining client fields and put into the global list */	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);	data->type = kind;	data->valid = 0;	init_MUTEX(&data->update_lock);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(new_client)))		goto ERROR2;	data->lm75 = NULL;	/* Initialize the chip */	w83627hf_init_client(new_client);	/* A few vars need to be filled upon startup */	data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1));	data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));	data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));	/* Register sysfs hooks */	device_create_file_in(new_client, 0);	if (kind != w83697hf)		device_create_file_in(new_client, 1);	device_create_file_in(new_client, 2);	device_create_file_in(new_client, 3);	device_create_file_in(new_client, 4);	if (kind != w83627thf && kind != w83637hf) {		device_create_file_in(new_client, 5);		device_create_file_in(new_client, 6);	}	device_create_file_in(new_client, 7);	device_create_file_in(new_client, 8);	device_create_file_fan(new_client, 1);	device_create_file_fan(new_client, 2);	if (kind != w83697hf)		device_create_file_fan(new_client, 3);	device_create_file_temp(new_client, 1);	device_create_file_temp(new_client, 2);	if (kind != w83697hf)		device_create_file_temp(new_client, 3);	if (kind != w83697hf)		device_create_file_vid(new_client);	if (kind != w83697hf)		device_create_file_vrm(new_client);	device_create_file_fan_div(new_client, 1);	device_create_file_fan_div(new_client, 2);	if (kind != w83697hf)		device_create_file_fan_div(new_client, 3);	device_create_file_alarms(new_client);	device_create_file_beep(new_client);	device_create_file_pwm(new_client, 1);	device_create_file_pwm(new_client, 2);	if (kind == w83627thf || kind == w83637hf)		device_create_file_pwm(new_client, 3);	device_create_file_sensor(new_client, 1);	device_create_file_sensor(new_client, 2);	if (kind != w83697hf)		device_create_file_sensor(new_client, 3);	return 0;      ERROR2:	kfree(data);      ERROR1:	release_region(address, WINB_EXTENT);      ERROR0:	return err;}static int w83627hf_detach_client(struct i2c_client *client){	int err;	if ((err = i2c_detach_client(client))) {		dev_err(&client->dev,		       "Client deregistration failed, client not detached.\n");		return err;	}	release_region(client->addr, WINB_EXTENT);	kfree(i2c_get_clientdata(client));	return 0;}/*   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 int w83627hf_read_value(struct i2c_client *client, u16 reg){	struct w83627hf_data *data = i2c_get_clientdata(client);	int res, word_sized;	down(&data->lock);	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);	}	up(&data->lock);	return res;}static int w83627thf_read_gpio5(struct i2c_client *client){	struct w83627hf_data *data = i2c_get_clientdata(client);	int res, inv;	down(&data->lock);	superio_enter();	superio_select(W83627HF_LD_GPIO5);	res = superio_inb(W83627THF_GPIO5_DR);	inv = superio_inb(W83627THF_GPIO5_INVR);	superio_exit();	up(&data->lock);	return res;}static int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value){	struct w83627hf_data *data = i2c_get_clientdata(client);	int word_sized;	down(&data->lock);	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);	}	up(&data->lock);	return 0;}/* Called when we have found a new W83781D. It should set limits, etc. */static void w83627hf_init_client(struct i2c_client *client){	struct w83627hf_data *data = i2c_get_clientdata(client);	int i;	int type = data->type;	u8 tmp;	if(init) {		/* save this register */		i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG);		/* Reset all except Watchdog values and last conversion values		   This sets fan-divs to 2, among others */		w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80);		/* Restore the register and disable power-on abnormal beep.		   This saves FAN 1/2/3 input/output values set by BIOS. */		w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80);		/* Disable master beep-enable (reset turns it on).		   Individual beeps should be reset to off but for some reason		   disabling this bit helps some people not get beeped */		w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0);	}	/* Minimize conflicts with other winbond i2c-only clients...  */	/* disable i2c subclients... how to disable main i2c client?? */	/* force i2c address to relatively uncommon address */	w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89);	w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c);	/* Read VID only once */	if (w83627hf == data->type || w83637hf == data->type) {		int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);		int hi = w83627hf_read_value(client, W83781D_REG_CHIPID);		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);	} else if (w83627thf == data->type) {		data->vid = w83627thf_read_gpio5(client) & 0x1f;	}	/* Read VRM & OVT Config only once */	if (w83627thf == data->type || w83637hf == data->type) {		data->vrm_ovt = 			w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG);		data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82;	} else {		/* Convert VID to voltage based on default VRM */		data->vrm = DEFAULT_VRM;	}	tmp = w83627hf_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 (w83627hf_read_value			    (client,			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])				data->sens[i - 1] = 1;			else				data->sens[i - 1] = 2;		}		if ((type == w83697hf) && (i == 2))			break;	}	data->pwmenable[0] = 1;	data->pwmenable[1] = 1;	data->pwmenable[2] = 1;	if(init) {		if (type == w83627hf) {			/* enable PWM2 control (can't hurt since PWM reg		           should have been reset to 0xff) */			w83627hf_write_value(client, W83627HF_REG_PWMCLK12,					    0x19);		}		/* enable comparator mode for temp2 and temp3 so	           alarm indication will work correctly */		i = w83627hf_read_value(client, W83781D_REG_IRQ);		if (!(i & 0x40))			w83627hf_write_value(client, W83781D_REG_IRQ,					    i | 0x40);	}	/* Start monitoring */	w83627hf_write_value(client, W83781D_REG_CONFIG,			    (w83627hf_read_value(client,						W83781D_REG_CONFIG) & 0xf7)			    | 0x01);}static struct w83627hf_data *w83627hf_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct w83627hf_data *data = i2c_get_clientdata(client);	int i;	down(&data->update_lock);	if ((jiffies - data->last_updated > HZ + HZ / 2) ||	    (jiffies < data->last_updated) || !data->valid) {		for (i = 0; i <= 8; i++) {			/* skip missing sensors */			if (((data->type == w83697hf) && (i == 1)) ||			    ((data->type == w83627thf || data->type == w83637hf)			    && (i == 4 || i == 5)))				continue;			data->in[i] =			    w83627hf_read_value(client, W83781D_REG_IN(i));			data->in_min[i] =			    w83627hf_read_value(client,					       W83781D_REG_IN_MIN(i));			data->in_max[i] =			    w83627hf_read_value(client,					       W83781D_REG_IN_MAX(i));		}		for (i = 1; i <= 3; i++) {			data->fan[i - 1] =			    w83627hf_read_value(client, W83781D_REG_FAN(i));			data->fan_min[i - 1] =			    w83627hf_read_value(client,					       W83781D_REG_FAN_MIN(i));		}		for (i = 1; i <= 3; i++) {			u8 tmp = w83627hf_read_value(client,				W836X7HF_REG_PWM(data->type, i)); 			/* bits 0-3 are reserved  in 627THF */ 			if (data->type == w83627thf)				tmp &= 0xf0;			data->pwm[i - 1] = tmp;			if(i == 2 &&			   (data->type == w83627hf || data->type == w83697hf))				break;		}		data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1));		data->temp_max =		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1));		data->temp_max_hyst =		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1));		data->temp_add[0] =		    w83627hf_read_value(client, W83781D_REG_TEMP(2));		data->temp_max_add[0] =		    w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2));		data->temp_max_hyst_add[0] =		    w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2));		if (data->type != w83697hf) {			data->temp_add[1] =			  w83627hf_read_value(client, W83781D_REG_TEMP(3));			data->temp_max_add[1] =			  w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3));			data->temp_max_hyst_add[1] =			  w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3));		}		i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV);		data->fan_div[0] = (i >> 4) & 0x03;		data->fan_div[1] = (i >> 6) & 0x03;		if (data->type != w83697hf) {			data->fan_div[2] = (w83627hf_read_value(client,					       W83781D_REG_PIN) >> 6) & 0x03;		}		i = w83627hf_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 =		    w83627hf_read_value(client, W83781D_REG_ALARM1) |		    (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) |		    (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16);		i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2);		data->beep_enable = i >> 7;		data->beep_mask = ((i & 0x7f) << 8) |		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) |		    w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16;		data->last_updated = jiffies;		data->valid = 1;	}	up(&data->update_lock);	return data;}static int __init sensors_w83627hf_init(void){	int addr;	if (w83627hf_find(&addr)) {		return -ENODEV;	}	normal_isa[0] = addr;	return i2c_add_driver(&w83627hf_driver);}static void __exit sensors_w83627hf_exit(void){	i2c_del_driver(&w83627hf_driver);}MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, "	      "Philip Edelbrock <phil@netroedge.com>, "	      "and Mark Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("W83627HF driver");MODULE_LICENSE("GPL");module_init(sensors_w83627hf_init);module_exit(sensors_w83627hf_exit);

⌨️ 快捷键说明

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