static int __init it87_find()

in it87.c [2387:2827]


static int __init it87_find(int sioaddr, unsigned short *address,
			    struct it87_sio_data *sio_data)
{
	int err;
	u16 chip_type;
	const char *board_vendor, *board_name;
	const struct it87_devices *config;

	err = superio_enter(sioaddr);
	if (err)
		return err;

	err = -ENODEV;
	chip_type = force_id ? force_id : superio_inw(sioaddr, DEVID);

	switch (chip_type) {
	case IT8705F_DEVID:
		sio_data->type = it87;
		break;
	case IT8712F_DEVID:
		sio_data->type = it8712;
		break;
	case IT8716F_DEVID:
	case IT8726F_DEVID:
		sio_data->type = it8716;
		break;
	case IT8718F_DEVID:
		sio_data->type = it8718;
		break;
	case IT8720F_DEVID:
		sio_data->type = it8720;
		break;
	case IT8721F_DEVID:
		sio_data->type = it8721;
		break;
	case IT8728F_DEVID:
		sio_data->type = it8728;
		break;
	case IT8732F_DEVID:
		sio_data->type = it8732;
		break;
	case IT8792E_DEVID:
		sio_data->type = it8792;
		break;
	case IT8771E_DEVID:
		sio_data->type = it8771;
		break;
	case IT8772E_DEVID:
		sio_data->type = it8772;
		break;
	case IT8781F_DEVID:
		sio_data->type = it8781;
		break;
	case IT8782F_DEVID:
		sio_data->type = it8782;
		break;
	case IT8783E_DEVID:
		sio_data->type = it8783;
		break;
	case IT8786E_DEVID:
		sio_data->type = it8786;
		break;
	case IT8790E_DEVID:
		sio_data->type = it8790;
		break;
	case IT8603E_DEVID:
	case IT8623E_DEVID:
		sio_data->type = it8603;
		break;
	case IT8620E_DEVID:
		sio_data->type = it8620;
		break;
	case IT8622E_DEVID:
		sio_data->type = it8622;
		break;
	case IT8628E_DEVID:
		sio_data->type = it8628;
		break;
	case 0xffff:	/* No device at all */
		goto exit;
	default:
		pr_debug("Unsupported chip (DEVID=0x%x)\n", chip_type);
		goto exit;
	}

	superio_select(sioaddr, PME);
	if (!(superio_inb(sioaddr, IT87_ACT_REG) & 0x01)) {
		pr_info("Device not activated, skipping\n");
		goto exit;
	}

	*address = superio_inw(sioaddr, IT87_BASE_REG) & ~(IT87_EXTENT - 1);
	if (*address == 0) {
		pr_info("Base address not set, skipping\n");
		goto exit;
	}

	err = 0;
	sio_data->sioaddr = sioaddr;
	sio_data->revision = superio_inb(sioaddr, DEVREV) & 0x0f;
	pr_info("Found IT%04x%s chip at 0x%x, revision %d\n", chip_type,
		it87_devices[sio_data->type].suffix,
		*address, sio_data->revision);

	config = &it87_devices[sio_data->type];

	/* in7 (VSB or VCCH5V) is always internal on some chips */
	if (has_in7_internal(config))
		sio_data->internal |= BIT(1);

	/* in8 (Vbat) is always internal */
	sio_data->internal |= BIT(2);

	/* in9 (AVCC3), always internal if supported */
	if (has_avcc3(config))
		sio_data->internal |= BIT(3); /* in9 is AVCC */
	else
		sio_data->skip_in |= BIT(9);

