diff options
author | H Hartley Sweeten <hartleys@visionengravers.com> | 2012-03-14 13:31:50 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2012-03-27 14:15:02 -0400 |
commit | e12a679ddee4eb5ab2f99f7cf129355461e142c0 (patch) | |
tree | 0e665dc6d5391f126d745f0e77ea238be1a08a3a /drivers/watchdog | |
parent | fb35a5ad5b4b2c3806b52b0159f4d5a0ad205c0f (diff) |
watchdog: Convert ep93xx driver to watchdog core
Convert the ep93xx_wdt driver to the watchdog framework API.
Also, use the dev_<fmt> functions instead of pr_<fmt> for logging.
Signed-off-by: H Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ryan Mallon <rmallon@gmail.com>
Cc: Mika Westerberg <mika.westerberg@iki.fi>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/Kconfig | 1 | ||||
-rw-r--r-- | drivers/watchdog/ep93xx_wdt.c | 203 |
2 files changed, 55 insertions, 149 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index af7444188f5c..7a8895396ecd 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -219,6 +219,7 @@ config MPCORE_WATCHDOG | |||
219 | config EP93XX_WATCHDOG | 219 | config EP93XX_WATCHDOG |
220 | tristate "EP93xx Watchdog" | 220 | tristate "EP93xx Watchdog" |
221 | depends on ARCH_EP93XX | 221 | depends on ARCH_EP93XX |
222 | select WATCHDOG_CORE | ||
222 | help | 223 | help |
223 | Say Y here if to include support for the watchdog timer | 224 | Say Y here if to include support for the watchdog timer |
224 | embedded in the Cirrus Logic EP93xx family of devices. | 225 | embedded in the Cirrus Logic EP93xx family of devices. |
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index bd01bde27c4a..414ce8fdecc9 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c | |||
@@ -8,6 +8,9 @@ | |||
8 | * Authors: Ray Lehtiniemi <rayl@mail.com>, | 8 | * Authors: Ray Lehtiniemi <rayl@mail.com>, |
9 | * Alessandro Zummo <a.zummo@towertech.it> | 9 | * Alessandro Zummo <a.zummo@towertech.it> |
10 | * | 10 | * |
11 | * Copyright (c) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> | ||
12 | * Convert to a platform device and use the watchdog framework API | ||
13 | * | ||
11 | * This file is licensed under the terms of the GNU General Public | 14 | * This file is licensed under the terms of the GNU General Public |
12 | * License version 2. This program is licensed "as is" without any | 15 | * License version 2. This program is licensed "as is" without any |
13 | * warranty of any kind, whether express or implied. | 16 | * warranty of any kind, whether express or implied. |
@@ -23,33 +26,31 @@ | |||
23 | * - Add a few missing ioctls | 26 | * - Add a few missing ioctls |
24 | */ | 27 | */ |
25 | 28 | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
27 | |||
28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
29 | #include <linux/module.h> | 30 | #include <linux/module.h> |
30 | #include <linux/fs.h> | ||
31 | #include <linux/miscdevice.h> | 31 | #include <linux/miscdevice.h> |
32 | #include <linux/watchdog.h> | 32 | #include <linux/watchdog.h> |
33 | #include <linux/timer.h> | 33 | #include <linux/timer.h> |
34 | #include <linux/uaccess.h> | ||
35 | #include <linux/io.h> | 34 | #include <linux/io.h> |
36 | 35 | ||
37 | #define WDT_VERSION "0.3" | 36 | #define WDT_VERSION "0.4" |
38 | 37 | ||
39 | /* default timeout (secs) */ | 38 | /* default timeout (secs) */ |
40 | #define WDT_TIMEOUT 30 | 39 | #define WDT_TIMEOUT 30 |
41 | 40 | ||
42 | static bool nowayout = WATCHDOG_NOWAYOUT; | 41 | static bool nowayout = WATCHDOG_NOWAYOUT; |
42 | module_param(nowayout, bool, 0); | ||
43 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | ||
44 | |||
43 | static int timeout = WDT_TIMEOUT; | 45 | static int timeout = WDT_TIMEOUT; |
46 | module_param(timeout, int, 0); | ||
47 | MODULE_PARM_DESC(timeout, | ||
48 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
49 | __MODULE_STRING(WDT_TIMEOUT) ")"); | ||
44 | 50 | ||
45 | static void __iomem *mmio_base; | 51 | static void __iomem *mmio_base; |
46 | static struct timer_list timer; | 52 | static struct timer_list timer; |
47 | static unsigned long next_heartbeat; | 53 | static unsigned long next_heartbeat; |
48 | static unsigned long wdt_status; | ||
49 | static unsigned long boot_status; | ||
50 | |||
51 | #define WDT_IN_USE 0 | ||
52 | #define WDT_OK_TO_CLOSE 1 | ||
53 | 54 | ||
54 | #define EP93XX_WATCHDOG 0x00 | 55 | #define EP93XX_WATCHDOG 0x00 |
55 | #define EP93XX_WDSTATUS 0x04 | 56 | #define EP93XX_WDSTATUS 0x04 |
@@ -57,155 +58,60 @@ static unsigned long boot_status; | |||
57 | /* reset the wdt every ~200ms */ | 58 | /* reset the wdt every ~200ms */ |
58 | #define WDT_INTERVAL (HZ/5) | 59 | #define WDT_INTERVAL (HZ/5) |
59 | 60 | ||
60 | static void wdt_enable(void) | 61 | static void ep93xx_wdt_timer_ping(unsigned long data) |
61 | { | ||
62 | writel(0xaaaa, mmio_base + EP93XX_WATCHDOG); | ||
63 | } | ||
64 | |||
65 | static void wdt_disable(void) | ||
66 | { | 62 | { |
67 | writel(0xaa55, mmio_base + EP93XX_WATCHDOG); | 63 | if (time_before(jiffies, next_heartbeat)) |
68 | } | 64 | writel(0x5555, mmio_base + EP93XX_WATCHDOG); |
69 | 65 | ||
70 | static inline void wdt_ping(void) | 66 | /* Re-set the timer interval */ |
71 | { | 67 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
72 | writel(0x5555, mmio_base + EP93XX_WATCHDOG); | ||
73 | } | 68 | } |
74 | 69 | ||
75 | static void wdt_startup(void) | 70 | static int ep93xx_wdt_start(struct watchdog_device *wdd) |
76 | { | 71 | { |
77 | next_heartbeat = jiffies + (timeout * HZ); | 72 | next_heartbeat = jiffies + (timeout * HZ); |
78 | 73 | ||
79 | wdt_enable(); | 74 | writel(0xaaaa, mmio_base + EP93XX_WATCHDOG); |
80 | mod_timer(&timer, jiffies + WDT_INTERVAL); | 75 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
76 | |||
77 | return 0; | ||
81 | } | 78 | } |
82 | 79 | ||
83 | static void wdt_shutdown(void) | 80 | static int ep93xx_wdt_stop(struct watchdog_device *wdd) |
84 | { | 81 | { |
85 | del_timer_sync(&timer); | 82 | del_timer_sync(&timer); |
86 | wdt_disable(); | 83 | writel(0xaa55, mmio_base + EP93XX_WATCHDOG); |
84 | |||
85 | return 0; | ||
87 | } | 86 | } |
88 | 87 | ||
89 | static void wdt_keepalive(void) | 88 | static int ep93xx_wdt_keepalive(struct watchdog_device *wdd) |
90 | { | 89 | { |
91 | /* user land ping */ | 90 | /* user land ping */ |
92 | next_heartbeat = jiffies + (timeout * HZ); | 91 | next_heartbeat = jiffies + (timeout * HZ); |
93 | } | ||
94 | |||
95 | static int ep93xx_wdt_open(struct inode *inode, struct file *file) | ||
96 | { | ||
97 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | ||
98 | return -EBUSY; | ||
99 | |||
100 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
101 | |||
102 | wdt_startup(); | ||
103 | |||
104 | return nonseekable_open(inode, file); | ||
105 | } | ||
106 | |||
107 | static ssize_t | ||
108 | ep93xx_wdt_write(struct file *file, const char __user *data, size_t len, | ||
109 | loff_t *ppos) | ||
110 | { | ||
111 | if (len) { | ||
112 | if (!nowayout) { | ||
113 | size_t i; | ||
114 | |||
115 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
116 | |||
117 | for (i = 0; i != len; i++) { | ||
118 | char c; | ||
119 | 92 | ||
120 | if (get_user(c, data + i)) | 93 | return 0; |
121 | return -EFAULT; | ||
122 | |||
123 | if (c == 'V') | ||
124 | set_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
125 | else | ||
126 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
127 | } | ||
128 | } | ||
129 | wdt_keepalive(); | ||
130 | } | ||
131 | |||
132 | return len; | ||
133 | } | 94 | } |
134 | 95 | ||
135 | static const struct watchdog_info ident = { | 96 | static const struct watchdog_info ep93xx_wdt_ident = { |
136 | .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE, | 97 | .options = WDIOF_CARDRESET | |
137 | .identity = "EP93xx Watchdog", | 98 | WDIOF_MAGICCLOSE | |
99 | WDIOF_KEEPALIVEPING, | ||
100 | .identity = "EP93xx Watchdog", | ||
138 | }; | 101 | }; |
139 | 102 | ||
140 | static long ep93xx_wdt_ioctl(struct file *file, | 103 | static struct watchdog_ops ep93xx_wdt_ops = { |
141 | unsigned int cmd, unsigned long arg) | ||
142 | { | ||
143 | int ret = -ENOTTY; | ||
144 | |||
145 | switch (cmd) { | ||
146 | case WDIOC_GETSUPPORT: | ||
147 | ret = copy_to_user((struct watchdog_info __user *)arg, &ident, | ||
148 | sizeof(ident)) ? -EFAULT : 0; | ||
149 | break; | ||
150 | |||
151 | case WDIOC_GETSTATUS: | ||
152 | ret = put_user(0, (int __user *)arg); | ||
153 | break; | ||
154 | |||
155 | case WDIOC_GETBOOTSTATUS: | ||
156 | ret = put_user(boot_status, (int __user *)arg); | ||
157 | break; | ||
158 | |||
159 | case WDIOC_KEEPALIVE: | ||
160 | wdt_keepalive(); | ||
161 | ret = 0; | ||
162 | break; | ||
163 | |||
164 | case WDIOC_GETTIMEOUT: | ||
165 | /* actually, it is 0.250 seconds.... */ | ||
166 | ret = put_user(1, (int __user *)arg); | ||
167 | break; | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int ep93xx_wdt_release(struct inode *inode, struct file *file) | ||
173 | { | ||
174 | if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) | ||
175 | wdt_shutdown(); | ||
176 | else | ||
177 | pr_crit("Device closed unexpectedly - timer will not stop\n"); | ||
178 | |||
179 | clear_bit(WDT_IN_USE, &wdt_status); | ||
180 | clear_bit(WDT_OK_TO_CLOSE, &wdt_status); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static const struct file_operations ep93xx_wdt_fops = { | ||
186 | .owner = THIS_MODULE, | 104 | .owner = THIS_MODULE, |
187 | .write = ep93xx_wdt_write, | 105 | .start = ep93xx_wdt_start, |
188 | .unlocked_ioctl = ep93xx_wdt_ioctl, | 106 | .stop = ep93xx_wdt_stop, |
189 | .open = ep93xx_wdt_open, | 107 | .ping = ep93xx_wdt_keepalive, |
190 | .release = ep93xx_wdt_release, | ||
191 | .llseek = no_llseek, | ||
192 | }; | 108 | }; |
193 | 109 | ||
194 | static struct miscdevice ep93xx_wdt_miscdev = { | 110 | static struct watchdog_device ep93xx_wdt_wdd = { |
195 | .minor = WATCHDOG_MINOR, | 111 | .info = &ep93xx_wdt_ident, |
196 | .name = "watchdog", | 112 | .ops = &ep93xx_wdt_ops, |
197 | .fops = &ep93xx_wdt_fops, | ||
198 | }; | 113 | }; |
199 | 114 | ||
200 | static void ep93xx_timer_ping(unsigned long data) | ||
201 | { | ||
202 | if (time_before(jiffies, next_heartbeat)) | ||
203 | wdt_ping(); | ||
204 | |||
205 | /* Re-set the timer interval */ | ||
206 | mod_timer(&timer, jiffies + WDT_INTERVAL); | ||
207 | } | ||
208 | |||
209 | static int __devinit ep93xx_wdt_probe(struct platform_device *pdev) | 115 | static int __devinit ep93xx_wdt_probe(struct platform_device *pdev) |
210 | { | 116 | { |
211 | struct resource *res; | 117 | struct resource *res; |
@@ -226,26 +132,32 @@ static int __devinit ep93xx_wdt_probe(struct platform_device *pdev) | |||
226 | 132 | ||
227 | if (timeout < 1 || timeout > 3600) { | 133 | if (timeout < 1 || timeout > 3600) { |
228 | timeout = WDT_TIMEOUT; | 134 | timeout = WDT_TIMEOUT; |
229 | pr_info("timeout value must be 1<=x<=3600, using %d\n", | 135 | dev_warn(&pdev->dev, |
136 | "timeout value must be 1<=x<=3600, using %d\n", | ||
230 | timeout); | 137 | timeout); |
231 | } | 138 | } |
232 | 139 | ||
233 | val = readl(mmio_base + EP93XX_WATCHDOG); | 140 | val = readl(mmio_base + EP93XX_WATCHDOG); |
234 | boot_status = val & 0x01 ? 1 : 0; | 141 | ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; |
142 | |||
143 | watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); | ||
235 | 144 | ||
236 | setup_timer(&timer, ep93xx_timer_ping, 1); | 145 | setup_timer(&timer, ep93xx_wdt_timer_ping, 1); |
237 | 146 | ||
238 | err = misc_register(&ep93xx_wdt_miscdev); | 147 | err = watchdog_register_device(&ep93xx_wdt_wdd); |
148 | if (err) | ||
149 | return err; | ||
239 | 150 | ||
240 | pr_info("EP93XX watchdog, driver version " WDT_VERSION "%s\n", | 151 | dev_info(&pdev->dev, |
152 | "EP93XX watchdog, driver version " WDT_VERSION "%s\n", | ||
241 | (val & 0x08) ? " (nCS1 disable detected)" : ""); | 153 | (val & 0x08) ? " (nCS1 disable detected)" : ""); |
242 | return err; | 154 | |
155 | return 0; | ||
243 | } | 156 | } |
244 | 157 | ||
245 | static int __devexit ep93xx_wdt_remove(struct platform_device *pdev) | 158 | static int __devexit ep93xx_wdt_remove(struct platform_device *pdev) |
246 | { | 159 | { |
247 | wdt_shutdown(); | 160 | watchdog_unregister_device(&ep93xx_wdt_wdd); |
248 | misc_deregister(&ep93xx_wdt_miscdev); | ||
249 | return 0; | 161 | return 0; |
250 | } | 162 | } |
251 | 163 | ||
@@ -260,16 +172,9 @@ static struct platform_driver ep93xx_wdt_driver = { | |||
260 | 172 | ||
261 | module_platform_driver(ep93xx_wdt_driver); | 173 | module_platform_driver(ep93xx_wdt_driver); |
262 | 174 | ||
263 | module_param(nowayout, bool, 0); | ||
264 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | ||
265 | |||
266 | module_param(timeout, int, 0); | ||
267 | MODULE_PARM_DESC(timeout, | ||
268 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
269 | __MODULE_STRING(WDT_TIMEOUT) ")"); | ||
270 | |||
271 | MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," | 175 | MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>," |
272 | "Alessandro Zummo <a.zummo@towertech.it>"); | 176 | "Alessandro Zummo <a.zummo@towertech.it>," |
177 | "H Hartley Sweeten <hsweeten@visionengravers.com>"); | ||
273 | MODULE_DESCRIPTION("EP93xx Watchdog"); | 178 | MODULE_DESCRIPTION("EP93xx Watchdog"); |
274 | MODULE_LICENSE("GPL"); | 179 | MODULE_LICENSE("GPL"); |
275 | MODULE_VERSION(WDT_VERSION); | 180 | MODULE_VERSION(WDT_VERSION); |