Version:  2.0.40 2.2.26 2.4.37 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16

Linux/drivers/watchdog/retu_wdt.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us