Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");