root/drivers/watchdog/retu_wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. retu_wdt_ping_enable
  2. retu_wdt_ping_disable
  3. retu_wdt_ping_work
  4. retu_wdt_start
  5. retu_wdt_stop
  6. retu_wdt_ping
  7. retu_wdt_set_timeout
  8. retu_wdt_probe
  9. retu_wdt_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Retu watchdog driver
   4  *
   5  * Copyright (C) 2004, 2005 Nokia Corporation
   6  *
   7  * Based on code written by Amit Kucheria and Michael Buesch.
   8  * Rewritten by Aaro Koskinen.
   9  */
  10 
  11 #include <linux/slab.h>
  12 #include <linux/errno.h>
  13 #include <linux/device.h>
  14 #include <linux/kernel.h>
  15 #include <linux/module.h>
  16 #include <linux/mfd/retu.h>
  17 #include <linux/watchdog.h>
  18 #include <linux/platform_device.h>
  19 
  20 /* Watchdog timer values in seconds */
  21 #define RETU_WDT_MAX_TIMER      63
  22 
  23 struct retu_wdt_dev {
  24         struct retu_dev         *rdev;
  25         struct device           *dev;
  26         struct delayed_work     ping_work;
  27 };
  28 
  29 /*
  30  * Since Retu watchdog cannot be disabled in hardware, we must kick it
  31  * with a timer until userspace watchdog software takes over. If
  32  * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
  33  */
  34 static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev)
  35 {
  36         retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
  37         schedule_delayed_work(&wdev->ping_work,
  38                         round_jiffies_relative(RETU_WDT_MAX_TIMER * HZ / 2));
  39 }
  40 
  41 static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev)
  42 {
  43         retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
  44         cancel_delayed_work_sync(&wdev->ping_work);
  45 }
  46 
  47 static void retu_wdt_ping_work(struct work_struct *work)
  48 {
  49         struct retu_wdt_dev *wdev = container_of(to_delayed_work(work),
  50                                                 struct retu_wdt_dev, ping_work);
  51         retu_wdt_ping_enable(wdev);
  52 }
  53 
  54 static int retu_wdt_start(struct watchdog_device *wdog)
  55 {
  56         struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
  57 
  58         retu_wdt_ping_disable(wdev);
  59 
  60         return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
  61 }
  62 
  63 static int retu_wdt_stop(struct watchdog_device *wdog)
  64 {
  65         struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
  66 
  67         retu_wdt_ping_enable(wdev);
  68 
  69         return 0;
  70 }
  71 
  72 static int retu_wdt_ping(struct watchdog_device *wdog)
  73 {
  74         struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
  75 
  76         return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
  77 }
  78 
  79 static int retu_wdt_set_timeout(struct watchdog_device *wdog,
  80                                 unsigned int timeout)
  81 {
  82         struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
  83 
  84         wdog->timeout = timeout;
  85         return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
  86 }
  87 
  88 static const struct watchdog_info retu_wdt_info = {
  89         .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
  90         .identity = "Retu watchdog",
  91 };
  92 
  93 static const struct watchdog_ops retu_wdt_ops = {
  94         .owner          = THIS_MODULE,
  95         .start          = retu_wdt_start,
  96         .stop           = retu_wdt_stop,
  97         .ping           = retu_wdt_ping,
  98         .set_timeout    = retu_wdt_set_timeout,
  99 };
 100 
 101 static int retu_wdt_probe(struct platform_device *pdev)
 102 {
 103         struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
 104         bool nowayout = WATCHDOG_NOWAYOUT;
 105         struct watchdog_device *retu_wdt;
 106         struct retu_wdt_dev *wdev;
 107         int ret;
 108 
 109         retu_wdt = devm_kzalloc(&pdev->dev, sizeof(*retu_wdt), GFP_KERNEL);
 110         if (!retu_wdt)
 111                 return -ENOMEM;
 112 
 113         wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
 114         if (!wdev)
 115                 return -ENOMEM;
 116 
 117         retu_wdt->info          = &retu_wdt_info;
 118         retu_wdt->ops           = &retu_wdt_ops;
 119         retu_wdt->timeout       = RETU_WDT_MAX_TIMER;
 120         retu_wdt->min_timeout   = 0;
 121         retu_wdt->max_timeout   = RETU_WDT_MAX_TIMER;
 122         retu_wdt->parent        = &pdev->dev;
 123 
 124         watchdog_set_drvdata(retu_wdt, wdev);
 125         watchdog_set_nowayout(retu_wdt, nowayout);
 126 
 127         wdev->rdev              = rdev;
 128         wdev->dev               = &pdev->dev;
 129 
 130         INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work);
 131 
 132         ret = watchdog_register_device(retu_wdt);
 133         if (ret < 0)
 134                 return ret;
 135 
 136         if (nowayout)
 137                 retu_wdt_ping(retu_wdt);
 138         else
 139                 retu_wdt_ping_enable(wdev);
 140 
 141         platform_set_drvdata(pdev, retu_wdt);
 142 
 143         return 0;
 144 }
 145 
 146 static int retu_wdt_remove(struct platform_device *pdev)
 147 {
 148         struct watchdog_device *wdog = platform_get_drvdata(pdev);
 149         struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 150 
 151         watchdog_unregister_device(wdog);
 152         cancel_delayed_work_sync(&wdev->ping_work);
 153 
 154         return 0;
 155 }
 156 
 157 static struct platform_driver retu_wdt_driver = {
 158         .probe          = retu_wdt_probe,
 159         .remove         = retu_wdt_remove,
 160         .driver         = {
 161                 .name   = "retu-wdt",
 162         },
 163 };
 164 module_platform_driver(retu_wdt_driver);
 165 
 166 MODULE_ALIAS("platform:retu-wdt");
 167 MODULE_DESCRIPTION("Retu watchdog");
 168 MODULE_AUTHOR("Amit Kucheria");
 169 MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
 170 MODULE_LICENSE("GPL");

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