1ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
2ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Watchdog driver for Kendin/Micrel KS8695.
3ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor *
4ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * (C) 2007 Andrew Victor
5ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor *
6ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * This program is free software; you can redistribute it and/or modify
7ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * it under the terms of the GNU General Public License version 2 as
8ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * published by the Free Software Foundation.
9ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
10ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
1127c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1227c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches
131977f032722c27ee3730284582fd3991ad9ac81bJiri Slaby#include <linux/bitops.h>
14ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/errno.h>
15ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/fs.h>
16ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/init.h>
17ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/kernel.h>
18ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/miscdevice.h>
19ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/module.h>
20ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/moduleparam.h>
21ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/platform_device.h>
22ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/types.h>
23ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#include <linux/watchdog.h>
24f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox#include <linux/io.h>
25f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox#include <linux/uaccess.h>
26568dba66ac307532b6703331df71c17373c17a4aYegor Yefremov#include <mach/hardware.h>
27a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/regs-timer.h>
28ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
29ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#define WDT_DEFAULT_TIME	5	/* seconds */
30ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#define WDT_MAX_TIME		171	/* seconds */
31ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
32ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int wdt_time = WDT_DEFAULT_TIME;
3386a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT;
34ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
35ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victormodule_param(wdt_time, int, 0);
36f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan CoxMODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
37f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox					__MODULE_STRING(WDT_DEFAULT_TIME) ")");
38ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
39ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#ifdef CONFIG_WATCHDOG_NOWAYOUT
4086a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0);
41f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan CoxMODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
42f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
43ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#endif
44ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
45ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
46ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic unsigned long ks8695wdt_busy;
471334f32938e46fb321c67a652997d33583257249Axel Linstatic DEFINE_SPINLOCK(ks8695_lock);
48ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
49ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/* ......................................................................... */
50ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
51ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
52ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Disable the watchdog.
53ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
54f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Coxstatic inline void ks8695_wdt_stop(void)
55ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
56ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	unsigned long tmcon;
57ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
58f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_lock(&ks8695_lock);
59ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/* disable timer0 */
60ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
61ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
62f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_unlock(&ks8695_lock);
63ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
64ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
65ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
66ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Enable and reset the watchdog.
67ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
68f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Coxstatic inline void ks8695_wdt_start(void)
69ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
70ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	unsigned long tmcon;
710a51810aa058a0a4ac76dd6f87f4d10bee774e2eAndrew Victor	unsigned long tval = wdt_time * KS8695_CLOCK_RATE;
72ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
73f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_lock(&ks8695_lock);
74ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/* disable timer0 */
75ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
76ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
77ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
78ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/* program timer0 */
79ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tval | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
80ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
81ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/* re-enable timer0 */
82ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
83ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
84f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_unlock(&ks8695_lock);
85ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
86ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
87ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
88ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Reload the watchdog timer.  (ie, pat the watchdog)
89ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
90f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Coxstatic inline void ks8695_wdt_reload(void)
91ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
92ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	unsigned long tmcon;
93ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
94f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_lock(&ks8695_lock);
95ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/* disable, then re-enable timer0 */
96ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
97ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
98ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	__raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
99f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	spin_unlock(&ks8695_lock);
100ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
101ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
102ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
103ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Change the watchdog time interval.
104ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
105ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int ks8695_wdt_settimeout(int new_time)
106ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
107ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	/*
1080a51810aa058a0a4ac76dd6f87f4d10bee774e2eAndrew Victor	 * All counting occurs at KS8695_CLOCK_RATE / 128 = 0.256 Hz
109ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	 *
110ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	 * Since WDV is a 16-bit counter, the maximum period is
111ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	 * 65536 / 0.256 = 256 seconds.
112ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	 */
113ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
114ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		return -EINVAL;
115ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
116f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	/* Set new watchdog time. It will be used when
117f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	   ks8695_wdt_start() is called. */
118ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	wdt_time = new_time;
119ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return 0;
120ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
121ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
122ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/* ......................................................................... */
123ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
124ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
125ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Watchdog device is opened, and watchdog starts running.
126ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
127ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int ks8695_wdt_open(struct inode *inode, struct file *file)
128ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
129ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (test_and_set_bit(0, &ks8695wdt_busy))
130ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		return -EBUSY;
131ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
132ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	ks8695_wdt_start();
133ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return nonseekable_open(inode, file);
134ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
135ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
136ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
137ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Close the watchdog device.
138ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
139ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor *  disabled.
140ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
141ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int ks8695_wdt_close(struct inode *inode, struct file *file)
142ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
143f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	/* Disable the watchdog when file is closed */
144ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (!nowayout)
145f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		ks8695_wdt_stop();
146ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	clear_bit(0, &ks8695wdt_busy);
147ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return 0;
148ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
149ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
15042747d712de56cf2087b702d2ad90af114c53138Wim Van Sebroeckstatic const struct watchdog_info ks8695_wdt_info = {
151ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.identity	= "ks8695 watchdog",
152ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
153ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor};
154ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
155ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
156ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Handle commands from user-space.
157ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
158f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Coxstatic long ks8695_wdt_ioctl(struct file *file, unsigned int cmd,
159f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox							unsigned long arg)
160ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
161ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	void __user *argp = (void __user *)arg;
162ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	int __user *p = argp;
163ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	int new_value;
164ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
165f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	switch (cmd) {
166f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	case WDIOC_GETSUPPORT:
167f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		return copy_to_user(argp, &ks8695_wdt_info,
168f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox					sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
169f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	case WDIOC_GETSTATUS:
170f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	case WDIOC_GETBOOTSTATUS:
171f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		return put_user(0, p);
172f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	case WDIOC_SETOPTIONS:
173f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		if (get_user(new_value, p))
174f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox			return -EFAULT;
175f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		if (new_value & WDIOS_DISABLECARD)
176f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox			ks8695_wdt_stop();
177f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		if (new_value & WDIOS_ENABLECARD)
178ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor			ks8695_wdt_start();
179f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		return 0;
1800c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck	case WDIOC_KEEPALIVE:
1810c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		ks8695_wdt_reload();	/* pat the watchdog */
1820c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		return 0;
1830c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck	case WDIOC_SETTIMEOUT:
1840c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		if (get_user(new_value, p))
1850c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck			return -EFAULT;
1860c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		if (ks8695_wdt_settimeout(new_value))
1870c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck			return -EINVAL;
1880c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		/* Enable new time value */
1890c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		ks8695_wdt_start();
1900c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		/* Return current value */
1910c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		return put_user(wdt_time, p);
1920c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck	case WDIOC_GETTIMEOUT:
1930c06090c9472db0525cb6fe229c3bea33bbbbb3cWim Van Sebroeck		return put_user(wdt_time, p);
194f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	default:
195f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox		return -ENOTTY;
196ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	}
197ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
198ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
199ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/*
200ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor * Pat the watchdog whenever device is written to.
201ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor */
202f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Coxstatic ssize_t ks8695_wdt_write(struct file *file, const char *data,
203f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox						size_t len, loff_t *ppos)
204ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
205ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	ks8695_wdt_reload();		/* pat the watchdog */
206ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return len;
207ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
208ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
209ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor/* ......................................................................... */
210ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
211ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic const struct file_operations ks8695wdt_fops = {
212ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.owner		= THIS_MODULE,
213ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.llseek		= no_llseek,
214f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	.unlocked_ioctl	= ks8695_wdt_ioctl,
215ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.open		= ks8695_wdt_open,
216ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.release	= ks8695_wdt_close,
217ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.write		= ks8695_wdt_write,
218ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor};
219ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
220ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic struct miscdevice ks8695wdt_miscdev = {
221ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.minor		= WATCHDOG_MINOR,
222ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.name		= "watchdog",
223ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.fops		= &ks8695wdt_fops,
224ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor};
225ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
226c98d58e00d8562520c9a69e688f007b860faebaaUwe Kleine-Königstatic int __devinit ks8695wdt_probe(struct platform_device *pdev)
227ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
228ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	int res;
229ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
230ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (ks8695wdt_miscdev.parent)
231ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		return -EBUSY;
232ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	ks8695wdt_miscdev.parent = &pdev->dev;
233ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
234ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	res = misc_register(&ks8695wdt_miscdev);
235ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (res)
236ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		return res;
237ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
23827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches	pr_info("KS8695 Watchdog Timer enabled (%d seconds%s)\n",
23927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		wdt_time, nowayout ? ", nowayout" : "");
240ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return 0;
241ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
242ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
243c98d58e00d8562520c9a69e688f007b860faebaaUwe Kleine-Königstatic int __devexit ks8695wdt_remove(struct platform_device *pdev)
244ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
245ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	int res;
246ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
247ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	res = misc_deregister(&ks8695wdt_miscdev);
248ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (!res)
249ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		ks8695wdt_miscdev.parent = NULL;
250ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
251ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return res;
252ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
253ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
254ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic void ks8695wdt_shutdown(struct platform_device *pdev)
255ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
256ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	ks8695_wdt_stop();
257ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
258ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
259ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#ifdef CONFIG_PM
260ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
261ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int ks8695wdt_suspend(struct platform_device *pdev, pm_message_t message)
262ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
263ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	ks8695_wdt_stop();
264ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return 0;
265ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
266ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
267ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int ks8695wdt_resume(struct platform_device *pdev)
268ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
269ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (ks8695wdt_busy)
270ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		ks8695_wdt_start();
271ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return 0;
272ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
273ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
274ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#else
275ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#define ks8695wdt_suspend NULL
276ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#define ks8695wdt_resume	NULL
277ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor#endif
278ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
279ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic struct platform_driver ks8695wdt_driver = {
280ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.probe		= ks8695wdt_probe,
281c98d58e00d8562520c9a69e688f007b860faebaaUwe Kleine-König	.remove		= __devexit_p(ks8695wdt_remove),
282ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.shutdown	= ks8695wdt_shutdown,
283ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.suspend	= ks8695wdt_suspend,
284ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.resume		= ks8695wdt_resume,
285ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	.driver		= {
286ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		.name	= "ks8695_wdt",
287ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		.owner	= THIS_MODULE,
288ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	},
289ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor};
290ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
291ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic int __init ks8695_wdt_init(void)
292ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
293f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	/* Check that the heartbeat value is within range;
294f4fabce15bb9b547f934e2b6f0e5e01044108e4dAlan Cox	   if not reset to the default */
295ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	if (ks8695_wdt_settimeout(wdt_time)) {
296ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor		ks8695_wdt_settimeout(WDT_DEFAULT_TIME);
297a77dba7e444a6618cbb666d1b42b79842b9c0171Wim Van Sebroeck		pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i"
298a77dba7e444a6618cbb666d1b42b79842b9c0171Wim Van Sebroeck					", using %d\n", wdt_time, WDT_MAX_TIME);
299ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	}
300ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	return platform_driver_register(&ks8695wdt_driver);
301ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
302ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
303ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victorstatic void __exit ks8695_wdt_exit(void)
304ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor{
305ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor	platform_driver_unregister(&ks8695wdt_driver);
306ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor}
307ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
308ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victormodule_init(ks8695_wdt_init);
309ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victormodule_exit(ks8695_wdt_exit);
310ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew Victor
311ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew VictorMODULE_AUTHOR("Andrew Victor");
312ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew VictorMODULE_DESCRIPTION("Watchdog driver for KS8695");
313ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew VictorMODULE_LICENSE("GPL");
314ccb8f430ac4cfd1acd12ff591918b8b67d73c977Andrew VictorMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
315f37d193c7c150c40059c7ce5de34e8b28a9cd4aeKay SieversMODULE_ALIAS("platform:ks8695_wdt");
316