Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 *  PNX833x Hardware Watchdog Driver
  3 *  Copyright 2008 NXP Semiconductors
  4 *  Daniel Laird <daniel.j.laird@nxp.com>
  5 *  Andre McCurdy <andre.mccurdy@nxp.com>
  6 *
  7 *  Heavily based upon - IndyDog	0.3
  8 *  A Hardware Watchdog Device for SGI IP22
  9 *
 10 * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
 11 *
 12 * This program is free software; you can redistribute it and/or
 13 * modify it under the terms of the GNU General Public License
 14 * as published by the Free Software Foundation; either version
 15 * 2 of the License, or (at your option) any later version.
 16 *
 17 * based on softdog.c by Alan Cox <alan@redhat.com>
 18 */
 19
 
 
 20#include <linux/module.h>
 21#include <linux/moduleparam.h>
 22#include <linux/types.h>
 23#include <linux/kernel.h>
 24#include <linux/fs.h>
 25#include <linux/mm.h>
 26#include <linux/miscdevice.h>
 27#include <linux/watchdog.h>
 28#include <linux/notifier.h>
 29#include <linux/reboot.h>
 30#include <linux/init.h>
 31#include <asm/mach-pnx833x/pnx833x.h>
 32
 33#define PFX "pnx833x: "
 34#define WATCHDOG_TIMEOUT 30		/* 30 sec Maximum timeout */
 35#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
 36#define	PNX_WATCHDOG_TIMEOUT	(WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
 37#define PNX_TIMEOUT_VALUE	2040000000U
 38
 39/** CONFIG block */
 40#define PNX833X_CONFIG                      (0x07000U)
 41#define PNX833X_CONFIG_CPU_WATCHDOG         (0x54)
 42#define PNX833X_CONFIG_CPU_WATCHDOG_COMPARE (0x58)
 43#define PNX833X_CONFIG_CPU_COUNTERS_CONTROL (0x1c)
 44
 45/** RESET block */
 46#define PNX833X_RESET                       (0x08000U)
 47#define PNX833X_RESET_CONFIG                (0x08)
 48
 49static int pnx833x_wdt_alive;
 50
 51/* Set default timeout in MHZ.*/
 52static int pnx833x_wdt_timeout = PNX_WATCHDOG_TIMEOUT;
 53module_param(pnx833x_wdt_timeout, int, 0);
 54MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
 55			__MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
 56
 57static int nowayout = WATCHDOG_NOWAYOUT;
 58module_param(nowayout, int, 0);
 59MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 60					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 61
 62#define START_DEFAULT	1
 63static int start_enabled = START_DEFAULT;
 64module_param(start_enabled, int, 0);
 65MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
 66				"(default=" __MODULE_STRING(START_DEFAULT) ")");
 67
 68static void pnx833x_wdt_start(void)
 69{
 70	/* Enable watchdog causing reset. */
 71	PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1;
 72	/* Set timeout.*/
 73	PNX833X_REG(PNX833X_CONFIG +
 74		PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
 75	/* Enable watchdog. */
 76	PNX833X_REG(PNX833X_CONFIG +
 77				PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
 78
 79	printk(KERN_INFO PFX "Started watchdog timer.\n");
 80}
 81
 82static void pnx833x_wdt_stop(void)
 83{
 84	/* Disable watchdog causing reset. */
 85	PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE;
 86	/* Disable watchdog.*/
 87	PNX833X_REG(PNX833X_CONFIG +
 88			PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
 89
 90	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
 91}
 92
 93static void pnx833x_wdt_ping(void)
 94{
 95	PNX833X_REG(PNX833X_CONFIG +
 96		PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
 97}
 98
 99/*
100 *	Allow only one person to hold it open
101 */
102static int pnx833x_wdt_open(struct inode *inode, struct file *file)
103{
104	if (test_and_set_bit(0, &pnx833x_wdt_alive))
105		return -EBUSY;
106
107	if (nowayout)
108		__module_get(THIS_MODULE);
109
110	/* Activate timer */
111	if (!start_enabled)
112		pnx833x_wdt_start();
113
114	pnx833x_wdt_ping();
115
116	printk(KERN_INFO "Started watchdog timer.\n");
117
118	return nonseekable_open(inode, file);
119}
120
121static int pnx833x_wdt_release(struct inode *inode, struct file *file)
122{
123	/* Shut off the timer.
124	 * Lock it in if it's a module and we defined ...NOWAYOUT */
125	if (!nowayout)
126		pnx833x_wdt_stop(); /* Turn the WDT off */
127
128	clear_bit(0, &pnx833x_wdt_alive);
129	return 0;
130}
131
132static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
133{
134	/* Refresh the timer. */
135	if (len)
136		pnx833x_wdt_ping();
137
138	return len;
139}
140
141static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
142							unsigned long arg)
143{
144	int options, new_timeout = 0;
145	uint32_t timeout, timeout_left = 0;
146
147	static const struct watchdog_info ident = {
148		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
149		.firmware_version = 0,
150		.identity = "Hardware Watchdog for PNX833x",
151	};
152
153	switch (cmd) {
154	default:
155		return -ENOTTY;
156
157	case WDIOC_GETSUPPORT:
158		if (copy_to_user((struct watchdog_info *)arg,
159				 &ident, sizeof(ident)))
160			return -EFAULT;
161		return 0;
162
163	case WDIOC_GETSTATUS:
164	case WDIOC_GETBOOTSTATUS:
165		return put_user(0, (int *)arg);
166
167	case WDIOC_SETOPTIONS:
168		if (get_user(options, (int *)arg))
169			return -EFAULT;
170
171		if (options & WDIOS_DISABLECARD)
172			pnx833x_wdt_stop();
173
174		if (options & WDIOS_ENABLECARD)
175			pnx833x_wdt_start();
176
177		return 0;
178
179	case WDIOC_KEEPALIVE:
180		pnx833x_wdt_ping();
181		return 0;
182
183	case WDIOC_SETTIMEOUT:
184	{
185		if (get_user(new_timeout, (int *)arg))
186			return -EFAULT;
187
188		pnx833x_wdt_timeout = new_timeout;
189		PNX833X_REG(PNX833X_CONFIG +
190			PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout;
191		return put_user(new_timeout, (int *)arg);
192	}
193
194	case WDIOC_GETTIMEOUT:
195		timeout = PNX833X_REG(PNX833X_CONFIG +
196					PNX833X_CONFIG_CPU_WATCHDOG_COMPARE);
197		return put_user(timeout, (int *)arg);
198
199	case WDIOC_GETTIMELEFT:
200		timeout_left = PNX833X_REG(PNX833X_CONFIG +
201						PNX833X_CONFIG_CPU_WATCHDOG);
202		return put_user(timeout_left, (int *)arg);
203
204	}
205}
206
207static int pnx833x_wdt_notify_sys(struct notifier_block *this,
208					unsigned long code, void *unused)
209{
210	if (code == SYS_DOWN || code == SYS_HALT)
211		pnx833x_wdt_stop(); /* Turn the WDT off */
212
213	return NOTIFY_DONE;
214}
215
216static const struct file_operations pnx833x_wdt_fops = {
217	.owner		= THIS_MODULE,
218	.llseek		= no_llseek,
219	.write		= pnx833x_wdt_write,
220	.unlocked_ioctl	= pnx833x_wdt_ioctl,
221	.open		= pnx833x_wdt_open,
222	.release	= pnx833x_wdt_release,
223};
224
225static struct miscdevice pnx833x_wdt_miscdev = {
226	.minor		= WATCHDOG_MINOR,
227	.name		= "watchdog",
228	.fops		= &pnx833x_wdt_fops,
229};
230
231static struct notifier_block pnx833x_wdt_notifier = {
232	.notifier_call = pnx833x_wdt_notify_sys,
233};
234
235static char banner[] __initdata =
236	KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
237
238static int __init watchdog_init(void)
239{
240	int ret, cause;
241
242	/* Lets check the reason for the reset.*/
243	cause = PNX833X_REG(PNX833X_RESET);
244	/*If bit 31 is set then watchdog was cause of reset.*/
245	if (cause & 0x80000000) {
246		printk(KERN_INFO PFX "The system was previously reset due to "
247			"the watchdog firing - please investigate...\n");
248	}
249
250	ret = register_reboot_notifier(&pnx833x_wdt_notifier);
251	if (ret) {
252		printk(KERN_ERR PFX
253			"cannot register reboot notifier (err=%d)\n", ret);
254		return ret;
255	}
256
257	ret = misc_register(&pnx833x_wdt_miscdev);
258	if (ret) {
259		printk(KERN_ERR PFX
260			"cannot register miscdev on minor=%d (err=%d)\n",
261			WATCHDOG_MINOR, ret);
262		unregister_reboot_notifier(&pnx833x_wdt_notifier);
263		return ret;
264	}
265
266	printk(banner);
 
267	if (start_enabled)
268		pnx833x_wdt_start();
269
270	return 0;
271}
272
273static void __exit watchdog_exit(void)
274{
275	misc_deregister(&pnx833x_wdt_miscdev);
276	unregister_reboot_notifier(&pnx833x_wdt_notifier);
277}
278
279module_init(watchdog_init);
280module_exit(watchdog_exit);
281
282MODULE_AUTHOR("Daniel Laird/Andre McCurdy");
283MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x");
284MODULE_LICENSE("GPL");
285MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
v4.17
  1/*
  2 *  PNX833x Hardware Watchdog Driver
  3 *  Copyright 2008 NXP Semiconductors
  4 *  Daniel Laird <daniel.j.laird@nxp.com>
  5 *  Andre McCurdy <andre.mccurdy@nxp.com>
  6 *
  7 *  Heavily based upon - IndyDog	0.3
  8 *  A Hardware Watchdog Device for SGI IP22
  9 *
 10 * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
 11 *
 12 * This program is free software; you can redistribute it and/or
 13 * modify it under the terms of the GNU General Public License
 14 * as published by the Free Software Foundation; either version
 15 * 2 of the License, or (at your option) any later version.
 16 *
 17 * based on softdog.c by Alan Cox <alan@redhat.com>
 18 */
 19
 20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 21
 22#include <linux/module.h>
 23#include <linux/moduleparam.h>
 24#include <linux/types.h>
 25#include <linux/kernel.h>
 26#include <linux/fs.h>
 27#include <linux/mm.h>
 28#include <linux/miscdevice.h>
 29#include <linux/watchdog.h>
 30#include <linux/notifier.h>
 31#include <linux/reboot.h>
 32#include <linux/init.h>
 33#include <asm/mach-pnx833x/pnx833x.h>
 34
 
 35#define WATCHDOG_TIMEOUT 30		/* 30 sec Maximum timeout */
 36#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
 37#define	PNX_WATCHDOG_TIMEOUT	(WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY)
 38#define PNX_TIMEOUT_VALUE	2040000000U
 39
 40/** CONFIG block */
 41#define PNX833X_CONFIG                      (0x07000U)
 42#define PNX833X_CONFIG_CPU_WATCHDOG         (0x54)
 43#define PNX833X_CONFIG_CPU_WATCHDOG_COMPARE (0x58)
 44#define PNX833X_CONFIG_CPU_COUNTERS_CONTROL (0x1c)
 45
 46/** RESET block */
 47#define PNX833X_RESET                       (0x08000U)
 48#define PNX833X_RESET_CONFIG                (0x08)
 49
 50static int pnx833x_wdt_alive;
 51
 52/* Set default timeout in MHZ.*/
 53static int pnx833x_wdt_timeout = PNX_WATCHDOG_TIMEOUT;
 54module_param(pnx833x_wdt_timeout, int, 0);
 55MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
 56			__MODULE_STRING(PNX_TIMEOUT_VALUE) "(30 seconds).");
 57
 58static bool nowayout = WATCHDOG_NOWAYOUT;
 59module_param(nowayout, bool, 0);
 60MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 61					__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 62
 63#define START_DEFAULT	1
 64static int start_enabled = START_DEFAULT;
 65module_param(start_enabled, int, 0);
 66MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
 67				"(default=" __MODULE_STRING(START_DEFAULT) ")");
 68
 69static void pnx833x_wdt_start(void)
 70{
 71	/* Enable watchdog causing reset. */
 72	PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1;
 73	/* Set timeout.*/
 74	PNX833X_REG(PNX833X_CONFIG +
 75		PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
 76	/* Enable watchdog. */
 77	PNX833X_REG(PNX833X_CONFIG +
 78				PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
 79
 80	pr_info("Started watchdog timer\n");
 81}
 82
 83static void pnx833x_wdt_stop(void)
 84{
 85	/* Disable watchdog causing reset. */
 86	PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE;
 87	/* Disable watchdog.*/
 88	PNX833X_REG(PNX833X_CONFIG +
 89			PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
 90
 91	pr_info("Stopped watchdog timer\n");
 92}
 93
 94static void pnx833x_wdt_ping(void)
 95{
 96	PNX833X_REG(PNX833X_CONFIG +
 97		PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
 98}
 99
100/*
101 *	Allow only one person to hold it open
102 */
103static int pnx833x_wdt_open(struct inode *inode, struct file *file)
104{
105	if (test_and_set_bit(0, &pnx833x_wdt_alive))
106		return -EBUSY;
107
108	if (nowayout)
109		__module_get(THIS_MODULE);
110
111	/* Activate timer */
112	if (!start_enabled)
113		pnx833x_wdt_start();
114
115	pnx833x_wdt_ping();
116
117	pr_info("Started watchdog timer\n");
118
119	return nonseekable_open(inode, file);
120}
121
122static int pnx833x_wdt_release(struct inode *inode, struct file *file)
123{
124	/* Shut off the timer.
125	 * Lock it in if it's a module and we defined ...NOWAYOUT */
126	if (!nowayout)
127		pnx833x_wdt_stop(); /* Turn the WDT off */
128
129	clear_bit(0, &pnx833x_wdt_alive);
130	return 0;
131}
132
133static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
134{
135	/* Refresh the timer. */
136	if (len)
137		pnx833x_wdt_ping();
138
139	return len;
140}
141
142static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
143							unsigned long arg)
144{
145	int options, new_timeout = 0;
146	uint32_t timeout, timeout_left = 0;
147
148	static const struct watchdog_info ident = {
149		.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
150		.firmware_version = 0,
151		.identity = "Hardware Watchdog for PNX833x",
152	};
153
154	switch (cmd) {
155	default:
156		return -ENOTTY;
157
158	case WDIOC_GETSUPPORT:
159		if (copy_to_user((struct watchdog_info *)arg,
160				 &ident, sizeof(ident)))
161			return -EFAULT;
162		return 0;
163
164	case WDIOC_GETSTATUS:
165	case WDIOC_GETBOOTSTATUS:
166		return put_user(0, (int *)arg);
167
168	case WDIOC_SETOPTIONS:
169		if (get_user(options, (int *)arg))
170			return -EFAULT;
171
172		if (options & WDIOS_DISABLECARD)
173			pnx833x_wdt_stop();
174
175		if (options & WDIOS_ENABLECARD)
176			pnx833x_wdt_start();
177
178		return 0;
179
180	case WDIOC_KEEPALIVE:
181		pnx833x_wdt_ping();
182		return 0;
183
184	case WDIOC_SETTIMEOUT:
185	{
186		if (get_user(new_timeout, (int *)arg))
187			return -EFAULT;
188
189		pnx833x_wdt_timeout = new_timeout;
190		PNX833X_REG(PNX833X_CONFIG +
191			PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout;
192		return put_user(new_timeout, (int *)arg);
193	}
194
195	case WDIOC_GETTIMEOUT:
196		timeout = PNX833X_REG(PNX833X_CONFIG +
197					PNX833X_CONFIG_CPU_WATCHDOG_COMPARE);
198		return put_user(timeout, (int *)arg);
199
200	case WDIOC_GETTIMELEFT:
201		timeout_left = PNX833X_REG(PNX833X_CONFIG +
202						PNX833X_CONFIG_CPU_WATCHDOG);
203		return put_user(timeout_left, (int *)arg);
204
205	}
206}
207
208static int pnx833x_wdt_notify_sys(struct notifier_block *this,
209					unsigned long code, void *unused)
210{
211	if (code == SYS_DOWN || code == SYS_HALT)
212		pnx833x_wdt_stop(); /* Turn the WDT off */
213
214	return NOTIFY_DONE;
215}
216
217static const struct file_operations pnx833x_wdt_fops = {
218	.owner		= THIS_MODULE,
219	.llseek		= no_llseek,
220	.write		= pnx833x_wdt_write,
221	.unlocked_ioctl	= pnx833x_wdt_ioctl,
222	.open		= pnx833x_wdt_open,
223	.release	= pnx833x_wdt_release,
224};
225
226static struct miscdevice pnx833x_wdt_miscdev = {
227	.minor		= WATCHDOG_MINOR,
228	.name		= "watchdog",
229	.fops		= &pnx833x_wdt_fops,
230};
231
232static struct notifier_block pnx833x_wdt_notifier = {
233	.notifier_call = pnx833x_wdt_notify_sys,
234};
235
 
 
 
236static int __init watchdog_init(void)
237{
238	int ret, cause;
239
240	/* Lets check the reason for the reset.*/
241	cause = PNX833X_REG(PNX833X_RESET);
242	/*If bit 31 is set then watchdog was cause of reset.*/
243	if (cause & 0x80000000) {
244		pr_info("The system was previously reset due to the watchdog firing - please investigate...\n");
 
245	}
246
247	ret = register_reboot_notifier(&pnx833x_wdt_notifier);
248	if (ret) {
249		pr_err("cannot register reboot notifier (err=%d)\n", ret);
 
250		return ret;
251	}
252
253	ret = misc_register(&pnx833x_wdt_miscdev);
254	if (ret) {
255		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
256		       WATCHDOG_MINOR, ret);
 
257		unregister_reboot_notifier(&pnx833x_wdt_notifier);
258		return ret;
259	}
260
261	pr_info("Hardware Watchdog Timer for PNX833x: Version 0.1\n");
262
263	if (start_enabled)
264		pnx833x_wdt_start();
265
266	return 0;
267}
268
269static void __exit watchdog_exit(void)
270{
271	misc_deregister(&pnx833x_wdt_miscdev);
272	unregister_reboot_notifier(&pnx833x_wdt_notifier);
273}
274
275module_init(watchdog_init);
276module_exit(watchdog_exit);
277
278MODULE_AUTHOR("Daniel Laird/Andre McCurdy");
279MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x");
280MODULE_LICENSE("GPL");