aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAxel Lin <axel.lin@gmail.com>2012-03-25 23:14:29 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-07-23 06:51:09 -0400
commit0dd6e4847ed8a42e81df6ffaa71129245a6d9d72 (patch)
treed9c3c0756b5f16f28aeaab70a4dc35ec3e57ef3e
parent6b761b2902c56b468370e0ee1691c37e0dae042a (diff)
watchdog: orion_wdt: Convert driver to watchdog core
Convert orion_wdt driver to use watchdog framework API. Signed-off-by: Axel Lin <axel.lin@gmail.com> Tested-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/orion_wdt.c203
2 files changed, 51 insertions, 153 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 277ecbc36bc..46e258c533c 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -279,6 +279,7 @@ config DAVINCI_WATCHDOG
279config ORION_WATCHDOG 279config ORION_WATCHDOG
280 tristate "Orion watchdog" 280 tristate "Orion watchdog"
281 depends on ARCH_ORION5X || ARCH_KIRKWOOD 281 depends on ARCH_ORION5X || ARCH_KIRKWOOD
282 select WATCHDOG_CORE
282 help 283 help
283 Say Y here if to include support for the watchdog timer 284 Say Y here if to include support for the watchdog timer
284 in the Marvell Orion5x and Kirkwood ARM SoCs. 285 in the Marvell Orion5x and Kirkwood ARM SoCs.
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 0f5736949c6..a73bea4aa1b 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -16,22 +16,21 @@
16#include <linux/moduleparam.h> 16#include <linux/moduleparam.h>
17#include <linux/types.h> 17#include <linux/types.h>
18#include <linux/kernel.h> 18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/miscdevice.h> 19#include <linux/miscdevice.h>
21#include <linux/platform_device.h> 20#include <linux/platform_device.h>
22#include <linux/watchdog.h> 21#include <linux/watchdog.h>
23#include <linux/init.h> 22#include <linux/init.h>
24#include <linux/uaccess.h>
25#include <linux/io.h> 23#include <linux/io.h>
26#include <linux/spinlock.h> 24#include <linux/spinlock.h>
27#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/err.h>
28#include <mach/bridge-regs.h> 27#include <mach/bridge-regs.h>
29 28
30/* 29/*
31 * Watchdog timer block registers. 30 * Watchdog timer block registers.
32 */ 31 */
33#define TIMER_CTRL 0x0000 32#define TIMER_CTRL 0x0000
34#define WDT_EN 0x0010 33#define WDT_EN 0x0010
35#define WDT_VAL 0x0024 34#define WDT_VAL 0x0024
36 35
37#define WDT_MAX_CYCLE_COUNT 0xffffffff 36#define WDT_MAX_CYCLE_COUNT 0xffffffff
@@ -44,27 +43,27 @@ static unsigned int wdt_max_duration; /* (seconds) */
44static struct clk *clk; 43static struct clk *clk;
45static unsigned int wdt_tclk; 44static unsigned int wdt_tclk;
46static void __iomem *wdt_reg; 45static void __iomem *wdt_reg;
47static unsigned long wdt_status;
48static DEFINE_SPINLOCK(wdt_lock); 46static DEFINE_SPINLOCK(wdt_lock);
49 47
50static void orion_wdt_ping(void) 48static int orion_wdt_ping(struct watchdog_device *wdt_dev)
51{ 49{
52 spin_lock(&wdt_lock); 50 spin_lock(&wdt_lock);
53 51
54 /* Reload watchdog duration */ 52 /* Reload watchdog duration */
55 writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL); 53 writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
56 54
57 spin_unlock(&wdt_lock); 55 spin_unlock(&wdt_lock);
56 return 0;
58} 57}
59 58
60static void orion_wdt_enable(void) 59static int orion_wdt_start(struct watchdog_device *wdt_dev)
61{ 60{
62 u32 reg; 61 u32 reg;
63 62
64 spin_lock(&wdt_lock); 63 spin_lock(&wdt_lock);
65 64
66 /* Set watchdog duration */ 65 /* Set watchdog duration */
67 writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL); 66 writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
68 67
69 /* Clear watchdog timer interrupt */ 68 /* Clear watchdog timer interrupt */
70 reg = readl(BRIDGE_CAUSE); 69 reg = readl(BRIDGE_CAUSE);
@@ -82,9 +81,10 @@ static void orion_wdt_enable(void)
82 writel(reg, RSTOUTn_MASK); 81 writel(reg, RSTOUTn_MASK);
83 82
84 spin_unlock(&wdt_lock); 83 spin_unlock(&wdt_lock);
84 return 0;
85} 85}
86 86
87static void orion_wdt_disable(void) 87static int orion_wdt_stop(struct watchdog_device *wdt_dev)
88{ 88{
89 u32 reg; 89 u32 reg;
90 90
@@ -101,139 +101,44 @@ static void orion_wdt_disable(void)
101 writel(reg, wdt_reg + TIMER_CTRL); 101 writel(reg, wdt_reg + TIMER_CTRL);
102 102
103 spin_unlock(&wdt_lock); 103 spin_unlock(&wdt_lock);
104 return 0;
104} 105}
105 106
106static int orion_wdt_get_timeleft(int *time_left) 107static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
107{ 108{
109 unsigned int time_left;
110
108 spin_lock(&wdt_lock); 111 spin_lock(&wdt_lock);
109 *time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk; 112 time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
110 spin_unlock(&wdt_lock); 113 spin_unlock(&wdt_lock);
111 return 0;
112}
113 114
114static int orion_wdt_open(struct inode *inode, struct file *file) 115 return time_left;
115{
116 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
117 return -EBUSY;
118 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
119 orion_wdt_enable();
120 return nonseekable_open(inode, file);
121} 116}
122 117
123static ssize_t orion_wdt_write(struct file *file, const char *data, 118static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
124 size_t len, loff_t *ppos) 119 unsigned int timeout)
125{ 120{
126 if (len) { 121 wdt_dev->timeout = timeout;
127 if (!nowayout) {
128 size_t i;
129
130 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
131 for (i = 0; i != len; i++) {
132 char c;
133
134 if (get_user(c, data + i))
135 return -EFAULT;
136 if (c == 'V')
137 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
138 }
139 }
140 orion_wdt_ping();
141 }
142 return len;
143}
144
145static int orion_wdt_settimeout(int new_time)
146{
147 if ((new_time <= 0) || (new_time > wdt_max_duration))
148 return -EINVAL;
149
150 /* Set new watchdog time to be used when
151 * orion_wdt_enable() or orion_wdt_ping() is called. */
152 heartbeat = new_time;
153 return 0; 122 return 0;
154} 123}
155 124
156static const struct watchdog_info ident = { 125static const struct watchdog_info orion_wdt_info = {
157 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | 126 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
158 WDIOF_KEEPALIVEPING, 127 .identity = "Orion Watchdog",
159 .identity = "Orion Watchdog",
160}; 128};
161 129
162static long orion_wdt_ioctl(struct file *file, unsigned int cmd, 130static const struct watchdog_ops orion_wdt_ops = {
163 unsigned long arg) 131 .owner = THIS_MODULE,
164{ 132 .start = orion_wdt_start,
165 int ret = -ENOTTY; 133 .stop = orion_wdt_stop,
166 int time; 134 .ping = orion_wdt_ping,
167 135 .set_timeout = orion_wdt_set_timeout,
168 switch (cmd) { 136 .get_timeleft = orion_wdt_get_timeleft,
169 case WDIOC_GETSUPPORT:
170 ret = copy_to_user((struct watchdog_info *)arg, &ident,
171 sizeof(ident)) ? -EFAULT : 0;
172 break;
173
174 case WDIOC_GETSTATUS:
175 case WDIOC_GETBOOTSTATUS:
176 ret = put_user(0, (int *)arg);
177 break;
178
179 case WDIOC_KEEPALIVE:
180 orion_wdt_ping();
181 ret = 0;
182 break;
183
184 case WDIOC_SETTIMEOUT:
185 ret = get_user(time, (int *)arg);
186 if (ret)
187 break;
188
189 if (orion_wdt_settimeout(time)) {
190 ret = -EINVAL;
191 break;
192 }
193 orion_wdt_ping();
194 /* Fall through */
195
196 case WDIOC_GETTIMEOUT:
197 ret = put_user(heartbeat, (int *)arg);
198 break;
199
200 case WDIOC_GETTIMELEFT:
201 if (orion_wdt_get_timeleft(&time)) {
202 ret = -EINVAL;
203 break;
204 }
205 ret = put_user(time, (int *)arg);
206 break;
207 }
208 return ret;
209}
210
211static int orion_wdt_release(struct inode *inode, struct file *file)
212{
213 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
214 orion_wdt_disable();
215 else
216 pr_crit("Device closed unexpectedly - timer will not stop\n");
217 clear_bit(WDT_IN_USE, &wdt_status);
218 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
219
220 return 0;
221}
222
223
224static const struct file_operations orion_wdt_fops = {
225 .owner = THIS_MODULE,
226 .llseek = no_llseek,
227 .write = orion_wdt_write,
228 .unlocked_ioctl = orion_wdt_ioctl,
229 .open = orion_wdt_open,
230 .release = orion_wdt_release,
231}; 137};
232 138
233static struct miscdevice orion_wdt_miscdev = { 139static struct watchdog_device orion_wdt = {
234 .minor = WATCHDOG_MINOR, 140 .info = &orion_wdt_info,
235 .name = "watchdog", 141 .ops = &orion_wdt_ops,
236 .fops = &orion_wdt_fops,
237}; 142};
238 143
239static int __devinit orion_wdt_probe(struct platform_device *pdev) 144static int __devinit orion_wdt_probe(struct platform_device *pdev)
@@ -241,29 +146,34 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
241 struct resource *res; 146 struct resource *res;
242 int ret; 147 int ret;
243 148
244 clk = clk_get(&pdev->dev, NULL); 149 clk = devm_clk_get(&pdev->dev, NULL);
245 if (IS_ERR(clk)) { 150 if (IS_ERR(clk)) {
246 printk(KERN_ERR "Orion Watchdog missing clock\n"); 151 dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
247 return -ENODEV; 152 return -ENODEV;
248 } 153 }
249 clk_prepare_enable(clk); 154 clk_prepare_enable(clk);
250 wdt_tclk = clk_get_rate(clk); 155 wdt_tclk = clk_get_rate(clk);
251 156
252 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 157 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
253 158 wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
254 wdt_reg = ioremap(res->start, resource_size(res)); 159 if (!wdt_reg)
255 160 return -ENOMEM;
256 if (orion_wdt_miscdev.parent)
257 return -EBUSY;
258 orion_wdt_miscdev.parent = &pdev->dev;
259 161
260 wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; 162 wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
261 if (orion_wdt_settimeout(heartbeat)) 163
164 if ((heartbeat < 1) || (heartbeat > wdt_max_duration))
262 heartbeat = wdt_max_duration; 165 heartbeat = wdt_max_duration;
263 166
264 ret = misc_register(&orion_wdt_miscdev); 167 orion_wdt.timeout = heartbeat;
265 if (ret) 168 orion_wdt.min_timeout = 1;
169 orion_wdt.max_timeout = wdt_max_duration;
170
171 watchdog_set_nowayout(&orion_wdt, nowayout);
172 ret = watchdog_register_device(&orion_wdt);
173 if (ret) {
174 clk_disable_unprepare(clk);
266 return ret; 175 return ret;
176 }
267 177
268 pr_info("Initial timeout %d sec%s\n", 178 pr_info("Initial timeout %d sec%s\n",
269 heartbeat, nowayout ? ", nowayout" : ""); 179 heartbeat, nowayout ? ", nowayout" : "");
@@ -272,27 +182,14 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
272 182
273static int __devexit orion_wdt_remove(struct platform_device *pdev) 183static int __devexit orion_wdt_remove(struct platform_device *pdev)
274{ 184{
275 int ret; 185 watchdog_unregister_device(&orion_wdt);
276
277 if (test_bit(WDT_IN_USE, &wdt_status)) {
278 orion_wdt_disable();
279 clear_bit(WDT_IN_USE, &wdt_status);
280 }
281
282 ret = misc_deregister(&orion_wdt_miscdev);
283 if (!ret)
284 orion_wdt_miscdev.parent = NULL;
285
286 clk_disable_unprepare(clk); 186 clk_disable_unprepare(clk);
287 clk_put(clk); 187 return 0;
288
289 return ret;
290} 188}
291 189
292static void orion_wdt_shutdown(struct platform_device *pdev) 190static void orion_wdt_shutdown(struct platform_device *pdev)
293{ 191{
294 if (test_bit(WDT_IN_USE, &wdt_status)) 192 orion_wdt_stop(&orion_wdt);
295 orion_wdt_disable();
296} 193}
297 194
298static struct platform_driver orion_wdt_driver = { 195static struct platform_driver orion_wdt_driver = {