vt1211.c

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

C
1,371
字号
	SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \		show_temp, NULL, SHOW_TEMP_INPUT, ix-1)static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = {	SENSOR_ATTR_TEMP_INPUT(1),	SENSOR_ATTR_TEMP_INPUT(2),	SENSOR_ATTR_TEMP_INPUT(3),	SENSOR_ATTR_TEMP_INPUT(4),	SENSOR_ATTR_TEMP_INPUT(5),	SENSOR_ATTR_TEMP_INPUT(6),	SENSOR_ATTR_TEMP_INPUT(7),};#define SENSOR_ATTR_TEMP_MAX(ix) \	SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \		show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1)static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = {	SENSOR_ATTR_TEMP_MAX(1),	SENSOR_ATTR_TEMP_MAX(2),	SENSOR_ATTR_TEMP_MAX(3),	SENSOR_ATTR_TEMP_MAX(4),	SENSOR_ATTR_TEMP_MAX(5),	SENSOR_ATTR_TEMP_MAX(6),	SENSOR_ATTR_TEMP_MAX(7),};#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \	SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \		show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1)static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = {	SENSOR_ATTR_TEMP_MAX_HYST(1),	SENSOR_ATTR_TEMP_MAX_HYST(2),	SENSOR_ATTR_TEMP_MAX_HYST(3),	SENSOR_ATTR_TEMP_MAX_HYST(4),	SENSOR_ATTR_TEMP_MAX_HYST(5),	SENSOR_ATTR_TEMP_MAX_HYST(6),	SENSOR_ATTR_TEMP_MAX_HYST(7),};#define SENSOR_ATTR_TEMP_ALARM(ix) \	SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \		show_temp, NULL, SHOW_TEMP_ALARM, ix-1)static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = {	SENSOR_ATTR_TEMP_ALARM(1),	SENSOR_ATTR_TEMP_ALARM(2),	SENSOR_ATTR_TEMP_ALARM(3),	SENSOR_ATTR_TEMP_ALARM(4),	SENSOR_ATTR_TEMP_ALARM(5),	SENSOR_ATTR_TEMP_ALARM(6),	SENSOR_ATTR_TEMP_ALARM(7),};#define SENSOR_ATTR_FAN(ix) \	SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \		show_fan, NULL, SHOW_FAN_INPUT, ix-1), \	SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \		show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \	SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \		show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \	SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \		show_fan, NULL, SHOW_FAN_ALARM, ix-1)#define SENSOR_ATTR_PWM(ix) \	SENSOR_ATTR_2(pwm##ix, S_IRUGO, \		show_pwm, NULL, SHOW_PWM, ix-1), \	SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \		show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \	SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \		show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)#define SENSOR_ATTR_PWM_FREQ(ix) \	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \		show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)#define SENSOR_ATTR_PWM_FREQ_RO(ix) \	SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \		show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \		show_pwm_auto_point_temp, set_pwm_auto_point_temp, \		ap-1, ix-1)#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \		show_pwm_auto_point_temp, NULL, \		ap-1, ix-1)#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \		show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \		ap-1, ix-1)#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \	SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \		show_pwm_auto_point_pwm, NULL, \		ap-1, ix-1)static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {	SENSOR_ATTR_FAN(1),	SENSOR_ATTR_FAN(2),	SENSOR_ATTR_PWM(1),	SENSOR_ATTR_PWM(2),	SENSOR_ATTR_PWM_FREQ(1),	SENSOR_ATTR_PWM_FREQ_RO(2),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),	SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),	SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),	SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),	SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),};static struct device_attribute vt1211_sysfs_misc[] = {	__ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),	__ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),	__ATTR(name, S_IRUGO, show_name, NULL),	__ATTR(alarms, S_IRUGO, show_alarms, NULL),};/* --------------------------------------------------------------------- * Device registration and initialization * --------------------------------------------------------------------- */static void __devinit vt1211_init_device(struct vt1211_data *data){	/* set VRM */	data->vrm = vid_which_vrm();	/* Read (and initialize) UCH config */	data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);	if (uch_config > -1) {		data->uch_config = (data->uch_config & 0x83) |				   (uch_config << 2);		vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);	}	/* Initialize the interrupt mode (if request at module load time).	 * The VT1211 implements 3 different modes for clearing interrupts:	 * 0: Clear INT when status register is read. Regenerate INT as long	 *    as temp stays above hysteresis limit.	 * 1: Clear INT when status register is read. DON'T regenerate INT	 *    until temp falls below hysteresis limit and exceeds hot limit	 *    again.	 * 2: Clear INT when temp falls below max limit.	 *	 * The driver only allows to force mode 0 since that's the only one	 * that makes sense for 'sensors' */	if (int_mode == 0) {		vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);		vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);	}	/* Fill in some hard wired values into our data struct */	data->pwm_auto_pwm[0][3] = 255;	data->pwm_auto_pwm[1][3] = 255;}static void vt1211_remove_sysfs(struct platform_device *pdev){	struct device *dev = &pdev->dev;	int i;	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {		device_remove_file(dev,			&vt1211_sysfs_in_input[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_in_min[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_in_max[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_in_alarm[i].dev_attr);	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {		device_remove_file(dev,			&vt1211_sysfs_temp_input[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_temp_max[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_temp_max_hyst[i].dev_attr);		device_remove_file(dev,			&vt1211_sysfs_temp_alarm[i].dev_attr);	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {		device_remove_file(dev,			&vt1211_sysfs_fan_pwm[i].dev_attr);	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {		device_remove_file(dev, &vt1211_sysfs_misc[i]);	}}static int __devinit vt1211_probe(struct platform_device *pdev){	struct device *dev = &pdev->dev;	struct vt1211_data *data;	struct resource *res;	int i, err;	if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) {		err = -ENOMEM;		dev_err(dev, "Out of memory\n");		goto EXIT;	}	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) {		err = -EBUSY;		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",			(unsigned long)res->start, (unsigned long)res->end);		goto EXIT_KFREE;	}	data->addr = res->start;	data->name = DRVNAME;	mutex_init(&data->update_lock);	platform_set_drvdata(pdev, data);	/* Initialize the VT1211 chip */	vt1211_init_device(data);	/* Create sysfs interface files */	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {		if (ISVOLT(i, data->uch_config)) {			if ((err = device_create_file(dev,				&vt1211_sysfs_in_input[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_in_min[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_in_max[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_in_alarm[i].dev_attr))) {				goto EXIT_DEV_REMOVE;			}		}	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {		if (ISTEMP(i, data->uch_config)) {			if ((err = device_create_file(dev,				&vt1211_sysfs_temp_input[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_temp_max[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_temp_max_hyst[i].dev_attr)) ||			    (err = device_create_file(dev,				&vt1211_sysfs_temp_alarm[i].dev_attr))) {				goto EXIT_DEV_REMOVE;			}		}	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {		err = device_create_file(dev,			&vt1211_sysfs_fan_pwm[i].dev_attr);		if (err) {			goto EXIT_DEV_REMOVE;		}	}	for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {		err = device_create_file(dev,		       &vt1211_sysfs_misc[i]);		if (err) {			goto EXIT_DEV_REMOVE;		}	}	/* Register device */	data->hwmon_dev = hwmon_device_register(dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		dev_err(dev, "Class registration failed (%d)\n", err);		goto EXIT_DEV_REMOVE_SILENT;	}	return 0;EXIT_DEV_REMOVE:	dev_err(dev, "Sysfs interface creation failed (%d)\n", err);EXIT_DEV_REMOVE_SILENT:	vt1211_remove_sysfs(pdev);	release_region(res->start, res->end - res->start + 1);EXIT_KFREE:	platform_set_drvdata(pdev, NULL);	kfree(data);EXIT:	return err;}static int __devexit vt1211_remove(struct platform_device *pdev){	struct vt1211_data *data = platform_get_drvdata(pdev);	struct resource *res;	hwmon_device_unregister(data->hwmon_dev);	vt1211_remove_sysfs(pdev);	platform_set_drvdata(pdev, NULL);	kfree(data);	res = platform_get_resource(pdev, IORESOURCE_IO, 0);	release_region(res->start, res->end - res->start + 1);	return 0;}static struct platform_driver vt1211_driver = {	.driver = {		.owner = THIS_MODULE,		.name  = DRVNAME,	},	.probe  = vt1211_probe,	.remove = __devexit_p(vt1211_remove),};static int __init vt1211_device_add(unsigned short address){	struct resource res = {		.start	= address,		.end	= address + 0x7f,		.flags	= IORESOURCE_IO,	};	int err;	pdev = platform_device_alloc(DRVNAME, address);	if (!pdev) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",		       err);		goto EXIT;	}	res.name = pdev->name;	err = platform_device_add_resources(pdev, &res, 1);	if (err) {		printk(KERN_ERR DRVNAME ": Device resource addition failed "		       "(%d)\n", err);		goto EXIT_DEV_PUT;	}	err = platform_device_add(pdev);	if (err) {		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",		       err);		goto EXIT_DEV_PUT;	}	return 0;EXIT_DEV_PUT:	platform_device_put(pdev);EXIT:	return err;}static int __init vt1211_find(int sio_cip, unsigned short *address){	int err = -ENODEV;	superio_enter(sio_cip);	if (superio_inb(sio_cip, SIO_VT1211_DEVID) != SIO_VT1211_ID) {		goto EXIT;	}	superio_select(sio_cip, SIO_VT1211_LDN_HWMON);	if ((superio_inb(sio_cip, SIO_VT1211_ACTIVE) & 1) == 0) {		printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "		       "skipping\n");		goto EXIT;	}	*address = ((superio_inb(sio_cip, SIO_VT1211_BADDR) << 8) |		    (superio_inb(sio_cip, SIO_VT1211_BADDR + 1))) & 0xff00;	if (*address == 0) {		printk(KERN_WARNING DRVNAME ": Base address is not set, "		       "skipping\n");		goto EXIT;	}	err = 0;	printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "	       "revision %u\n", *address,	       superio_inb(sio_cip, SIO_VT1211_DEVREV));EXIT:	superio_exit(sio_cip);	return err;}static int __init vt1211_init(void){	int err;	unsigned short address = 0;	if ((err = vt1211_find(SIO_REG_CIP1, &address)) &&	    (err = vt1211_find(SIO_REG_CIP2, &address))) {		goto EXIT;	}	if ((uch_config < -1) || (uch_config > 31)) {		err = -EINVAL;		printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "		       "Choose a value between 0 and 31.\n", uch_config);	  goto EXIT;	}	if ((int_mode < -1) || (int_mode > 0)) {		err = -EINVAL;		printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "		       "Only mode 0 is supported.\n", int_mode);	  goto EXIT;	}	err = platform_driver_register(&vt1211_driver);	if (err) {		goto EXIT;	}	/* Sets global pdev as a side effect */	err = vt1211_device_add(address);	if (err) {		goto EXIT_DRV_UNREGISTER;	}	return 0;EXIT_DRV_UNREGISTER:	platform_driver_unregister(&vt1211_driver);EXIT:	return err;}static void __exit vt1211_exit(void){	platform_device_unregister(pdev);	platform_driver_unregister(&vt1211_driver);}MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");MODULE_DESCRIPTION("VT1211 sensors");MODULE_LICENSE("GPL");module_init(vt1211_init);module_exit(vt1211_exit);

⌨️ 快捷键说明

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