1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Advantech Embedded Controller Watchdog Driver 4 * 5 * This driver supports Advantech products with ITE based Embedded Controller. 6 * It does not support Advantech products with other ECs or without EC. 7 * 8 * Copyright (C) 2022 Advantech Europe B.V. 9 */ 10 11 #include <linux/delay.h> 12 #include <linux/io.h> 13 #include <linux/isa.h> 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/moduleparam.h> 17 #include <linux/watchdog.h> 18 19 #define DRIVER_NAME "advantech_ec_wdt" 20 21 /* EC IO region */ 22 #define EC_BASE_ADDR 0x299 23 #define EC_ADDR_EXTENT 2 24 25 /* EC minimum IO access delay in ms */ 26 #define EC_MIN_DELAY 10 27 28 /* EC interface definitions */ 29 #define EC_ADDR_CMD (EC_BASE_ADDR + 1) 30 #define EC_ADDR_DATA EC_BASE_ADDR 31 #define EC_CMD_EC_PROBE 0x30 32 #define EC_CMD_COMM 0x89 33 #define EC_CMD_WDT_START 0x28 34 #define EC_CMD_WDT_STOP 0x29 35 #define EC_CMD_WDT_RESET 0x2A 36 #define EC_DAT_EN_DLY_H 0x58 37 #define EC_DAT_EN_DLY_L 0x59 38 #define EC_DAT_RST_DLY_H 0x5E 39 #define EC_DAT_RST_DLY_L 0x5F 40 #define EC_MAGIC 0x95 41 42 /* module parameters */ 43 #define MIN_TIME 1 44 #define MAX_TIME 6000 /* 100 minutes */ 45 #define DEFAULT_TIME 60 46 47 static unsigned int timeout; 48 static ktime_t ec_timestamp; 49 50 module_param(timeout, uint, 0); 51 MODULE_PARM_DESC(timeout, 52 "Default Watchdog timer setting (" __MODULE_STRING(DEFAULT_TIME) "s). The range is from " __MODULE_STRING(MIN_TIME) " to " __MODULE_STRING(MAX_TIME) "."); 53 54 static void adv_ec_wdt_timing_gate(void) 55 { 56 ktime_t time_cur, time_delta; 57 58 /* ensure minimum delay between IO accesses*/ 59 time_cur = ktime_get(); 60 time_delta = ktime_to_ms(ktime_sub(time_cur, ec_timestamp)); 61 if (time_delta < EC_MIN_DELAY) { 62 time_delta = EC_MIN_DELAY - time_delta; 63 usleep_range(time_delta * 1000, (time_delta + 1) * 1000); 64 } 65 ec_timestamp = ktime_get(); 66 } 67 68 static void adv_ec_wdt_outb(unsigned char value, unsigned short port) 69 { 70 adv_ec_wdt_timing_gate(); 71 outb(value, port); 72 } 73 74 static unsigned char adv_ec_wdt_inb(unsigned short port) 75 { 76 adv_ec_wdt_timing_gate(); 77 return inb(port); 78 } 79 80 static int adv_ec_wdt_ping(struct watchdog_device *wdd) 81 { 82 adv_ec_wdt_outb(EC_CMD_WDT_RESET, EC_ADDR_CMD); 83 return 0; 84 } 85 86 static int adv_ec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) 87 { 88 unsigned int val; 89 90 /* scale time to EC 100 ms base */ 91 val = t * 10; 92 93 /* reset enable delay, just in case it was set by BIOS etc. */ 94 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); 95 adv_ec_wdt_outb(EC_DAT_EN_DLY_H, EC_ADDR_DATA); 96 adv_ec_wdt_outb(0, EC_ADDR_DATA); 97 98 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); 99 adv_ec_wdt_outb(EC_DAT_EN_DLY_L, EC_ADDR_DATA); 100 adv_ec_wdt_outb(0, EC_ADDR_DATA); 101 102 /* set reset delay */ 103 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); 104 adv_ec_wdt_outb(EC_DAT_RST_DLY_H, EC_ADDR_DATA); 105 adv_ec_wdt_outb(val >> 8, EC_ADDR_DATA); 106 107 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD); 108 adv_ec_wdt_outb(EC_DAT_RST_DLY_L, EC_ADDR_DATA); 109 adv_ec_wdt_outb(val & 0xFF, EC_ADDR_DATA); 110 111 wdd->timeout = t; 112 return 0; 113 } 114 115 static int adv_ec_wdt_start(struct watchdog_device *wdd) 116 { 117 adv_ec_wdt_set_timeout(wdd, wdd->timeout); 118 adv_ec_wdt_outb(EC_CMD_WDT_START, EC_ADDR_CMD); 119 120 return 0; 121 } 122 123 static int adv_ec_wdt_stop(struct watchdog_device *wdd) 124 { 125 adv_ec_wdt_outb(EC_CMD_WDT_STOP, EC_ADDR_CMD); 126 127 return 0; 128 } 129 130 static const struct watchdog_info adv_ec_wdt_info = { 131 .identity = DRIVER_NAME, 132 .options = WDIOF_SETTIMEOUT | 133 WDIOF_MAGICCLOSE | 134 WDIOF_KEEPALIVEPING, 135 }; 136 137 static const struct watchdog_ops adv_ec_wdt_ops = { 138 .owner = THIS_MODULE, 139 .start = adv_ec_wdt_start, 140 .stop = adv_ec_wdt_stop, 141 .ping = adv_ec_wdt_ping, 142 .set_timeout = adv_ec_wdt_set_timeout, 143 }; 144 145 static struct watchdog_device adv_ec_wdt_dev = { 146 .info = &adv_ec_wdt_info, 147 .ops = &adv_ec_wdt_ops, 148 .min_timeout = MIN_TIME, 149 .max_timeout = MAX_TIME, 150 .timeout = DEFAULT_TIME, 151 }; 152 153 static int adv_ec_wdt_probe(struct device *dev, unsigned int id) 154 { 155 if (!devm_request_region(dev, EC_BASE_ADDR, EC_ADDR_EXTENT, dev_name(dev))) { 156 dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", 157 EC_BASE_ADDR, EC_BASE_ADDR + EC_ADDR_EXTENT); 158 return -EBUSY; 159 } 160 161 watchdog_init_timeout(&adv_ec_wdt_dev, timeout, dev); 162 watchdog_stop_on_reboot(&adv_ec_wdt_dev); 163 watchdog_stop_on_unregister(&adv_ec_wdt_dev); 164 165 return devm_watchdog_register_device(dev, &adv_ec_wdt_dev); 166 } 167 168 static struct isa_driver adv_ec_wdt_driver = { 169 .probe = adv_ec_wdt_probe, 170 .driver = { 171 .name = DRIVER_NAME, 172 }, 173 }; 174 175 static int __init adv_ec_wdt_init(void) 176 { 177 unsigned int val; 178 179 /* quick probe for EC */ 180 if (!request_region(EC_BASE_ADDR, EC_ADDR_EXTENT, DRIVER_NAME)) 181 return -EBUSY; 182 183 adv_ec_wdt_outb(EC_CMD_EC_PROBE, EC_ADDR_CMD); 184 val = adv_ec_wdt_inb(EC_ADDR_DATA); 185 release_region(EC_BASE_ADDR, EC_ADDR_EXTENT); 186 187 if (val != EC_MAGIC) 188 return -ENODEV; 189 190 return isa_register_driver(&adv_ec_wdt_driver, 1); 191 } 192 193 static void __exit adv_ec_wdt_exit(void) 194 { 195 isa_unregister_driver(&adv_ec_wdt_driver); 196 } 197 198 module_init(adv_ec_wdt_init); 199 module_exit(adv_ec_wdt_exit); 200 201 MODULE_AUTHOR("Thomas Kastner <thomas.kastner@advantech.com>"); 202 MODULE_DESCRIPTION("Advantech Embedded Controller Watchdog Device Driver"); 203 MODULE_LICENSE("GPL"); 204 MODULE_VERSION("20221019"); 205 MODULE_ALIAS("isa:" DRIVER_NAME); 206