root/drivers/watchdog/of_xilinx_wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xilinx_wdt_start
  2. xilinx_wdt_stop
  3. xilinx_wdt_keepalive
  4. xwdt_selftest
  5. xwdt_clk_disable_unprepare
  6. xwdt_probe
  7. xwdt_suspend
  8. xwdt_resume

   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");

/* [<][>][^][v][top][bottom][index][help] */