Skip to content
w83627ehf.c 77.3 KiB
Newer Older
		 * one.
		 */
		reg = w83627ehf_read_value(data, W83627EHF_REG_TEMP_CONFIG[2]);
		if (data->temp_src[2] == 2 && (reg & 0x01))
			data->have_temp &= ~(1 << 2);

		if ((data->temp_src[2] == 2 && (data->have_temp & (1 << 2)))
		    || (data->temp_src[3] == 2 && (data->have_temp & (1 << 3))))
			data->in6_skip = 1;

		data->temp_label = w83667hg_b_temp_label;
	} else {
		/* Temperature sources are fixed */
		for (i = 0; i < 3; i++) {
			data->reg_temp[i] = W83627EHF_REG_TEMP[i];
			data->reg_temp_over[i] = W83627EHF_REG_TEMP_OVER[i];
			data->reg_temp_hyst[i] = W83627EHF_REG_TEMP_HYST[i];
			data->reg_temp_config[i] = W83627EHF_REG_TEMP_CONFIG[i];
		}
	if (sio_data->kind == nct6775) {
		data->has_fan_div = true;
		data->fan_from_reg = fan_from_reg16;
		data->fan_from_reg_min = fan_from_reg8;
		data->REG_PWM = NCT6775_REG_PWM;
		data->REG_TARGET = NCT6775_REG_TARGET;
		data->REG_FAN = NCT6775_REG_FAN;
		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
		data->REG_FAN_MAX_OUTPUT = NCT6775_REG_FAN_MAX_OUTPUT;
		data->REG_FAN_STEP_OUTPUT = NCT6775_REG_FAN_STEP_OUTPUT;
	} else if (sio_data->kind == nct6776) {
		data->has_fan_div = false;
		data->fan_from_reg = fan_from_reg13;
		data->fan_from_reg_min = fan_from_reg13;
		data->REG_PWM = NCT6775_REG_PWM;
		data->REG_TARGET = NCT6775_REG_TARGET;
		data->REG_FAN = NCT6775_REG_FAN;
		data->REG_FAN_MIN = NCT6776_REG_FAN_MIN;
		data->REG_FAN_START_OUTPUT = NCT6775_REG_FAN_START_OUTPUT;
		data->REG_FAN_STOP_OUTPUT = NCT6775_REG_FAN_STOP_OUTPUT;
		data->REG_FAN_STOP_TIME = NCT6775_REG_FAN_STOP_TIME;
	} else if (sio_data->kind == w83667hg_b) {
		data->has_fan_div = true;
		data->fan_from_reg = fan_from_reg8;
		data->fan_from_reg_min = fan_from_reg8;
		data->REG_PWM = W83627EHF_REG_PWM;
		data->REG_TARGET = W83627EHF_REG_TARGET;
		data->REG_FAN = W83627EHF_REG_FAN;
		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
		data->REG_FAN_MAX_OUTPUT =
		  W83627EHF_REG_FAN_MAX_OUTPUT_W83667_B;
		data->REG_FAN_STEP_OUTPUT =
		  W83627EHF_REG_FAN_STEP_OUTPUT_W83667_B;
	} else {
		data->has_fan_div = true;
		data->fan_from_reg = fan_from_reg8;
		data->fan_from_reg_min = fan_from_reg8;
		data->REG_PWM = W83627EHF_REG_PWM;
		data->REG_TARGET = W83627EHF_REG_TARGET;
		data->REG_FAN = W83627EHF_REG_FAN;
		data->REG_FAN_MIN = W83627EHF_REG_FAN_MIN;
		data->REG_FAN_START_OUTPUT = W83627EHF_REG_FAN_START_OUTPUT;
		data->REG_FAN_STOP_OUTPUT = W83627EHF_REG_FAN_STOP_OUTPUT;
		data->REG_FAN_STOP_TIME = W83627EHF_REG_FAN_STOP_TIME;
		data->REG_FAN_MAX_OUTPUT =
		  W83627EHF_REG_FAN_MAX_OUTPUT_COMMON;
		data->REG_FAN_STEP_OUTPUT =
		  W83627EHF_REG_FAN_STEP_OUTPUT_COMMON;
	}
	/* Initialize the chip */
	w83627ehf_init_device(data, sio_data->kind);
	data->vrm = vid_which_vrm();
	superio_enter(sio_data->sioreg);
	/* Read VID value */
	if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b ||
	    sio_data->kind == nct6775 || sio_data->kind == nct6776) {
		/* W83667HG has different pins for VID input and output, so
		we can get the VID input values directly at logical device D
		0xe3. */
		superio_select(sio_data->sioreg, W83667HG_LD_VID);
		data->vid = superio_inb(sio_data->sioreg, 0xe3);
		err = device_create_file(dev, &dev_attr_cpu0_vid);
		if (err)
			goto exit_release;
		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);
			if (sio_data->kind == w83627ehf) /* 6 VID pins only */
				data->vid &= 0x3f;

			err = device_create_file(dev, &dev_attr_cpu0_vid);
			if (err)
				goto exit_release;
		} else {
			dev_info(dev, "VID pins in output mode, CPU VID not "
				 "available\n");
		}
	/* fan4 and fan5 share some pins with the GPIO and serial flash */
	if (sio_data->kind == nct6775) {
		/* On NCT6775, fan4 shares pins with the fdc interface */
		fan3pin = 1;
		fan4pin = !(superio_inb(sio_data->sioreg, 0x2A) & 0x80);
		fan4min = 0;
		fan5pin = 0;
	} else if (sio_data->kind == nct6776) {
		fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40);
		fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01);
		fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02);
		fan4min = fan4pin;
	} else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) {
		fan3pin = 1;
		fan4pin = superio_inb(sio_data->sioreg, 0x27) & 0x40;
		fan5pin = superio_inb(sio_data->sioreg, 0x27) & 0x20;
		fan4min = fan4pin;
		fan4pin = !(superio_inb(sio_data->sioreg, 0x29) & 0x06);
		fan5pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x02);
		fan4min = fan4pin;

	if (fan_debounce &&
	    (sio_data->kind == nct6775 || sio_data->kind == nct6776)) {
		u8 tmp;

		superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
		tmp = superio_inb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE);
		if (sio_data->kind == nct6776)
			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
				     0x3e | tmp);
		else
			superio_outb(sio_data->sioreg, NCT6775_REG_FAN_DEBOUNCE,
				     0x1e | tmp);
		pr_info("Enabled fan debounce for chip %s\n", data->name);
	}

	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 = data->has_fan_min = 0x03; /* fan1 and fan2 */

	data->has_fan |= (fan3pin << 2);
	data->has_fan_min |= (fan3pin << 2);

	/*
	 * NCT6775F and NCT6776F don't have the W83627EHF_REG_FANDIV1 register
	 */
	if (sio_data->kind == nct6775 || sio_data->kind == nct6776) {
		data->has_fan |= (fan4pin << 3) | (fan5pin << 4);
		data->has_fan_min |= (fan4min << 3) | (fan5pin << 4);
	} else {
		i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
		if ((i & (1 << 2)) && fan4pin) {
			data->has_fan |= (1 << 3);
			data->has_fan_min |= (1 << 3);
		}
		if (!(i & (1 << 1)) && fan5pin) {
			data->has_fan |= (1 << 4);
			data->has_fan_min |= (1 << 4);
		}
	}
	/* Read fan clock dividers immediately */
	w83627ehf_update_fan_div_common(dev, data);

	/* Read pwm data to save original values */
	w83627ehf_update_pwm_common(dev, data);
	for (i = 0; i < data->pwm_num; i++)
		data->pwm_enable_orig[i] = data->pwm_enable[i];
	/* Read pwm data to save original values */
	w83627ehf_update_pwm_common(dev, data);
	for (i = 0; i < data->pwm_num; i++)
		data->pwm_enable_orig[i] = data->pwm_enable[i];

	/* Register sysfs hooks */
	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++) {
		err = device_create_file(dev, &sda_sf3_arrays[i].dev_attr);
		if (err)
			goto exit_remove;
	for (i = 0; i < ARRAY_SIZE(sda_sf3_max_step_arrays); i++) {
		struct sensor_device_attribute *attr =
		  &sda_sf3_max_step_arrays[i];
		if (data->REG_FAN_STEP_OUTPUT &&
		    data->REG_FAN_STEP_OUTPUT[attr->index] != 0xff) {
			err = device_create_file(dev, &attr->dev_attr);
			if (err)
				goto exit_remove;
		}
	}
	/* if fan4 is enabled create the sf3 files for it */
	if ((data->has_fan & (1 << 3)) && data->pwm_num >= 4)
		for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
			err = device_create_file(dev,
					&sda_sf3_arrays_fan4[i].dev_attr);
			if (err)
				goto exit_remove;
		}
	for (i = 0; i < data->in_num; i++) {
		if ((i == 6) && data->in6_skip)
			continue;
		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,
				goto exit_remove;
			if (sio_data->kind != nct6776) {
				err = device_create_file(dev,
						&sda_fan_div[i].dev_attr);
				if (err)
					goto exit_remove;
			}
			if (data->has_fan_min & (1 << i)) {
				err = device_create_file(dev,
						&sda_fan_min[i].dev_attr);
				if (err)
					goto exit_remove;
			}
			if (i < data->pwm_num &&
				((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 < NUM_REG_TEMP; i++) {
		if (!(data->have_temp & (1 << i)))
		err = device_create_file(dev, &sda_temp_input[i].dev_attr);
		if (err)
			goto exit_remove;
		if (data->temp_label) {
			err = device_create_file(dev,
						 &sda_temp_label[i].dev_attr);
			if (err)
				goto exit_remove;
		}
		if (data->reg_temp_over[i]) {
			err = device_create_file(dev,
				&sda_temp_max[i].dev_attr);
			if (err)
				goto exit_remove;
		}
		if (data->reg_temp_hyst[i]) {
			err = device_create_file(dev,
				&sda_temp_max_hyst[i].dev_attr);
			if (err)
				goto exit_remove;
		}
			continue;
		if ((err = device_create_file(dev,
				&sda_temp_alarm[i].dev_attr))
			|| (err = device_create_file(dev,
				&sda_temp_type[i].dev_attr)))
			goto exit_remove;
	err = device_create_file(dev, &sda_caseopen[0].dev_attr);
	if (err)
		goto exit_remove;

	if (sio_data->kind == nct6776) {
		err = device_create_file(dev, &sda_caseopen[1].dev_attr);
		if (err)
			goto exit_remove;
	}

	err = device_create_file(dev, &dev_attr_name);
	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;
	}
exit_remove:
	w83627ehf_device_remove_files(dev);
	platform_set_drvdata(pdev, NULL);
	release_region(res->start, IOREGION_LENGTH);
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);
static struct platform_driver w83627ehf_driver = {
		.owner	= THIS_MODULE,
	.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";
	static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
	static const char __initdata sio_name_W83667HG[] = "W83667HG";
	static const char __initdata sio_name_W83667HG_B[] = "W83667HG-B";
	static const char __initdata sio_name_NCT6775[] = "NCT6775F";
	static const char __initdata sio_name_NCT6776[] = "NCT6776F";
	const char *sio_name;
	superio_enter(sioaddr);
	if (force_id)
		val = force_id;
	else
		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;
	case SIO_W83627DHG_P_ID:
		sio_data->kind = w83627dhg_p;
		sio_name = sio_name_W83627DHG_P;
		break;
	case SIO_W83667HG_ID:
		sio_data->kind = w83667hg;
		sio_name = sio_name_W83667HG;
		break;
	case SIO_W83667HG_B_ID:
		sio_data->kind = w83667hg_b;
		sio_name = sio_name_W83667HG_B;
		break;
	case SIO_NCT6775_ID:
		sio_data->kind = nct6775;
		sio_name = sio_name_NCT6775;
		break;
	case SIO_NCT6776_ID:
		sio_data->kind = nct6776;
		sio_name = sio_name_NCT6776;
		break;
		if (val != 0xffff)
			pr_debug("unsupported chip ID: 0x%04x\n", val);
		superio_exit(sioaddr);
	/* 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;
		pr_err("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);
		pr_warn("Forcibly enabling Super-I/O. "
			"Sensor is probably unusable.\n");
		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);

	superio_exit(sioaddr);
	pr_info("Found %s chip at %#x\n", sio_name, *addr);
	sio_data->sioreg = sioaddr;
/* 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))
	err = platform_driver_register(&w83627ehf_driver);
	if (err)
		goto exit;

	pdev = platform_device_alloc(DRVNAME, address);
	if (!pdev) {
		pr_err("Device allocation failed\n");
		goto exit_unregister;
	}

	err = platform_device_add_data(pdev, &sio_data,
				       sizeof(struct w83627ehf_sio_data));
	if (err) {
		pr_err("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 = acpi_check_resource_conflict(&res);
	if (err)
		goto exit_device_put;
	err = platform_device_add_resources(pdev, &res, 1);
	if (err) {
		pr_err("Device resource addition failed (%d)\n", err);
		goto exit_device_put;
	}

	/* platform_device_add calls probe() */
	err = platform_device_add(pdev);
	if (err) {
		pr_err("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);