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