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