1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt 4 * 5 * (C) Copyright 2013 - 2014 Xilinx, Inc. 6 * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/err.h> 11 #include <linux/module.h> 12 #include <linux/types.h> 13 #include <linux/kernel.h> 14 #include <linux/ioport.h> 15 #include <linux/watchdog.h> 16 #include <linux/io.h> 17 #include <linux/of.h> 18 #include <linux/of_device.h> 19 #include <linux/of_address.h> 20 21 /* Register offsets for the Wdt device */ 22 #define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */ 23 #define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */ 24 #define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */ 25 26 /* Control/Status Register Masks */ 27 #define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */ 28 #define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */ 29 #define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */ 30 31 /* Control/Status Register 0/1 bits */ 32 #define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */ 33 34 /* SelfTest constants */ 35 #define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000 36 #define XWT_TIMER_FAILED 0xFFFFFFFF 37 38 #define WATCHDOG_NAME "Xilinx Watchdog" 39 40 struct xwdt_device { 41 void __iomem *base; 42 u32 wdt_interval; 43 spinlock_t spinlock; 44 struct watchdog_device xilinx_wdt_wdd; 45 struct clk *clk; 46 }; 47 48 static int xilinx_wdt_start(struct watchdog_device *wdd) 49 { 50 int ret; 51 u32 control_status_reg; 52 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 53 54 ret = clk_enable(xdev->clk); 55 if (ret) { 56 dev_err(wdd->parent, "Failed to enable clock\n"); 57 return ret; 58 } 59 60 spin_lock(&xdev->spinlock); 61 62 /* Clean previous status and enable the watchdog timer */ 63 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 64 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 65 66 iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), 67 xdev->base + XWT_TWCSR0_OFFSET); 68 69 iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET); 70 71 spin_unlock(&xdev->spinlock); 72 73 return 0; 74 } 75 76 static int xilinx_wdt_stop(struct watchdog_device *wdd) 77 { 78 u32 control_status_reg; 79 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 80 81 spin_lock(&xdev->spinlock); 82 83 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 84 85 iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), 86 xdev->base + XWT_TWCSR0_OFFSET); 87 88 iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET); 89 90 spin_unlock(&xdev->spinlock); 91 92 clk_disable(xdev->clk); 93 94 pr_info("Stopped!\n"); 95 96 return 0; 97 } 98 99 static int xilinx_wdt_keepalive(struct watchdog_device *wdd) 100 { 101 u32 control_status_reg; 102 struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 103 104 spin_lock(&xdev->spinlock); 105 106 control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 107 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 108 iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET); 109 110 spin_unlock(&xdev->spinlock); 111 112 return 0; 113 } 114 115 static const struct watchdog_info xilinx_wdt_ident = { 116 .options = WDIOF_MAGICCLOSE | 117 WDIOF_KEEPALIVEPING, 118 .firmware_version = 1, 119 .identity = WATCHDOG_NAME, 120 }; 121 122 static const struct watchdog_ops xilinx_wdt_ops = { 123 .owner = THIS_MODULE, 124 .start = xilinx_wdt_start, 125 .stop = xilinx_wdt_stop, 126 .ping = xilinx_wdt_keepalive, 127 }; 128 129 static u32 xwdt_selftest(struct xwdt_device *xdev) 130 { 131 int i; 132 u32 timer_value1; 133 u32 timer_value2; 134 135 spin_lock(&xdev->spinlock); 136 137 timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET); 138 timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 139 140 for (i = 0; 141 ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && 142 (timer_value2 == timer_value1)); i++) { 143 timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 144 } 145 146 spin_unlock(&xdev->spinlock); 147 148 if (timer_value2 != timer_value1) 149 return ~XWT_TIMER_FAILED; 150 else 151 return XWT_TIMER_FAILED; 152 } 153 154 static void xwdt_clk_disable_unprepare(void *data) 155 { 156 clk_disable_unprepare(data); 157 } 158 159 static int xwdt_probe(struct platform_device *pdev) 160 { 161 struct device *dev = &pdev->dev; 162 int rc; 163 u32 pfreq = 0, enable_once = 0; 164 struct xwdt_device *xdev; 165 struct watchdog_device *xilinx_wdt_wdd; 166 167 xdev = devm_kzalloc(dev, sizeof(*xdev), GFP_KERNEL); 168 if (!xdev) 169 return -ENOMEM; 170 171 xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd; 172 xilinx_wdt_wdd->info = &xilinx_wdt_ident; 173 xilinx_wdt_wdd->ops = &xilinx_wdt_ops; 174 xilinx_wdt_wdd->parent = dev; 175 176 xdev->base = devm_platform_ioremap_resource(pdev, 0); 177 if (IS_ERR(xdev->base)) 178 return PTR_ERR(xdev->base); 179 180 rc = of_property_read_u32(dev->of_node, "xlnx,wdt-interval", 181 &xdev->wdt_interval); 182 if (rc) 183 dev_warn(dev, "Parameter \"xlnx,wdt-interval\" not found\n"); 184 185 rc = of_property_read_u32(dev->of_node, "xlnx,wdt-enable-once", 186 &enable_once); 187 if (rc) 188 dev_warn(dev, 189 "Parameter \"xlnx,wdt-enable-once\" not found\n"); 190 191 watchdog_set_nowayout(xilinx_wdt_wdd, enable_once); 192 193 xdev->clk = devm_clk_get(dev, NULL); 194 if (IS_ERR(xdev->clk)) { 195 if (PTR_ERR(xdev->clk) != -ENOENT) 196 return PTR_ERR(xdev->clk); 197 198 /* 199 * Clock framework support is optional, continue on 200 * anyways if we don't find a matching clock. 201 */ 202 xdev->clk = NULL; 203 204 rc = of_property_read_u32(dev->of_node, "clock-frequency", 205 &pfreq); 206 if (rc) 207 dev_warn(dev, 208 "The watchdog clock freq cannot be obtained\n"); 209 } else { 210 pfreq = clk_get_rate(xdev->clk); 211 } 212 213 /* 214 * Twice of the 2^wdt_interval / freq because the first wdt overflow is 215 * ignored (interrupt), reset is only generated at second wdt overflow 216 */ 217 if (pfreq && xdev->wdt_interval) 218 xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) / 219 pfreq); 220 221 spin_lock_init(&xdev->spinlock); 222 watchdog_set_drvdata(xilinx_wdt_wdd, xdev); 223 224 rc = clk_prepare_enable(xdev->clk); 225 if (rc) { 226 dev_err(dev, "unable to enable clock\n"); 227 return rc; 228 } 229 rc = devm_add_action_or_reset(dev, xwdt_clk_disable_unprepare, 230 xdev->clk); 231 if (rc) 232 return rc; 233 234 rc = xwdt_selftest(xdev); 235 if (rc == XWT_TIMER_FAILED) { 236 dev_err(dev, "SelfTest routine error\n"); 237 return rc; 238 } 239 240 rc = devm_watchdog_register_device(dev, xilinx_wdt_wdd); 241 if (rc) 242 return rc; 243 244 clk_disable(xdev->clk); 245 246 dev_info(dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", 247 xdev->base, xilinx_wdt_wdd->timeout); 248 249 platform_set_drvdata(pdev, xdev); 250 251 return 0; 252 } 253 254 /** 255 * xwdt_suspend - Suspend the device. 256 * 257 * @dev: handle to the device structure. 258 * Return: 0 always. 259 */ 260 static int __maybe_unused xwdt_suspend(struct device *dev) 261 { 262 struct xwdt_device *xdev = dev_get_drvdata(dev); 263 264 if (watchdog_active(&xdev->xilinx_wdt_wdd)) 265 xilinx_wdt_stop(&xdev->xilinx_wdt_wdd); 266 267 return 0; 268 } 269 270 /** 271 * xwdt_resume - Resume the device. 272 * 273 * @dev: handle to the device structure. 274 * Return: 0 on success, errno otherwise. 275 */ 276 static int __maybe_unused xwdt_resume(struct device *dev) 277 { 278 struct xwdt_device *xdev = dev_get_drvdata(dev); 279 int ret = 0; 280 281 if (watchdog_active(&xdev->xilinx_wdt_wdd)) 282 ret = xilinx_wdt_start(&xdev->xilinx_wdt_wdd); 283 284 return ret; 285 } 286 287 static SIMPLE_DEV_PM_OPS(xwdt_pm_ops, xwdt_suspend, xwdt_resume); 288 289 /* Match table for of_platform binding */ 290 static const struct of_device_id xwdt_of_match[] = { 291 { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 292 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 293 {}, 294 }; 295 MODULE_DEVICE_TABLE(of, xwdt_of_match); 296 297 static struct platform_driver xwdt_driver = { 298 .probe = xwdt_probe, 299 .driver = { 300 .name = WATCHDOG_NAME, 301 .of_match_table = xwdt_of_match, 302 .pm = &xwdt_pm_ops, 303 }, 304 }; 305 306 module_platform_driver(xwdt_driver); 307 308 MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); 309 MODULE_DESCRIPTION("Xilinx Watchdog driver"); 310 MODULE_LICENSE("GPL"); 311