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;
}