w83627hf.c

来自「linux 内核源代码」· C语言 代码 · 共 1,707 行 · 第 1/4 页

C
1,707
字号
	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);	platform_set_drvdata(pdev, NULL);	kfree(data);	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	release_region(res->start, WINB_REGION_SIZE);	return 0;}/* Registers 0x50-0x5f are banked */static inline void w83627hf_set_bank(struct w83627hf_data *data, u16 reg){	if ((reg & 0x00f0) == 0x50) {		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);		outb_p(reg >> 8, data->addr + W83781D_DATA_REG_OFFSET);	}}/* Not strictly necessary, but play it safe for now */static inline void w83627hf_reset_bank(struct w83627hf_data *data, u16 reg){	if (reg & 0xff00) {		outb_p(W83781D_REG_BANK, data->addr + W83781D_ADDR_REG_OFFSET);		outb_p(0, data->addr + W83781D_DATA_REG_OFFSET);	}}static int w83627hf_read_value(struct w83627hf_data *data, u16 reg){	int res, word_sized;	mutex_lock(&data->lock);	word_sized = (((reg & 0xff00) == 0x100)		   || ((reg & 0xff00) == 0x200))		  && (((reg & 0x00ff) == 0x50)		   || ((reg & 0x00ff) == 0x53)		   || ((reg & 0x00ff) == 0x55));	w83627hf_set_bank(data, reg);	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);	res = inb_p(data->addr + W83781D_DATA_REG_OFFSET);	if (word_sized) {		outb_p((reg & 0xff) + 1,		       data->addr + W83781D_ADDR_REG_OFFSET);		res =		    (res << 8) + inb_p(data->addr +				       W83781D_DATA_REG_OFFSET);	}	w83627hf_reset_bank(data, reg);	mutex_unlock(&data->lock);	return res;}static int __devinit w83627thf_read_gpio5(struct platform_device *pdev){	int res = 0xff, sel;	superio_enter();	superio_select(W83627HF_LD_GPIO5);	/* Make sure these GPIO pins are enabled */	if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) {		dev_dbg(&pdev->dev, "GPIO5 disabled, no VID function\n");		goto exit;	}	/* Make sure the pins are configured for input	   There must be at least five (VRM 9), and possibly 6 (VRM 10) */	sel = superio_inb(W83627THF_GPIO5_IOSR) & 0x3f;	if ((sel & 0x1f) != 0x1f) {		dev_dbg(&pdev->dev, "GPIO5 not configured for VID "			"function\n");		goto exit;	}	dev_info(&pdev->dev, "Reading VID from GPIO5\n");	res = superio_inb(W83627THF_GPIO5_DR) & sel;exit:	superio_exit();	return res;}static int __devinit w83687thf_read_vid(struct platform_device *pdev){	int res = 0xff;	superio_enter();	superio_select(W83627HF_LD_HWM);	/* Make sure these GPIO pins are enabled */	if (!(superio_inb(W83687THF_VID_EN) & (1 << 2))) {		dev_dbg(&pdev->dev, "VID disabled, no VID function\n");		goto exit;	}	/* Make sure the pins are configured for input */	if (!(superio_inb(W83687THF_VID_CFG) & (1 << 4))) {		dev_dbg(&pdev->dev, "VID configured as output, "			"no VID function\n");		goto exit;	}	res = superio_inb(W83687THF_VID_DATA) & 0x3f;exit:	superio_exit();	return res;}static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value){	int word_sized;	mutex_lock(&data->lock);	word_sized = (((reg & 0xff00) == 0x100)		   || ((reg & 0xff00) == 0x200))		  && (((reg & 0x00ff) == 0x53)		   || ((reg & 0x00ff) == 0x55));	w83627hf_set_bank(data, reg);	outb_p(reg & 0xff, data->addr + W83781D_ADDR_REG_OFFSET);	if (word_sized) {		outb_p(value >> 8,		       data->addr + W83781D_DATA_REG_OFFSET);		outb_p((reg & 0xff) + 1,		       data->addr + W83781D_ADDR_REG_OFFSET);	}	outb_p(value & 0xff,	       data->addr + W83781D_DATA_REG_OFFSET);	w83627hf_reset_bank(data, reg);	mutex_unlock(&data->lock);	return 0;}static void __devinit w83627hf_init_device(struct platform_device *pdev){	struct w83627hf_data *data = platform_get_drvdata(pdev);	int i;	enum chips type = data->type;	u8 tmp;	if (reset) {		/* Resetting the chip has been the default for a long time,		   but repeatedly caused problems (fans going to full		   speed...) so it is now optional. It might even go away if		   nobody reports it as being useful, as I see very little		   reason why this would be needed at all. */		dev_info(&pdev->dev, "If reset=1 solved a problem you were "			 "having, please report!\n");		/* save this register */		i = w83627hf_read_value(data, W83781D_REG_BEEP_CONFIG);		/* Reset all except Watchdog values and last conversion values		   This sets fan-divs to 2, among others */		w83627hf_write_value(data, 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(data, 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(data, 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(data, W83781D_REG_I2C_SUBADDR, 0x89);	w83627hf_write_value(data, W83781D_REG_I2C_ADDR, force_i2c);	/* Read VID only once */	if (type == w83627hf || type == w83637hf) {		int lo = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);		int hi = w83627hf_read_value(data, W83781D_REG_CHIPID);		data->vid = (lo & 0x0f) | ((hi & 0x01) << 4);	} else if (type == w83627thf) {		data->vid = w83627thf_read_gpio5(pdev);	} else if (type == w83687thf) {		data->vid = w83687thf_read_vid(pdev);	}	/* Read VRM & OVT Config only once */	if (type == w83627thf || type == w83637hf || type == w83687thf) {		data->vrm_ovt = 			w83627hf_read_value(data, W83627THF_REG_VRM_OVT_CFG);	}	tmp = w83627hf_read_value(data, W83781D_REG_SCFG1);	for (i = 1; i <= 3; i++) {		if (!(tmp & BIT_SCFG1[i - 1])) {			data->sens[i - 1] = 4;		} else {			if (w83627hf_read_value			    (data,			     W83781D_REG_SCFG2) & BIT_SCFG2[i - 1])				data->sens[i - 1] = 1;			else				data->sens[i - 1] = 2;		}		if ((type == w83697hf) && (i == 2))			break;	}	if(init) {		/* Enable temp2 */		tmp = w83627hf_read_value(data, W83627HF_REG_TEMP2_CONFIG);		if (tmp & 0x01) {			dev_warn(&pdev->dev, "Enabling temp2, readings "				 "might not make sense\n");			w83627hf_write_value(data, W83627HF_REG_TEMP2_CONFIG,				tmp & 0xfe);		}		/* Enable temp3 */		if (type != w83697hf) {			tmp = w83627hf_read_value(data,				W83627HF_REG_TEMP3_CONFIG);			if (tmp & 0x01) {				dev_warn(&pdev->dev, "Enabling temp3, "					 "readings might not make sense\n");				w83627hf_write_value(data,					W83627HF_REG_TEMP3_CONFIG, tmp & 0xfe);			}		}	}	/* Start monitoring */	w83627hf_write_value(data, W83781D_REG_CONFIG,			    (w83627hf_read_value(data,						W83781D_REG_CONFIG) & 0xf7)			    | 0x01);}static void w83627hf_update_fan_div(struct w83627hf_data *data){	int reg;	reg = w83627hf_read_value(data, W83781D_REG_VID_FANDIV);	data->fan_div[0] = (reg >> 4) & 0x03;	data->fan_div[1] = (reg >> 6) & 0x03;	if (data->type != w83697hf) {		data->fan_div[2] = (w83627hf_read_value(data,				       W83781D_REG_PIN) >> 6) & 0x03;	}	reg = w83627hf_read_value(data, W83781D_REG_VBAT);	data->fan_div[0] |= (reg >> 3) & 0x04;	data->fan_div[1] |= (reg >> 4) & 0x04;	if (data->type != w83697hf)		data->fan_div[2] |= (reg >> 5) & 0x04;}static struct w83627hf_data *w83627hf_update_device(struct device *dev){	struct w83627hf_data *data = dev_get_drvdata(dev);	int i, num_temps = (data->type == w83697hf) ? 2 : 3;	mutex_lock(&data->update_lock);	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)	    || !data->valid) {		for (i = 0; i <= 8; i++) {			/* skip missing sensors */			if (((data->type == w83697hf) && (i == 1)) ||			    ((data->type != w83627hf && data->type != w83697hf)			    && (i == 5 || i == 6)))				continue;			data->in[i] =			    w83627hf_read_value(data, W83781D_REG_IN(i));			data->in_min[i] =			    w83627hf_read_value(data,					       W83781D_REG_IN_MIN(i));			data->in_max[i] =			    w83627hf_read_value(data,					       W83781D_REG_IN_MAX(i));		}		for (i = 0; i <= 2; i++) {			data->fan[i] =			    w83627hf_read_value(data, W83627HF_REG_FAN(i));			data->fan_min[i] =			    w83627hf_read_value(data,					       W83627HF_REG_FAN_MIN(i));		}		for (i = 0; i <= 2; i++) {			u8 tmp = w83627hf_read_value(data,				W836X7HF_REG_PWM(data->type, i)); 			/* bits 0-3 are reserved  in 627THF */ 			if (data->type == w83627thf)				tmp &= 0xf0;			data->pwm[i] = tmp;			if (i == 1 &&			    (data->type == w83627hf || data->type == w83697hf))				break;		}		if (data->type == w83627hf) {				u8 tmp = w83627hf_read_value(data,						W83627HF_REG_PWM_FREQ);				data->pwm_freq[0] = tmp & 0x07;				data->pwm_freq[1] = (tmp >> 4) & 0x07;		} else if (data->type != w83627thf) {			for (i = 1; i <= 3; i++) {				data->pwm_freq[i - 1] =					w83627hf_read_value(data,						W83637HF_REG_PWM_FREQ[i - 1]);				if (i == 2 && (data->type == w83697hf))					break;			}		}		for (i = 0; i < num_temps; i++) {			data->temp[i] = w83627hf_read_value(						data, w83627hf_reg_temp[i]);			data->temp_max[i] = w83627hf_read_value(						data, w83627hf_reg_temp_over[i]);			data->temp_max_hyst[i] = w83627hf_read_value(						data, w83627hf_reg_temp_hyst[i]);		}		w83627hf_update_fan_div(data);		data->alarms =		    w83627hf_read_value(data, W83781D_REG_ALARM1) |		    (w83627hf_read_value(data, W83781D_REG_ALARM2) << 8) |		    (w83627hf_read_value(data, W83781D_REG_ALARM3) << 16);		i = w83627hf_read_value(data, W83781D_REG_BEEP_INTS2);		data->beep_enable = i >> 7;		data->beep_mask = ((i & 0x7f) << 8) |		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS1) |		    w83627hf_read_value(data, W83781D_REG_BEEP_INTS3) << 16;		data->last_updated = jiffies;		data->valid = 1;	}	mutex_unlock(&data->update_lock);	return data;}static int __init w83627hf_device_add(unsigned short address,				      const struct w83627hf_sio_data *sio_data){	struct resource res = {		.start	= address + WINB_REGION_OFFSET,		.end	= address + WINB_REGION_OFFSET + WINB_REGION_SIZE - 1,		.name	= DRVNAME,		.flags	= IORESOURCE_IO,	};	int err;	pdev = platform_device_alloc(DRVNAME, address);	if (!pdev) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Device allocation failed\n");		goto exit;	}	err = platform_device_add_resources(pdev, &res, 1);	if (err) {		printk(KERN_ERR DRVNAME ": Device resource addition failed "		       "(%d)\n", err);		goto exit_device_put;	}	err = platform_device_add_data(pdev, sio_data,				       sizeof(struct w83627hf_sio_data));	if (err) {		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");		goto exit_device_put;	}	err = platform_device_add(pdev);	if (err) {		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",		       err);		goto exit_device_put;	}	return 0;exit_device_put:	platform_device_put(pdev);exit:	return err;}static int __init sensors_w83627hf_init(void){	int err;	unsigned short address;	struct w83627hf_sio_data sio_data;	if (w83627hf_find(0x2e, &address, &sio_data)	 && w83627hf_find(0x4e, &address, &sio_data))		return -ENODEV;	err = platform_driver_register(&w83627hf_driver);	if (err)		goto exit;	/* Sets global pdev as a side effect */	err = w83627hf_device_add(address, &sio_data);	if (err)		goto exit_driver;	return 0;exit_driver:	platform_driver_unregister(&w83627hf_driver);exit:	return err;}static void __exit sensors_w83627hf_exit(void){	platform_device_unregister(pdev);	platform_driver_unregister(&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 + =
减小字号Ctrl + -
显示快捷键?