w83627ehf.c

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

C
1,579
字号
		device_remove_file(dev, &sda_fan_alarm[i].dev_attr);		device_remove_file(dev, &sda_fan_div[i].dev_attr);		device_remove_file(dev, &sda_fan_min[i].dev_attr);	}	for (i = 0; i < 4; i++) {		device_remove_file(dev, &sda_pwm[i].dev_attr);		device_remove_file(dev, &sda_pwm_mode[i].dev_attr);		device_remove_file(dev, &sda_pwm_enable[i].dev_attr);		device_remove_file(dev, &sda_target_temp[i].dev_attr);		device_remove_file(dev, &sda_tolerance[i].dev_attr);	}	for (i = 0; i < ARRAY_SIZE(sda_temp); i++)		device_remove_file(dev, &sda_temp[i].dev_attr);	device_remove_file(dev, &dev_attr_name);	if (data->vid != 0x3f)		device_remove_file(dev, &dev_attr_cpu0_vid);}/* Get the monitoring functions started */static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data){	int i;	u8 tmp, diode;	/* Start monitoring is needed */	tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);	if (!(tmp & 0x01))		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,				      tmp | 0x01);	/* Enable temp2 and temp3 if needed */	for (i = 0; i < 2; i++) {		tmp = w83627ehf_read_value(data,					   W83627EHF_REG_TEMP_CONFIG[i]);		if (tmp & 0x01)			w83627ehf_write_value(data,					      W83627EHF_REG_TEMP_CONFIG[i],					      tmp & 0xfe);	}	/* Enable VBAT monitoring if needed */	tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);	if (!(tmp & 0x01))		w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);	/* Get thermal sensor types */	diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);	for (i = 0; i < 3; i++) {		if ((tmp & (0x02 << i)))			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;		else			data->temp_type[i] = 4; /* thermistor */	}}static int __devinit w83627ehf_probe(struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct w83627ehf_sio_data *sio_data = dev->platform_data;	struct w83627ehf_data *data;	struct resource *res;	u8 fan4pin, fan5pin, en_vrm10;	int i, err = 0;	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {		err = -EBUSY;		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",			(unsigned long)res->start,			(unsigned long)res->start + IOREGION_LENGTH - 1);		goto exit;	}	if (!(data = kzalloc(sizeof(struct w83627ehf_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit_release;	}	data->addr = res->start;	mutex_init(&data->lock);	mutex_init(&data->update_lock);	data->name = w83627ehf_device_names[sio_data->kind];	platform_set_drvdata(pdev, data);	/* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */	data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;	/* Initialize the chip */	w83627ehf_init_device(data);	data->vrm = vid_which_vrm();	superio_enter(sio_data->sioreg);	/* Read VID value */	superio_select(sio_data->sioreg, W83627EHF_LD_HWM);	if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80) {		/* Set VID input sensibility if needed. In theory the BIOS		   should have set it, but in practice it's not always the		   case. We only do it for the W83627EHF/EHG because the		   W83627DHG is more complex in this respect. */		if (sio_data->kind == w83627ehf) {			en_vrm10 = superio_inb(sio_data->sioreg,					       SIO_REG_EN_VRM10);			if ((en_vrm10 & 0x08) && data->vrm == 90) {				dev_warn(dev, "Setting VID input voltage to "					 "TTL\n");				superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,					     en_vrm10 & ~0x08);			} else if (!(en_vrm10 & 0x08) && data->vrm == 100) {				dev_warn(dev, "Setting VID input voltage to "					 "VRM10\n");				superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,					     en_vrm10 | 0x08);			}		}		data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;	} else {		dev_info(dev, "VID pins in output mode, CPU VID not "			 "available\n");		data->vid = 0x3f;	}	/* fan4 and fan5 share some pins with the GPIO and serial flash */	fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;	fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;	superio_exit(sio_data->sioreg);	/* It looks like fan4 and fan5 pins can be alternatively used	   as fan on/off switches, but fan5 control is write only :/	   We assume that if the serial interface is disabled, designers	   connected fan5 as input unless they are emitting log 1, which	   is not the default. */	data->has_fan = 0x07; /* fan1, fan2 and fan3 */	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);	if ((i & (1 << 2)) && (!fan4pin))		data->has_fan |= (1 << 3);	if (!(i & (1 << 1)) && (!fan5pin))		data->has_fan |= (1 << 4);	/* Read fan clock dividers immediately */	w83627ehf_update_fan_div(data);	/* Register sysfs hooks */  	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)		if ((err = device_create_file(dev,			&sda_sf3_arrays[i].dev_attr)))			goto exit_remove;	/* if fan4 is enabled create the sf3 files for it */	if (data->has_fan & (1 << 3))		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {			if ((err = device_create_file(dev,				&sda_sf3_arrays_fan4[i].dev_attr)))				goto exit_remove;		}	for (i = 0; i < data->in_num; i++)		if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))			|| (err = device_create_file(dev,				&sda_in_alarm[i].dev_attr))			|| (err = device_create_file(dev,				&sda_in_min[i].dev_attr))			|| (err = device_create_file(dev,				&sda_in_max[i].dev_attr)))			goto exit_remove;	for (i = 0; i < 5; i++) {		if (data->has_fan & (1 << i)) {			if ((err = device_create_file(dev,					&sda_fan_input[i].dev_attr))				|| (err = device_create_file(dev,					&sda_fan_alarm[i].dev_attr))				|| (err = device_create_file(dev,					&sda_fan_div[i].dev_attr))				|| (err = device_create_file(dev,					&sda_fan_min[i].dev_attr)))				goto exit_remove;			if (i < 4 && /* w83627ehf only has 4 pwm */				((err = device_create_file(dev,					&sda_pwm[i].dev_attr))				|| (err = device_create_file(dev,					&sda_pwm_mode[i].dev_attr))				|| (err = device_create_file(dev,					&sda_pwm_enable[i].dev_attr))				|| (err = device_create_file(dev,					&sda_target_temp[i].dev_attr))				|| (err = device_create_file(dev,					&sda_tolerance[i].dev_attr))))				goto exit_remove;		}	}	for (i = 0; i < ARRAY_SIZE(sda_temp); i++)		if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))			goto exit_remove;	err = device_create_file(dev, &dev_attr_name);	if (err)		goto exit_remove;	if (data->vid != 0x3f) {		err = device_create_file(dev, &dev_attr_cpu0_vid);		if (err)			goto exit_remove;	}	data->hwmon_dev = hwmon_device_register(dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		goto exit_remove;	}	return 0;exit_remove:	w83627ehf_device_remove_files(dev);	kfree(data);	platform_set_drvdata(pdev, NULL);exit_release:	release_region(res->start, IOREGION_LENGTH);exit:	return err;}static int __devexit w83627ehf_remove(struct platform_device *pdev){	struct w83627ehf_data *data = platform_get_drvdata(pdev);	hwmon_device_unregister(data->hwmon_dev);	w83627ehf_device_remove_files(&pdev->dev);	release_region(data->addr, IOREGION_LENGTH);	platform_set_drvdata(pdev, NULL);	kfree(data);	return 0;}static struct platform_driver w83627ehf_driver = {	.driver = {		.owner	= THIS_MODULE,		.name	= DRVNAME,	},	.probe		= w83627ehf_probe,	.remove		= __devexit_p(w83627ehf_remove),};/* w83627ehf_find() looks for a '627 in the Super-I/O config space */static int __init w83627ehf_find(int sioaddr, unsigned short *addr,				 struct w83627ehf_sio_data *sio_data){	static const char __initdata sio_name_W83627EHF[] = "W83627EHF";	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";	u16 val;	const char *sio_name;	superio_enter(sioaddr);	val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)	    | superio_inb(sioaddr, SIO_REG_DEVID + 1);	switch (val & SIO_ID_MASK) {	case SIO_W83627EHF_ID:		sio_data->kind = w83627ehf;		sio_name = sio_name_W83627EHF;		break;	case SIO_W83627EHG_ID:		sio_data->kind = w83627ehf;		sio_name = sio_name_W83627EHG;		break;	case SIO_W83627DHG_ID:		sio_data->kind = w83627dhg;		sio_name = sio_name_W83627DHG;		break;	default:		if (val != 0xffff)			pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",				 val);		superio_exit(sioaddr);		return -ENODEV;	}	/* We have a known chip, find the HWM I/O address */	superio_select(sioaddr, W83627EHF_LD_HWM);	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);	*addr = val & IOREGION_ALIGNMENT;	if (*addr == 0) {		printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "		       "device with a base I/O port 0.\n");		superio_exit(sioaddr);		return -ENODEV;	}	/* Activate logical device if needed */	val = superio_inb(sioaddr, SIO_REG_ENABLE);	if (!(val & 0x01)) {		printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "		       "Sensor is probably unusable.\n");		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);	}	superio_exit(sioaddr);	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);	sio_data->sioreg = sioaddr;	return 0;}/* when Super-I/O functions move to a separate file, the Super-I/O * bus will manage the lifetime of the device and this module will only keep * track of the w83627ehf driver. But since we platform_device_alloc(), we * must keep track of the device */static struct platform_device *pdev;static int __init sensors_w83627ehf_init(void){	int err;	unsigned short address;	struct resource res;	struct w83627ehf_sio_data sio_data;	/* initialize sio_data->kind and sio_data->sioreg.	 *	 * when Super-I/O functions move to a separate file, the Super-I/O	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a	 * w83627ehf hardware monitor, and call probe() */	if (w83627ehf_find(0x2e, &address, &sio_data) &&	    w83627ehf_find(0x4e, &address, &sio_data))		return -ENODEV;	err = platform_driver_register(&w83627ehf_driver);	if (err)		goto exit;	if (!(pdev = platform_device_alloc(DRVNAME, address))) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Device allocation failed\n");		goto exit_unregister;	}	err = platform_device_add_data(pdev, &sio_data,				       sizeof(struct w83627ehf_sio_data));	if (err) {		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");		goto exit_device_put;	}	memset(&res, 0, sizeof(res));	res.name = DRVNAME;	res.start = address + IOREGION_OFFSET;	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;	res.flags = IORESOURCE_IO;	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;	}	/* platform_device_add calls probe() */	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_unregister:	platform_driver_unregister(&w83627ehf_driver);exit:	return err;}static void __exit sensors_w83627ehf_exit(void){	platform_device_unregister(pdev);	platform_driver_unregister(&w83627ehf_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("W83627EHF driver");MODULE_LICENSE("GPL");module_init(sensors_w83627ehf_init);module_exit(sensors_w83627ehf_exit);

⌨️ 快捷键说明

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