Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /***************************************************************************
0003  *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
0004  *   Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com>           *
0005  *   Copyright (C) 2010 Giel van Schijndel <me@mortis.eu>                  *
0006  *                                                                         *
0007  ***************************************************************************/
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/err.h>
0012 #include <linux/init.h>
0013 #include <linux/io.h>
0014 #include <linux/ioport.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/watchdog.h>
0018 
0019 #define DRVNAME "f71808e_wdt"
0020 
0021 #define SIO_F71808FG_LD_WDT 0x07    /* Watchdog timer logical device */
0022 #define SIO_UNLOCK_KEY      0x87    /* Key to enable Super-I/O */
0023 #define SIO_LOCK_KEY        0xAA    /* Key to disable Super-I/O */
0024 
0025 #define SIO_REG_LDSEL       0x07    /* Logical device select */
0026 #define SIO_REG_DEVID       0x20    /* Device ID (2 bytes) */
0027 #define SIO_REG_DEVREV      0x22    /* Device revision */
0028 #define SIO_REG_MANID       0x23    /* Fintek ID (2 bytes) */
0029 #define SIO_REG_CLOCK_SEL   0x26    /* Clock select */
0030 #define SIO_REG_ROM_ADDR_SEL    0x27    /* ROM address select */
0031 #define SIO_F81866_REG_PORT_SEL 0x27    /* F81866 Multi-Function Register */
0032 #define SIO_REG_TSI_LEVEL_SEL   0x28    /* TSI Level select */
0033 #define SIO_REG_MFUNCT1     0x29    /* Multi function select 1 */
0034 #define SIO_REG_MFUNCT2     0x2a    /* Multi function select 2 */
0035 #define SIO_REG_MFUNCT3     0x2b    /* Multi function select 3 */
0036 #define SIO_F81866_REG_GPIO1    0x2c    /* F81866 GPIO1 Enable Register */
0037 #define SIO_REG_ENABLE      0x30    /* Logical device enable */
0038 #define SIO_REG_ADDR        0x60    /* Logical device address (2 bytes) */
0039 
0040 #define SIO_FINTEK_ID       0x1934  /* Manufacturers ID */
0041 #define SIO_F71808_ID       0x0901  /* Chipset ID */
0042 #define SIO_F71858_ID       0x0507  /* Chipset ID */
0043 #define SIO_F71862_ID       0x0601  /* Chipset ID */
0044 #define SIO_F71868_ID       0x1106  /* Chipset ID */
0045 #define SIO_F71869_ID       0x0814  /* Chipset ID */
0046 #define SIO_F71869A_ID      0x1007  /* Chipset ID */
0047 #define SIO_F71882_ID       0x0541  /* Chipset ID */
0048 #define SIO_F71889_ID       0x0723  /* Chipset ID */
0049 #define SIO_F81803_ID       0x1210  /* Chipset ID */
0050 #define SIO_F81865_ID       0x0704  /* Chipset ID */
0051 #define SIO_F81866_ID       0x1010  /* Chipset ID */
0052 #define SIO_F81966_ID       0x1502  /* F81804 chipset ID, same for f81966 */
0053 
0054 #define F71808FG_REG_WDO_CONF       0xf0
0055 #define F71808FG_REG_WDT_CONF       0xf5
0056 #define F71808FG_REG_WD_TIME        0xf6
0057 
0058 #define F71808FG_FLAG_WDOUT_EN      7
0059 
0060 #define F71808FG_FLAG_WDTMOUT_STS   6
0061 #define F71808FG_FLAG_WD_EN     5
0062 #define F71808FG_FLAG_WD_PULSE      4
0063 #define F71808FG_FLAG_WD_UNIT       3
0064 
0065 #define F81865_REG_WDO_CONF     0xfa
0066 #define F81865_FLAG_WDOUT_EN        0
0067 
0068 /* Default values */
0069 #define WATCHDOG_TIMEOUT    60  /* 1 minute default timeout */
0070 #define WATCHDOG_MAX_TIMEOUT    (60 * 255)
0071 #define WATCHDOG_PULSE_WIDTH    125 /* 125 ms, default pulse width for
0072                        watchdog signal */
0073 #define WATCHDOG_F71862FG_PIN   63  /* default watchdog reset output
0074                        pin number 63 */
0075 
0076 static unsigned short force_id;
0077 module_param(force_id, ushort, 0);
0078 MODULE_PARM_DESC(force_id, "Override the detected device ID");
0079 
0080 static int timeout = WATCHDOG_TIMEOUT;  /* default timeout in seconds */
0081 module_param(timeout, int, 0);
0082 MODULE_PARM_DESC(timeout,
0083     "Watchdog timeout in seconds. 1<= timeout <="
0084             __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
0085             __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
0086 
0087 static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
0088 module_param(pulse_width, uint, 0);
0089 MODULE_PARM_DESC(pulse_width,
0090     "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
0091             " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
0092 
0093 static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
0094 module_param(f71862fg_pin, uint, 0);
0095 MODULE_PARM_DESC(f71862fg_pin,
0096     "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
0097             " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
0098 
0099 static bool nowayout = WATCHDOG_NOWAYOUT;
0100 module_param(nowayout, bool, 0444);
0101 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
0102 
0103 static unsigned int start_withtimeout;
0104 module_param(start_withtimeout, uint, 0);
0105 MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
0106     " given initial timeout. Zero (default) disables this feature.");
0107 
0108 enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
0109          f81803, f81865, f81866, f81966};
0110 
0111 static const char * const fintek_wdt_names[] = {
0112     "f71808fg",
0113     "f71858fg",
0114     "f71862fg",
0115     "f71868",
0116     "f71869",
0117     "f71882fg",
0118     "f71889fg",
0119     "f81803",
0120     "f81865",
0121     "f81866",
0122     "f81966"
0123 };
0124 
0125 /* Super-I/O Function prototypes */
0126 static inline int superio_inb(int base, int reg);
0127 static inline int superio_inw(int base, int reg);
0128 static inline void superio_outb(int base, int reg, u8 val);
0129 static inline void superio_set_bit(int base, int reg, int bit);
0130 static inline void superio_clear_bit(int base, int reg, int bit);
0131 static inline int superio_enter(int base);
0132 static inline void superio_select(int base, int ld);
0133 static inline void superio_exit(int base);
0134 
0135 struct fintek_wdt {
0136     struct watchdog_device wdd;
0137     unsigned short  sioaddr;
0138     enum chips  type;
0139     struct watchdog_info ident;
0140 
0141     u8      timer_val;  /* content for the wd_time register */
0142     char        minutes_mode;
0143     u8      pulse_val;  /* pulse width flag */
0144     char        pulse_mode; /* enable pulse output mode? */
0145 };
0146 
0147 struct fintek_wdt_pdata {
0148     enum chips  type;
0149 };
0150 
0151 /* Super I/O functions */
0152 static inline int superio_inb(int base, int reg)
0153 {
0154     outb(reg, base);
0155     return inb(base + 1);
0156 }
0157 
0158 static int superio_inw(int base, int reg)
0159 {
0160     int val;
0161     val  = superio_inb(base, reg) << 8;
0162     val |= superio_inb(base, reg + 1);
0163     return val;
0164 }
0165 
0166 static inline void superio_outb(int base, int reg, u8 val)
0167 {
0168     outb(reg, base);
0169     outb(val, base + 1);
0170 }
0171 
0172 static inline void superio_set_bit(int base, int reg, int bit)
0173 {
0174     unsigned long val = superio_inb(base, reg);
0175     __set_bit(bit, &val);
0176     superio_outb(base, reg, val);
0177 }
0178 
0179 static inline void superio_clear_bit(int base, int reg, int bit)
0180 {
0181     unsigned long val = superio_inb(base, reg);
0182     __clear_bit(bit, &val);
0183     superio_outb(base, reg, val);
0184 }
0185 
0186 static inline int superio_enter(int base)
0187 {
0188     /* Don't step on other drivers' I/O space by accident */
0189     if (!request_muxed_region(base, 2, DRVNAME)) {
0190         pr_err("I/O address 0x%04x already in use\n", (int)base);
0191         return -EBUSY;
0192     }
0193 
0194     /* according to the datasheet the key must be sent twice! */
0195     outb(SIO_UNLOCK_KEY, base);
0196     outb(SIO_UNLOCK_KEY, base);
0197 
0198     return 0;
0199 }
0200 
0201 static inline void superio_select(int base, int ld)
0202 {
0203     outb(SIO_REG_LDSEL, base);
0204     outb(ld, base + 1);
0205 }
0206 
0207 static inline void superio_exit(int base)
0208 {
0209     outb(SIO_LOCK_KEY, base);
0210     release_region(base, 2);
0211 }
0212 
0213 static int fintek_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
0214 {
0215     struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0216 
0217     if (timeout > 0xff) {
0218         wd->timer_val = DIV_ROUND_UP(timeout, 60);
0219         wd->minutes_mode = true;
0220         timeout = wd->timer_val * 60;
0221     } else {
0222         wd->timer_val = timeout;
0223         wd->minutes_mode = false;
0224     }
0225 
0226     wdd->timeout = timeout;
0227 
0228     return 0;
0229 }
0230 
0231 static int fintek_wdt_set_pulse_width(struct fintek_wdt *wd, unsigned int pw)
0232 {
0233     unsigned int t1 = 25, t2 = 125, t3 = 5000;
0234 
0235     if (wd->type == f71868) {
0236         t1 = 30;
0237         t2 = 150;
0238         t3 = 6000;
0239     }
0240 
0241     if        (pw <=  1) {
0242         wd->pulse_val = 0;
0243     } else if (pw <= t1) {
0244         wd->pulse_val = 1;
0245     } else if (pw <= t2) {
0246         wd->pulse_val = 2;
0247     } else if (pw <= t3) {
0248         wd->pulse_val = 3;
0249     } else {
0250         pr_err("pulse width out of range\n");
0251         return -EINVAL;
0252     }
0253 
0254     wd->pulse_mode = pw;
0255 
0256     return 0;
0257 }
0258 
0259 static int fintek_wdt_keepalive(struct watchdog_device *wdd)
0260 {
0261     struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0262     int err;
0263 
0264     err = superio_enter(wd->sioaddr);
0265     if (err)
0266         return err;
0267     superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0268 
0269     if (wd->minutes_mode)
0270         /* select minutes for timer units */
0271         superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0272                 F71808FG_FLAG_WD_UNIT);
0273     else
0274         /* select seconds for timer units */
0275         superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0276                 F71808FG_FLAG_WD_UNIT);
0277 
0278     /* Set timer value */
0279     superio_outb(wd->sioaddr, F71808FG_REG_WD_TIME,
0280                wd->timer_val);
0281 
0282     superio_exit(wd->sioaddr);
0283 
0284     return 0;
0285 }
0286 
0287 static int fintek_wdt_start(struct watchdog_device *wdd)
0288 {
0289     struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0290     int err;
0291     u8 tmp;
0292 
0293     /* Make sure we don't die as soon as the watchdog is enabled below */
0294     err = fintek_wdt_keepalive(wdd);
0295     if (err)
0296         return err;
0297 
0298     err = superio_enter(wd->sioaddr);
0299     if (err)
0300         return err;
0301     superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0302 
0303     /* Watchdog pin configuration */
0304     switch (wd->type) {
0305     case f71808fg:
0306         /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
0307         superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3);
0308         superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3);
0309         break;
0310 
0311     case f71862fg:
0312         if (f71862fg_pin == 63) {
0313             /* SPI must be disabled first to use this pin! */
0314             superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6);
0315             superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4);
0316         } else if (f71862fg_pin == 56) {
0317             superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
0318         }
0319         break;
0320 
0321     case f71868:
0322     case f71869:
0323         /* GPIO14 --> WDTRST# */
0324         superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4);
0325         break;
0326 
0327     case f71882fg:
0328         /* Set pin 56 to WDTRST# */
0329         superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
0330         break;
0331 
0332     case f71889fg:
0333         /* set pin 40 to WDTRST# */
0334         superio_outb(wd->sioaddr, SIO_REG_MFUNCT3,
0335             superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf);
0336         break;
0337 
0338     case f81803:
0339         /* Enable TSI Level register bank */
0340         superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3);
0341         /* Set pin 27 to WDTRST# */
0342         superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f &
0343             superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL));
0344         break;
0345 
0346     case f81865:
0347         /* Set pin 70 to WDTRST# */
0348         superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5);
0349         break;
0350 
0351     case f81866:
0352     case f81966:
0353         /*
0354          * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0.
0355          * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch:
0356          *     BIT5: 0 -> WDTRST#
0357          *           1 -> GPIO15
0358          */
0359         tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL);
0360         tmp &= ~(BIT(3) | BIT(0));
0361         tmp |= BIT(2);
0362         superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp);
0363 
0364         superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5);
0365         break;
0366 
0367     default:
0368         /*
0369          * 'default' label to shut up the compiler and catch
0370          * programmer errors
0371          */
0372         err = -ENODEV;
0373         goto exit_superio;
0374     }
0375 
0376     superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0377     superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0);
0378 
0379     if (wd->type == f81865 || wd->type == f81866 || wd->type == f81966)
0380         superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF,
0381                 F81865_FLAG_WDOUT_EN);
0382     else
0383         superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF,
0384                 F71808FG_FLAG_WDOUT_EN);
0385 
0386     superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0387             F71808FG_FLAG_WD_EN);
0388 
0389     if (wd->pulse_mode) {
0390         /* Select "pulse" output mode with given duration */
0391         u8 wdt_conf = superio_inb(wd->sioaddr,
0392                 F71808FG_REG_WDT_CONF);
0393 
0394         /* Set WD_PSWIDTH bits (1:0) */
0395         wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03);
0396         /* Set WD_PULSE to "pulse" mode */
0397         wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
0398 
0399         superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF,
0400                 wdt_conf);
0401     } else {
0402         /* Select "level" output mode */
0403         superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0404                 F71808FG_FLAG_WD_PULSE);
0405     }
0406 
0407 exit_superio:
0408     superio_exit(wd->sioaddr);
0409 
0410     return err;
0411 }
0412 
0413 static int fintek_wdt_stop(struct watchdog_device *wdd)
0414 {
0415     struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0416     int err;
0417 
0418     err = superio_enter(wd->sioaddr);
0419     if (err)
0420         return err;
0421     superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0422 
0423     superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0424             F71808FG_FLAG_WD_EN);
0425 
0426     superio_exit(wd->sioaddr);
0427 
0428     return 0;
0429 }
0430 
0431 static bool fintek_wdt_is_running(struct fintek_wdt *wd, u8 wdt_conf)
0432 {
0433     return (superio_inb(wd->sioaddr, SIO_REG_ENABLE) & BIT(0))
0434         && (wdt_conf & BIT(F71808FG_FLAG_WD_EN));
0435 }
0436 
0437 static const struct watchdog_ops fintek_wdt_ops = {
0438     .owner = THIS_MODULE,
0439     .start = fintek_wdt_start,
0440     .stop = fintek_wdt_stop,
0441     .ping = fintek_wdt_keepalive,
0442     .set_timeout = fintek_wdt_set_timeout,
0443 };
0444 
0445 static int fintek_wdt_probe(struct platform_device *pdev)
0446 {
0447     struct device *dev = &pdev->dev;
0448     struct fintek_wdt_pdata *pdata;
0449     struct watchdog_device *wdd;
0450     struct fintek_wdt *wd;
0451     int wdt_conf, err = 0;
0452     struct resource *res;
0453     int sioaddr;
0454 
0455     res = platform_get_resource(pdev, IORESOURCE_IO, 0);
0456     if (!res)
0457         return -ENXIO;
0458 
0459     sioaddr = res->start;
0460 
0461     wd = devm_kzalloc(dev, sizeof(*wd), GFP_KERNEL);
0462     if (!wd)
0463         return -ENOMEM;
0464 
0465     pdata = dev->platform_data;
0466 
0467     wd->type = pdata->type;
0468     wd->sioaddr = sioaddr;
0469     wd->ident.options = WDIOF_SETTIMEOUT
0470             | WDIOF_MAGICCLOSE
0471             | WDIOF_KEEPALIVEPING
0472             | WDIOF_CARDRESET;
0473 
0474     snprintf(wd->ident.identity,
0475         sizeof(wd->ident.identity), "%s watchdog",
0476         fintek_wdt_names[wd->type]);
0477 
0478     err = superio_enter(sioaddr);
0479     if (err)
0480         return err;
0481     superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0482 
0483     wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
0484 
0485     /*
0486      * We don't want WDTMOUT_STS to stick around till regular reboot.
0487      * Write 1 to the bit to clear it to zero.
0488      */
0489     superio_outb(sioaddr, F71808FG_REG_WDT_CONF,
0490              wdt_conf | BIT(F71808FG_FLAG_WDTMOUT_STS));
0491 
0492     wdd = &wd->wdd;
0493 
0494     if (fintek_wdt_is_running(wd, wdt_conf))
0495         set_bit(WDOG_HW_RUNNING, &wdd->status);
0496 
0497     superio_exit(sioaddr);
0498 
0499     wdd->parent     = dev;
0500     wdd->info               = &wd->ident;
0501     wdd->ops                = &fintek_wdt_ops;
0502     wdd->min_timeout        = 1;
0503     wdd->max_timeout        = WATCHDOG_MAX_TIMEOUT;
0504 
0505     watchdog_set_drvdata(wdd, wd);
0506     watchdog_set_nowayout(wdd, nowayout);
0507     watchdog_stop_on_unregister(wdd);
0508     watchdog_stop_on_reboot(wdd);
0509     watchdog_init_timeout(wdd, start_withtimeout ?: timeout, NULL);
0510 
0511     if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS))
0512         wdd->bootstatus = WDIOF_CARDRESET;
0513 
0514     /*
0515      * WATCHDOG_HANDLE_BOOT_ENABLED can result in keepalive being directly
0516      * called without a set_timeout before, so it needs to be done here
0517      * unconditionally.
0518      */
0519     fintek_wdt_set_timeout(wdd, wdd->timeout);
0520     fintek_wdt_set_pulse_width(wd, pulse_width);
0521 
0522     if (start_withtimeout) {
0523         err = fintek_wdt_start(wdd);
0524         if (err) {
0525             dev_err(dev, "cannot start watchdog timer\n");
0526             return err;
0527         }
0528 
0529         set_bit(WDOG_HW_RUNNING, &wdd->status);
0530         dev_info(dev, "watchdog started with initial timeout of %u sec\n",
0531              start_withtimeout);
0532     }
0533 
0534     return devm_watchdog_register_device(dev, wdd);
0535 }
0536 
0537 static int __init fintek_wdt_find(int sioaddr)
0538 {
0539     enum chips type;
0540     u16 devid;
0541     int err = superio_enter(sioaddr);
0542     if (err)
0543         return err;
0544 
0545     devid = superio_inw(sioaddr, SIO_REG_MANID);
0546     if (devid != SIO_FINTEK_ID) {
0547         pr_debug("Not a Fintek device\n");
0548         err = -ENODEV;
0549         goto exit;
0550     }
0551 
0552     devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
0553     switch (devid) {
0554     case SIO_F71808_ID:
0555         type = f71808fg;
0556         break;
0557     case SIO_F71862_ID:
0558         type = f71862fg;
0559         break;
0560     case SIO_F71868_ID:
0561         type = f71868;
0562         break;
0563     case SIO_F71869_ID:
0564     case SIO_F71869A_ID:
0565         type = f71869;
0566         break;
0567     case SIO_F71882_ID:
0568         type = f71882fg;
0569         break;
0570     case SIO_F71889_ID:
0571         type = f71889fg;
0572         break;
0573     case SIO_F71858_ID:
0574         /* Confirmed (by datasheet) not to have a watchdog. */
0575         err = -ENODEV;
0576         goto exit;
0577     case SIO_F81803_ID:
0578         type = f81803;
0579         break;
0580     case SIO_F81865_ID:
0581         type = f81865;
0582         break;
0583     case SIO_F81866_ID:
0584         type = f81866;
0585         break;
0586     case SIO_F81966_ID:
0587         type = f81966;
0588         break;
0589     default:
0590         pr_info("Unrecognized Fintek device: %04x\n",
0591             (unsigned int)devid);
0592         err = -ENODEV;
0593         goto exit;
0594     }
0595 
0596     pr_info("Found %s watchdog chip, revision %d\n",
0597         fintek_wdt_names[type],
0598         (int)superio_inb(sioaddr, SIO_REG_DEVREV));
0599 
0600 exit:
0601     superio_exit(sioaddr);
0602     return err ? err : type;
0603 }
0604 
0605 static struct platform_driver fintek_wdt_driver = {
0606     .probe          = fintek_wdt_probe,
0607     .driver         = {
0608         .name   = DRVNAME,
0609     },
0610 };
0611 
0612 static struct platform_device *fintek_wdt_pdev;
0613 
0614 static int __init fintek_wdt_init(void)
0615 {
0616     static const unsigned short addrs[] = { 0x2e, 0x4e };
0617     struct fintek_wdt_pdata pdata;
0618     struct resource wdt_res = {};
0619     int ret;
0620     int i;
0621 
0622     if (f71862fg_pin != 63 && f71862fg_pin != 56) {
0623         pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
0624         return -EINVAL;
0625     }
0626 
0627     for (i = 0; i < ARRAY_SIZE(addrs); i++) {
0628         ret = fintek_wdt_find(addrs[i]);
0629         if (ret >= 0)
0630             break;
0631     }
0632     if (i == ARRAY_SIZE(addrs))
0633         return ret;
0634 
0635     pdata.type = ret;
0636 
0637     ret = platform_driver_register(&fintek_wdt_driver);
0638     if (ret)
0639         return ret;
0640 
0641     wdt_res.name = "superio port";
0642     wdt_res.flags = IORESOURCE_IO;
0643     wdt_res.start = addrs[i];
0644     wdt_res.end   = addrs[i] + 1;
0645 
0646     fintek_wdt_pdev = platform_device_register_resndata(NULL, DRVNAME, -1,
0647                                 &wdt_res, 1,
0648                                 &pdata, sizeof(pdata));
0649     if (IS_ERR(fintek_wdt_pdev)) {
0650         platform_driver_unregister(&fintek_wdt_driver);
0651         return PTR_ERR(fintek_wdt_pdev);
0652     }
0653 
0654     return 0;
0655 }
0656 
0657 static void __exit fintek_wdt_exit(void)
0658 {
0659     platform_device_unregister(fintek_wdt_pdev);
0660     platform_driver_unregister(&fintek_wdt_driver);
0661 }
0662 
0663 MODULE_DESCRIPTION("F71808E Watchdog Driver");
0664 MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>");
0665 MODULE_LICENSE("GPL");
0666 
0667 module_init(fintek_wdt_init);
0668 module_exit(fintek_wdt_exit);