0001
0002
0003
0004
0005
0006 #include <linux/acpi.h>
0007 #include <linux/device.h>
0008 #include <linux/interrupt.h>
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/watchdog.h>
0012
0013 #define NIWD_CONTROL 0x01
0014 #define NIWD_COUNTER2 0x02
0015 #define NIWD_COUNTER1 0x03
0016 #define NIWD_COUNTER0 0x04
0017 #define NIWD_SEED2 0x05
0018 #define NIWD_SEED1 0x06
0019 #define NIWD_SEED0 0x07
0020
0021 #define NIWD_IO_SIZE 0x08
0022
0023 #define NIWD_CONTROL_MODE 0x80
0024 #define NIWD_CONTROL_PROC_RESET 0x20
0025 #define NIWD_CONTROL_PET 0x10
0026 #define NIWD_CONTROL_RUNNING 0x08
0027 #define NIWD_CONTROL_CAPTURECOUNTER 0x04
0028 #define NIWD_CONTROL_RESET 0x02
0029 #define NIWD_CONTROL_ALARM 0x01
0030
0031 #define NIWD_PERIOD_NS 30720
0032 #define NIWD_MIN_TIMEOUT 1
0033 #define NIWD_MAX_TIMEOUT 515
0034 #define NIWD_DEFAULT_TIMEOUT 60
0035
0036 #define NIWD_NAME "ni903x_wdt"
0037
0038 struct ni903x_wdt {
0039 struct device *dev;
0040 u16 io_base;
0041 struct watchdog_device wdd;
0042 };
0043
0044 static unsigned int timeout;
0045 module_param(timeout, uint, 0);
0046 MODULE_PARM_DESC(timeout,
0047 "Watchdog timeout in seconds. (default="
0048 __MODULE_STRING(NIWD_DEFAULT_TIMEOUT) ")");
0049
0050 static int nowayout = WATCHDOG_NOWAYOUT;
0051 module_param(nowayout, int, S_IRUGO);
0052 MODULE_PARM_DESC(nowayout,
0053 "Watchdog cannot be stopped once started (default="
0054 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0055
0056 static void ni903x_start(struct ni903x_wdt *wdt)
0057 {
0058 u8 control = inb(wdt->io_base + NIWD_CONTROL);
0059
0060 outb(control | NIWD_CONTROL_RESET, wdt->io_base + NIWD_CONTROL);
0061 outb(control | NIWD_CONTROL_PET, wdt->io_base + NIWD_CONTROL);
0062 }
0063
0064 static int ni903x_wdd_set_timeout(struct watchdog_device *wdd,
0065 unsigned int timeout)
0066 {
0067 struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
0068 u32 counter = timeout * (1000000000 / NIWD_PERIOD_NS);
0069
0070 outb(((0x00FF0000 & counter) >> 16), wdt->io_base + NIWD_SEED2);
0071 outb(((0x0000FF00 & counter) >> 8), wdt->io_base + NIWD_SEED1);
0072 outb((0x000000FF & counter), wdt->io_base + NIWD_SEED0);
0073
0074 wdd->timeout = timeout;
0075
0076 return 0;
0077 }
0078
0079 static unsigned int ni903x_wdd_get_timeleft(struct watchdog_device *wdd)
0080 {
0081 struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
0082 u8 control, counter0, counter1, counter2;
0083 u32 counter;
0084
0085 control = inb(wdt->io_base + NIWD_CONTROL);
0086 control |= NIWD_CONTROL_CAPTURECOUNTER;
0087 outb(control, wdt->io_base + NIWD_CONTROL);
0088
0089 counter2 = inb(wdt->io_base + NIWD_COUNTER2);
0090 counter1 = inb(wdt->io_base + NIWD_COUNTER1);
0091 counter0 = inb(wdt->io_base + NIWD_COUNTER0);
0092
0093 counter = (counter2 << 16) | (counter1 << 8) | counter0;
0094
0095 return counter / (1000000000 / NIWD_PERIOD_NS);
0096 }
0097
0098 static int ni903x_wdd_ping(struct watchdog_device *wdd)
0099 {
0100 struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
0101 u8 control;
0102
0103 control = inb(wdt->io_base + NIWD_CONTROL);
0104 outb(control | NIWD_CONTROL_PET, wdt->io_base + NIWD_CONTROL);
0105
0106 return 0;
0107 }
0108
0109 static int ni903x_wdd_start(struct watchdog_device *wdd)
0110 {
0111 struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
0112
0113 outb(NIWD_CONTROL_RESET | NIWD_CONTROL_PROC_RESET,
0114 wdt->io_base + NIWD_CONTROL);
0115
0116 ni903x_wdd_set_timeout(wdd, wdd->timeout);
0117 ni903x_start(wdt);
0118
0119 return 0;
0120 }
0121
0122 static int ni903x_wdd_stop(struct watchdog_device *wdd)
0123 {
0124 struct ni903x_wdt *wdt = watchdog_get_drvdata(wdd);
0125
0126 outb(NIWD_CONTROL_RESET, wdt->io_base + NIWD_CONTROL);
0127
0128 return 0;
0129 }
0130
0131 static acpi_status ni903x_resources(struct acpi_resource *res, void *data)
0132 {
0133 struct ni903x_wdt *wdt = data;
0134 u16 io_size;
0135
0136 switch (res->type) {
0137 case ACPI_RESOURCE_TYPE_IO:
0138 if (wdt->io_base != 0) {
0139 dev_err(wdt->dev, "too many IO resources\n");
0140 return AE_ERROR;
0141 }
0142
0143 wdt->io_base = res->data.io.minimum;
0144 io_size = res->data.io.address_length;
0145
0146 if (io_size < NIWD_IO_SIZE) {
0147 dev_err(wdt->dev, "memory region too small\n");
0148 return AE_ERROR;
0149 }
0150
0151 if (!devm_request_region(wdt->dev, wdt->io_base, io_size,
0152 NIWD_NAME)) {
0153 dev_err(wdt->dev, "failed to get memory region\n");
0154 return AE_ERROR;
0155 }
0156
0157 return AE_OK;
0158
0159 case ACPI_RESOURCE_TYPE_END_TAG:
0160 default:
0161
0162 return AE_OK;
0163 }
0164 }
0165
0166 static const struct watchdog_info ni903x_wdd_info = {
0167 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0168 .identity = "NI Watchdog",
0169 };
0170
0171 static const struct watchdog_ops ni903x_wdd_ops = {
0172 .owner = THIS_MODULE,
0173 .start = ni903x_wdd_start,
0174 .stop = ni903x_wdd_stop,
0175 .ping = ni903x_wdd_ping,
0176 .set_timeout = ni903x_wdd_set_timeout,
0177 .get_timeleft = ni903x_wdd_get_timeleft,
0178 };
0179
0180 static int ni903x_acpi_add(struct acpi_device *device)
0181 {
0182 struct device *dev = &device->dev;
0183 struct watchdog_device *wdd;
0184 struct ni903x_wdt *wdt;
0185 acpi_status status;
0186 int ret;
0187
0188 wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
0189 if (!wdt)
0190 return -ENOMEM;
0191
0192 device->driver_data = wdt;
0193 wdt->dev = dev;
0194
0195 status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
0196 ni903x_resources, wdt);
0197 if (ACPI_FAILURE(status) || wdt->io_base == 0) {
0198 dev_err(dev, "failed to get resources\n");
0199 return -ENODEV;
0200 }
0201
0202 wdd = &wdt->wdd;
0203 wdd->info = &ni903x_wdd_info;
0204 wdd->ops = &ni903x_wdd_ops;
0205 wdd->min_timeout = NIWD_MIN_TIMEOUT;
0206 wdd->max_timeout = NIWD_MAX_TIMEOUT;
0207 wdd->timeout = NIWD_DEFAULT_TIMEOUT;
0208 wdd->parent = dev;
0209 watchdog_set_drvdata(wdd, wdt);
0210 watchdog_set_nowayout(wdd, nowayout);
0211 watchdog_init_timeout(wdd, timeout, dev);
0212
0213 ret = watchdog_register_device(wdd);
0214 if (ret)
0215 return ret;
0216
0217
0218 outb(NIWD_CONTROL_RESET | NIWD_CONTROL_MODE,
0219 wdt->io_base + NIWD_CONTROL);
0220
0221 dev_dbg(dev, "io_base=0x%04X, timeout=%d, nowayout=%d\n",
0222 wdt->io_base, timeout, nowayout);
0223
0224 return 0;
0225 }
0226
0227 static int ni903x_acpi_remove(struct acpi_device *device)
0228 {
0229 struct ni903x_wdt *wdt = acpi_driver_data(device);
0230
0231 ni903x_wdd_stop(&wdt->wdd);
0232 watchdog_unregister_device(&wdt->wdd);
0233
0234 return 0;
0235 }
0236
0237 static const struct acpi_device_id ni903x_device_ids[] = {
0238 {"NIC775C", 0},
0239 {"", 0},
0240 };
0241 MODULE_DEVICE_TABLE(acpi, ni903x_device_ids);
0242
0243 static struct acpi_driver ni903x_acpi_driver = {
0244 .name = NIWD_NAME,
0245 .ids = ni903x_device_ids,
0246 .ops = {
0247 .add = ni903x_acpi_add,
0248 .remove = ni903x_acpi_remove,
0249 },
0250 };
0251
0252 module_acpi_driver(ni903x_acpi_driver);
0253
0254 MODULE_DESCRIPTION("NI 903x Watchdog");
0255 MODULE_AUTHOR("Jeff Westfahl <jeff.westfahl@ni.com>");
0256 MODULE_AUTHOR("Kyle Roeschley <kyle.roeschley@ni.com>");
0257 MODULE_LICENSE("GPL");