	if (!has_five_pwm(config))
		sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5);
	else if (!has_six_pwm(config))
		sio_data->skip_pwm |= BIT(5);

	if (!has_vid(config))
		sio_data->skip_vid = 1;

	/* Read GPIO config and VID value from LDN 7 (GPIO) */
	if (sio_data->type == it87) {
		/* The IT8705F has a different LD number for GPIO */
		superio_select(sioaddr, 5);
		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	} else if (sio_data->type == it8783) {
		int reg25, reg27, reg2a, reg2c, regef;

		superio_select(sioaddr, GPIO);

		reg25 = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
		reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG);
		reg2c = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
		regef = superio_inb(sioaddr, IT87_SIO_SPI_REG);

		/* Check if fan3 is there or not */
		if ((reg27 & BIT(0)) || !(reg2c & BIT(2)))
			sio_data->skip_fan |= BIT(2);
		if ((reg25 & BIT(4)) ||
		    (!(reg2a & BIT(1)) && (regef & BIT(0))))
			sio_data->skip_pwm |= BIT(2);

		/* Check if fan2 is there or not */
		if (reg27 & BIT(7))
			sio_data->skip_fan |= BIT(1);
		if (reg27 & BIT(3))
			sio_data->skip_pwm |= BIT(1);

		/* VIN5 */
		if ((reg27 & BIT(0)) || (reg2c & BIT(2)))
			sio_data->skip_in |= BIT(5); /* No VIN5 */

		/* VIN6 */
		if (reg27 & BIT(1))
			sio_data->skip_in |= BIT(6); /* No VIN6 */

		/*
		 * VIN7
		 * Does not depend on bit 2 of Reg2C, contrary to datasheet.
		 */
		if (reg27 & BIT(2)) {
			/*
			 * The data sheet is a bit unclear regarding the
			 * internal voltage divider for VCCH5V. It says
			 * "This bit enables and switches VIN7 (pin 91) to the
			 * internal voltage divider for VCCH5V".
			 * This is different to other chips, where the internal
			 * voltage divider would connect VIN7 to an internal
			 * voltage source. Maybe that is the case here as well.
			 *
			 * Since we don't know for sure, re-route it if that is
			 * not the case, and ask the user to report if the
			 * resulting voltage is sane.
			 */
			if (!(reg2c & BIT(1))) {
				reg2c |= BIT(1);
				superio_outb(sioaddr, IT87_SIO_PINX2_REG,
					     reg2c);
				sio_data->need_in7_reroute = true;
				pr_notice("Routing internal VCCH5V to in7.\n");
			}
			pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
			pr_notice("Please report if it displays a reasonable voltage.\n");
		}

		if (reg2c & BIT(0))
			sio_data->internal |= BIT(0);
		if (reg2c & BIT(1))
			sio_data->internal |= BIT(1);

		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	} else if (sio_data->type == it8603) {
		int reg27, reg29;

		superio_select(sioaddr, GPIO);

		reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);

		/* Check if fan3 is there or not */
		if (reg27 & BIT(6))
			sio_data->skip_pwm |= BIT(2);
		if (reg27 & BIT(7))
			sio_data->skip_fan |= BIT(2);

		/* Check if fan2 is there or not */
		reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
		if (reg29 & BIT(1))
			sio_data->skip_pwm |= BIT(1);
		if (reg29 & BIT(2))
			sio_data->skip_fan |= BIT(1);

		sio_data->skip_in |= BIT(5); /* No VIN5 */
		sio_data->skip_in |= BIT(6); /* No VIN6 */

		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	} else if (sio_data->type == it8620 || sio_data->type == it8628) {
		int reg;

		superio_select(sioaddr, GPIO);

		/* Check for pwm5 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
		if (reg & BIT(6))
			sio_data->skip_pwm |= BIT(4);

		/* Check for fan4, fan5 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
		if (!(reg & BIT(5)))
			sio_data->skip_fan |= BIT(3);
		if (!(reg & BIT(4)))
			sio_data->skip_fan |= BIT(4);

		/* Check for pwm3, fan3 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
		if (reg & BIT(6))
			sio_data->skip_pwm |= BIT(2);
		if (reg & BIT(7))
			sio_data->skip_fan |= BIT(2);

		/* Check for pwm4 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG);
		if (reg & BIT(2))
			sio_data->skip_pwm |= BIT(3);

		/* Check for pwm2, fan2 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
		if (reg & BIT(1))
			sio_data->skip_pwm |= BIT(1);
		if (reg & BIT(2))
			sio_data->skip_fan |= BIT(1);
		/* Check for pwm6, fan6 */
		if (!(reg & BIT(7))) {
			sio_data->skip_pwm |= BIT(5);
			sio_data->skip_fan |= BIT(5);
		}

		/* Check if AVCC is on VIN3 */
		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
		if (reg & BIT(0))
			sio_data->internal |= BIT(0);
		else
			sio_data->skip_in |= BIT(9);

		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	} else if (sio_data->type == it8622) {
		int reg;

		superio_select(sioaddr, GPIO);

		/* Check for pwm4, fan4 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG);
		if (reg & BIT(6))
			sio_data->skip_fan |= BIT(3);
		if (reg & BIT(5))
			sio_data->skip_pwm |= BIT(3);

		/* Check for pwm3, fan3, pwm5, fan5 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
		if (reg & BIT(6))
			sio_data->skip_pwm |= BIT(2);
		if (reg & BIT(7))
			sio_data->skip_fan |= BIT(2);
		if (reg & BIT(3))
			sio_data->skip_pwm |= BIT(4);
		if (reg & BIT(1))
			sio_data->skip_fan |= BIT(4);

		/* Check for pwm2, fan2 */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
		if (reg & BIT(1))
			sio_data->skip_pwm |= BIT(1);
		if (reg & BIT(2))
			sio_data->skip_fan |= BIT(1);

		/* Check for AVCC */
		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);
		if (!(reg & BIT(0)))
			sio_data->skip_in |= BIT(9);

		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	} else {
		int reg;
		bool uart6;

		superio_select(sioaddr, GPIO);

		/* Check for fan4, fan5 */
		if (has_five_fans(config)) {
			reg = superio_inb(sioaddr, IT87_SIO_GPIO2_REG);
			switch (sio_data->type) {
			case it8718:
				if (reg & BIT(5))
					sio_data->skip_fan |= BIT(3);
				if (reg & BIT(4))
					sio_data->skip_fan |= BIT(4);
				break;
			case it8720:
			case it8721:
			case it8728:
				if (!(reg & BIT(5)))
					sio_data->skip_fan |= BIT(3);
				if (!(reg & BIT(4)))
					sio_data->skip_fan |= BIT(4);
				break;
			default:
				break;
			}
		}

		reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
		if (!sio_data->skip_vid) {
			/* We need at least 4 VID pins */
			if (reg & 0x0f) {
				pr_info("VID is disabled (pins used for GPIO)\n");
				sio_data->skip_vid = 1;
			}
		}

		/* Check if fan3 is there or not */
		if (reg & BIT(6))
			sio_data->skip_pwm |= BIT(2);
		if (reg & BIT(7))
			sio_data->skip_fan |= BIT(2);

		/* Check if fan2 is there or not */
		reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
		if (reg & BIT(1))
			sio_data->skip_pwm |= BIT(1);
		if (reg & BIT(2))
			sio_data->skip_fan |= BIT(1);

		if ((sio_data->type == it8718 || sio_data->type == it8720) &&
		    !(sio_data->skip_vid))
			sio_data->vid_value = superio_inb(sioaddr,
							  IT87_SIO_VID_REG);

		reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG);

		uart6 = sio_data->type == it8782 && (reg & BIT(2));

		/*
		 * The IT8720F has no VIN7 pin, so VCCH5V should always be
		 * routed internally to VIN7 with an internal divider.
		 * Curiously, there still is a configuration bit to control
		 * this, which means it can be set incorrectly. And even
		 * more curiously, many boards out there are improperly
		 * configured, even though the IT8720F datasheet claims
		 * that the internal routing of VCCH5V to VIN7 is the default
		 * setting. So we force the internal routing in this case.
		 *
		 * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
		 * If UART6 is enabled, re-route VIN7 to the internal divider
		 * if that is not already the case.
		 */
		if ((sio_data->type == it8720 || uart6) && !(reg & BIT(1))) {
			reg |= BIT(1);
			superio_outb(sioaddr, IT87_SIO_PINX2_REG, reg);
			sio_data->need_in7_reroute = true;
			pr_notice("Routing internal VCCH5V to in7\n");
		}
		if (reg & BIT(0))
			sio_data->internal |= BIT(0);
		if (reg & BIT(1))
			sio_data->internal |= BIT(1);

		/*
		 * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
		 * While VIN7 can be routed to the internal voltage divider,
		 * VIN5 and VIN6 are not available if UART6 is enabled.
		 *
		 * Also, temp3 is not available if UART6 is enabled and TEMPIN3
		 * is the temperature source. Since we can not read the
		 * temperature source here, skip_temp is preliminary.
		 */
		if (uart6) {
			sio_data->skip_in |= BIT(5) | BIT(6);
			sio_data->skip_temp |= BIT(2);
		}

		sio_data->beep_pin = superio_inb(sioaddr,
						 IT87_SIO_BEEP_PIN_REG) & 0x3f;
	}
	if (sio_data->beep_pin)
		pr_info("Beeping is supported\n");

	/* Disable specific features based on DMI strings */
	board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
	board_name = dmi_get_system_info(DMI_BOARD_NAME);
	if (board_vendor && board_name) {
		if (strcmp(board_vendor, "nVIDIA") == 0 &&
		    strcmp(board_name, "FN68PT") == 0) {
			/*
			 * On the Shuttle SN68PT, FAN_CTL2 is apparently not
			 * connected to a fan, but to something else. One user
			 * has reported instant system power-off when changing
			 * the PWM2 duty cycle, so we disable it.
			 * I use the board name string as the trigger in case
			 * the same board is ever used in other systems.
			 */
			pr_info("Disabling pwm2 due to hardware constraints\n");
			sio_data->skip_pwm = BIT(1);
		}
	}

exit:
	superio_exit(sioaddr);
	return err;
}