^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2016 National Instruments Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define NIWD_CONTROL 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define NIWD_COUNTER2 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define NIWD_COUNTER1 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define NIWD_COUNTER0 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define NIWD_SEED2 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define NIWD_SEED1 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define NIWD_SEED0 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define NIWD_IO_SIZE 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define NIWD_CONTROL_MODE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define NIWD_CONTROL_PROC_RESET 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define NIWD_CONTROL_PET 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define NIWD_CONTROL_RUNNING 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define NIWD_CONTROL_CAPTURECOUNTER 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define NIWD_CONTROL_RESET 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define NIWD_CONTROL_ALARM 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define NIWD_PERIOD_NS 30720
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define NIWD_MIN_TIMEOUT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define NIWD_MAX_TIMEOUT 515
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define NIWD_DEFAULT_TIMEOUT 60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define NIWD_NAME "ni903x_wdt"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) struct ni903x_wdt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u16 io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) struct watchdog_device wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static unsigned int timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) module_param(timeout, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) MODULE_PARM_DESC(timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) "Watchdog timeout in seconds. (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) __MODULE_STRING(NIWD_DEFAULT_TIMEOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) module_param(nowayout, int, S_IRUGO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) MODULE_PARM_DESC(nowayout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static void ni903x_start(struct ni903x_wdt *wdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u8 control = inb(wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) outb(control | NIWD_CONTROL_RESET, wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) outb(control | NIWD_CONTROL_PET, wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static int ni903x_wdd_set_timeout(struct watchdog_device *wdd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u32 counter = timeout * (1000000000 / NIWD_PERIOD_NS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) outb(((0x00FF0000 & counter) >> 16), wdt->io_base + NIWD_SEED2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) outb(((0x0000FF00 & counter) >> 8), wdt->io_base + NIWD_SEED1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) outb((0x000000FF & counter), wdt->io_base + NIWD_SEED0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) wdd->timeout = timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static unsigned int ni903x_wdd_get_timeleft(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) u8 control, counter0, counter1, counter2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) u32 counter;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) control = inb(wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) control |= NIWD_CONTROL_CAPTURECOUNTER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) outb(control, wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) counter2 = inb(wdt->io_base + NIWD_COUNTER2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) counter1 = inb(wdt->io_base + NIWD_COUNTER1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) counter0 = inb(wdt->io_base + NIWD_COUNTER0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) counter = (counter2 << 16) | (counter1 << 8) | counter0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return counter / (1000000000 / NIWD_PERIOD_NS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static int ni903x_wdd_ping(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) u8 control;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) control = inb(wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) outb(control | NIWD_CONTROL_PET, wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) static int ni903x_wdd_start(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) outb(NIWD_CONTROL_RESET | NIWD_CONTROL_PROC_RESET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) ni903x_wdd_set_timeout(wdd, wdd->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) ni903x_start(wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int ni903x_wdd_stop(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) outb(NIWD_CONTROL_RESET, wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static acpi_status ni903x_resources(struct acpi_resource *res, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct ni903x_wdt *wdt = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u16 io_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) switch (res->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) case ACPI_RESOURCE_TYPE_IO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (wdt->io_base != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) dev_err(wdt->dev, "too many IO resources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) wdt->io_base = res->data.io.minimum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) io_size = res->data.io.address_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (io_size < NIWD_IO_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) dev_err(wdt->dev, "memory region too small\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (!devm_request_region(wdt->dev, wdt->io_base, io_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) NIWD_NAME)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) dev_err(wdt->dev, "failed to get memory region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return AE_ERROR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) case ACPI_RESOURCE_TYPE_END_TAG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) /* Ignore unsupported resources, e.g. IRQ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static const struct watchdog_info ni903x_wdd_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .identity = "NI Watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static const struct watchdog_ops ni903x_wdd_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .start = ni903x_wdd_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .stop = ni903x_wdd_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .ping = ni903x_wdd_ping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .set_timeout = ni903x_wdd_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .get_timeleft = ni903x_wdd_get_timeleft,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int ni903x_acpi_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct device *dev = &device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct watchdog_device *wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct ni903x_wdt *wdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (!wdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) device->driver_data = wdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) wdt->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) ni903x_resources, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (ACPI_FAILURE(status) || wdt->io_base == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) dev_err(dev, "failed to get resources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) wdd = &wdt->wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) wdd->info = &ni903x_wdd_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) wdd->ops = &ni903x_wdd_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) wdd->min_timeout = NIWD_MIN_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) wdd->max_timeout = NIWD_MAX_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) wdd->timeout = NIWD_DEFAULT_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) wdd->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) watchdog_set_drvdata(wdd, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) watchdog_set_nowayout(wdd, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) watchdog_init_timeout(wdd, timeout, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ret = watchdog_register_device(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) /* Switch from boot mode to user mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) outb(NIWD_CONTROL_RESET | NIWD_CONTROL_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) wdt->io_base + NIWD_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) dev_dbg(dev, "io_base=0x%04X, timeout=%d, nowayout=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) wdt->io_base, timeout, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static int ni903x_acpi_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct ni903x_wdt *wdt = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ni903x_wdd_stop(&wdt->wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) watchdog_unregister_device(&wdt->wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static const struct acpi_device_id ni903x_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {"NIC775C", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) MODULE_DEVICE_TABLE(acpi, ni903x_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) static struct acpi_driver ni903x_acpi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .name = NIWD_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .ids = ni903x_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .add = ni903x_acpi_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .remove = ni903x_acpi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) module_acpi_driver(ni903x_acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) MODULE_DESCRIPTION("NI 903x Watchdog");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) MODULE_AUTHOR("Jeff Westfahl <jeff.westfahl@ni.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) MODULE_AUTHOR("Kyle Roeschley <kyle.roeschley@ni.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) MODULE_LICENSE("GPL");