static int fintek_wdt_start()

in f71808e_wdt.c [287:411]


static int fintek_wdt_start(struct watchdog_device *wdd)
{
	struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
	int err;
	u8 tmp;

	/* Make sure we don't die as soon as the watchdog is enabled below */
	err = fintek_wdt_keepalive(wdd);
	if (err)
		return err;

	err = superio_enter(wd->sioaddr);
	if (err)
		return err;
	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);

	/* Watchdog pin configuration */
	switch (wd->type) {
	case f71808fg:
		/* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3);
		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3);
		break;

	case f71862fg:
		if (f71862fg_pin == 63) {
			/* SPI must be disabled first to use this pin! */
			superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6);
			superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4);
		} else if (f71862fg_pin == 56) {
			superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
		}
		break;

	case f71868:
	case f71869:
		/* GPIO14 --> WDTRST# */
		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4);
		break;

	case f71882fg:
		/* Set pin 56 to WDTRST# */
		superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
		break;

	case f71889fg:
		/* set pin 40 to WDTRST# */
		superio_outb(wd->sioaddr, SIO_REG_MFUNCT3,
			superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf);
		break;

	case f81803:
		/* Enable TSI Level register bank */
		superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3);
		/* Set pin 27 to WDTRST# */
		superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f &
			superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL));
		break;

	case f81865:
		/* Set pin 70 to WDTRST# */
		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5);
		break;

	case f81866:
	case f81966:
		/*
		 * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0.
		 * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch:
		 *     BIT5: 0 -> WDTRST#
		 *           1 -> GPIO15
		 */
		tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL);
		tmp &= ~(BIT(3) | BIT(0));
		tmp |= BIT(2);
		superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp);

		superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5);
		break;

	default:
		/*
		 * 'default' label to shut up the compiler and catch
		 * programmer errors
		 */
		err = -ENODEV;
		goto exit_superio;
	}

	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
	superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0);

	if (wd->type == f81865 || wd->type == f81866 || wd->type == f81966)
		superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF,
				F81865_FLAG_WDOUT_EN);
	else
		superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF,
				F71808FG_FLAG_WDOUT_EN);

	superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
			F71808FG_FLAG_WD_EN);

	if (wd->pulse_mode) {
		/* Select "pulse" output mode with given duration */
		u8 wdt_conf = superio_inb(wd->sioaddr,
				F71808FG_REG_WDT_CONF);

		/* Set WD_PSWIDTH bits (1:0) */
		wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03);
		/* Set WD_PULSE to "pulse" mode */
		wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);

		superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF,
				wdt_conf);
	} else {
		/* Select "level" output mode */
		superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
				F71808FG_FLAG_WD_PULSE);
	}

exit_superio:
	superio_exit(wd->sioaddr);

	return err;
}