omap_wdt.c revision a09e64fbc0094e3073dbb09c3b4bfe4ab669244b
17768a13c252a97e13a552f88f642962768de1fa4Komal Shah/*
27768a13c252a97e13a552f88f642962768de1fa4Komal Shah * linux/drivers/char/watchdog/omap_wdt.c
37768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
47768a13c252a97e13a552f88f642962768de1fa4Komal Shah * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
57768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
67768a13c252a97e13a552f88f642962768de1fa4Komal Shah * Author: MontaVista Software, Inc.
77768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	 <gdavis@mvista.com> or <source@mvista.com>
87768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
97768a13c252a97e13a552f88f642962768de1fa4Komal Shah * 2003 (c) MontaVista Software, Inc. This file is licensed under the
107768a13c252a97e13a552f88f642962768de1fa4Komal Shah * terms of the GNU General Public License version 2. This program is
117768a13c252a97e13a552f88f642962768de1fa4Komal Shah * licensed "as is" without any warranty of any kind, whether express
127768a13c252a97e13a552f88f642962768de1fa4Komal Shah * or implied.
137768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
147768a13c252a97e13a552f88f642962768de1fa4Komal Shah * History:
157768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
167768a13c252a97e13a552f88f642962768de1fa4Komal Shah * 20030527: George G. Davis <gdavis@mvista.com>
177768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
187768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	(c) Copyright 2000 Oleg Drokin <green@crimea.edu>
197768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	Based on SoftDog driver by Alan Cox <alan@redhat.com>
207768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
217768a13c252a97e13a552f88f642962768de1fa4Komal Shah * Copyright (c) 2004 Texas Instruments.
227768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	1. Modified to support OMAP1610 32-KHz watchdog timer
237768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	2. Ported to 2.6 kernel
247768a13c252a97e13a552f88f642962768de1fa4Komal Shah *
257768a13c252a97e13a552f88f642962768de1fa4Komal Shah * Copyright (c) 2005 David Brownell
267768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	Use the driver model and standard identifiers; handle bigger timeouts.
277768a13c252a97e13a552f88f642962768de1fa4Komal Shah */
287768a13c252a97e13a552f88f642962768de1fa4Komal Shah
297768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/module.h>
307768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/types.h>
317768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/kernel.h>
327768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/fs.h>
337768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/mm.h>
347768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/miscdevice.h>
357768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/watchdog.h>
367768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/reboot.h>
377768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/init.h>
387768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/err.h>
397768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/platform_device.h>
407768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/moduleparam.h>
417768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <linux/clk.h>
421977f032722c27ee3730284582fd3991ad9ac81bJiri Slaby#include <linux/bitops.h>
437768a13c252a97e13a552f88f642962768de1fa4Komal Shah
447768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <asm/io.h>
457768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include <asm/uaccess.h>
46a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h>
477768a13c252a97e13a552f88f642962768de1fa4Komal Shah
48a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/prcm.h>
497768a13c252a97e13a552f88f642962768de1fa4Komal Shah
507768a13c252a97e13a552f88f642962768de1fa4Komal Shah#include "omap_wdt.h"
517768a13c252a97e13a552f88f642962768de1fa4Komal Shah
527768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic unsigned timer_margin;
537768a13c252a97e13a552f88f642962768de1fa4Komal Shahmodule_param(timer_margin, uint, 0);
547768a13c252a97e13a552f88f642962768de1fa4Komal ShahMODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
557768a13c252a97e13a552f88f642962768de1fa4Komal Shah
567768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_users;
577768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic struct clk *armwdt_ck = NULL;
587768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic struct clk *mpu_wdt_ick = NULL;
597768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic struct clk *mpu_wdt_fck = NULL;
607768a13c252a97e13a552f88f642962768de1fa4Komal Shah
617768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic unsigned int wdt_trgr_pattern = 0x1234;
627768a13c252a97e13a552f88f642962768de1fa4Komal Shah
637768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_ping(void)
647768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
657768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* wait for posted write to complete */
667768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
677768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
687768a13c252a97e13a552f88f642962768de1fa4Komal Shah	wdt_trgr_pattern = ~wdt_trgr_pattern;
697768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
707768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* wait for posted write to complete */
717768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
727768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
737768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* reloaded WCRR from WLDR */
747768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
757768a13c252a97e13a552f88f642962768de1fa4Komal Shah
767768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_enable(void)
777768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
787768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* Sequence to enable the watchdog */
797768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
807768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
817768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
827768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(0x4444, OMAP_WATCHDOG_SPR);
837768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
847768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
857768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
867768a13c252a97e13a552f88f642962768de1fa4Komal Shah
877768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_disable(void)
887768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
897768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* sequence required to disable watchdog */
907768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(0xAAAA, OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
917768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
927768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
937768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(0x5555, OMAP_WATCHDOG_SPR);	/* TIMER_MODE */
947768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
957768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
967768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
977768a13c252a97e13a552f88f642962768de1fa4Komal Shah
987768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_adjust_timeout(unsigned new_timeout)
997768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1007768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (new_timeout < TIMER_MARGIN_MIN)
1017768a13c252a97e13a552f88f642962768de1fa4Komal Shah		new_timeout = TIMER_MARGIN_DEFAULT;
1027768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (new_timeout > TIMER_MARGIN_MAX)
1037768a13c252a97e13a552f88f642962768de1fa4Komal Shah		new_timeout = TIMER_MARGIN_MAX;
1047768a13c252a97e13a552f88f642962768de1fa4Komal Shah	timer_margin = new_timeout;
1057768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
1067768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1077768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_set_timeout(void)
1087768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1097768a13c252a97e13a552f88f642962768de1fa4Komal Shah	u32 pre_margin = GET_WLDR_VAL(timer_margin);
1107768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1117768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* just count up at 32 KHz */
1127768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
1137768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
1147768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
1157768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
1167768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
1177768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
1187768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1197768a13c252a97e13a552f88f642962768de1fa4Komal Shah/*
1207768a13c252a97e13a552f88f642962768de1fa4Komal Shah *	Allow only one task to hold it open
1217768a13c252a97e13a552f88f642962768de1fa4Komal Shah */
1227768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1237768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_open(struct inode *inode, struct file *file)
1247768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1257768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
1267768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return -EBUSY;
1277768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1287768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap16xx())
1297768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_enable(armwdt_ck);	/* Enable the clock */
1307768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1317768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap24xx()) {
1327768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
1337768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
1347768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
1357768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1367768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* initialize prescaler */
1377768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
1387768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
1397768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
1407768a13c252a97e13a552f88f642962768de1fa4Komal Shah	while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
1417768a13c252a97e13a552f88f642962768de1fa4Komal Shah		cpu_relax();
1427768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1437768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_set_timeout();
1447768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_enable();
145ec9505a7ecadc0ab8f8e3c4c5fa900d57467e391Wim Van Sebroeck	return nonseekable_open(inode, file);
1467768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
1477768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1487768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_release(struct inode *inode, struct file *file)
1497768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1507768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/*
1517768a13c252a97e13a552f88f642962768de1fa4Komal Shah	 *      Shut off the timer unless NOWAYOUT is defined.
1527768a13c252a97e13a552f88f642962768de1fa4Komal Shah	 */
1537768a13c252a97e13a552f88f642962768de1fa4Komal Shah#ifndef CONFIG_WATCHDOG_NOWAYOUT
1547768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_disable();
1557768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1567768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap16xx()) {
1577768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_disable(armwdt_ck);	/* Disable the clock */
1587768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(armwdt_ck);
1597768a13c252a97e13a552f88f642962768de1fa4Komal Shah		armwdt_ck = NULL;
1607768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
1617768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1627768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap24xx()) {
1637768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_disable(mpu_wdt_ick);	/* Disable the clock */
1647768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_disable(mpu_wdt_fck);	/* Disable the clock */
1657768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_ick);
1667768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_fck);
1677768a13c252a97e13a552f88f642962768de1fa4Komal Shah		mpu_wdt_ick = NULL;
1687768a13c252a97e13a552f88f642962768de1fa4Komal Shah		mpu_wdt_fck = NULL;
1697768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
1707768a13c252a97e13a552f88f642962768de1fa4Komal Shah#else
1717768a13c252a97e13a552f88f642962768de1fa4Komal Shah	printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
1727768a13c252a97e13a552f88f642962768de1fa4Komal Shah#endif
1737768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_users = 0;
1747768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return 0;
1757768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
1767768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1777768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic ssize_t
1787768a13c252a97e13a552f88f642962768de1fa4Komal Shahomap_wdt_write(struct file *file, const char __user *data,
1797768a13c252a97e13a552f88f642962768de1fa4Komal Shah		size_t len, loff_t *ppos)
1807768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1817768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* Refresh LOAD_TIME. */
1827768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (len)
1837768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_ping();
1847768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return len;
1857768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
1867768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1877768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int
1887768a13c252a97e13a552f88f642962768de1fa4Komal Shahomap_wdt_ioctl(struct inode *inode, struct file *file,
1897768a13c252a97e13a552f88f642962768de1fa4Komal Shah	unsigned int cmd, unsigned long arg)
1907768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
1917768a13c252a97e13a552f88f642962768de1fa4Komal Shah	int new_margin;
1927768a13c252a97e13a552f88f642962768de1fa4Komal Shah	static struct watchdog_info ident = {
1937768a13c252a97e13a552f88f642962768de1fa4Komal Shah		.identity = "OMAP Watchdog",
1947768a13c252a97e13a552f88f642962768de1fa4Komal Shah		.options = WDIOF_SETTIMEOUT,
1957768a13c252a97e13a552f88f642962768de1fa4Komal Shah		.firmware_version = 0,
1967768a13c252a97e13a552f88f642962768de1fa4Komal Shah	};
1977768a13c252a97e13a552f88f642962768de1fa4Komal Shah
1987768a13c252a97e13a552f88f642962768de1fa4Komal Shah	switch (cmd) {
1997768a13c252a97e13a552f88f642962768de1fa4Komal Shah	default:
2001bf1496d41756496db2fcf4c8f1932b9762232f6Wim Van Sebroeck		return -ENOTTY;
2017768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_GETSUPPORT:
2027768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return copy_to_user((struct watchdog_info __user *)arg, &ident,
2037768a13c252a97e13a552f88f642962768de1fa4Komal Shah				sizeof(ident));
2047768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_GETSTATUS:
2057768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return put_user(0, (int __user *)arg);
2067768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_GETBOOTSTATUS:
2077768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (cpu_is_omap16xx())
2087768a13c252a97e13a552f88f642962768de1fa4Komal Shah			return put_user(omap_readw(ARM_SYSST),
2097768a13c252a97e13a552f88f642962768de1fa4Komal Shah					(int __user *)arg);
2107768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (cpu_is_omap24xx())
2117768a13c252a97e13a552f88f642962768de1fa4Komal Shah			return put_user(omap_prcm_get_reset_sources(),
2127768a13c252a97e13a552f88f642962768de1fa4Komal Shah					(int __user *)arg);
2137768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_KEEPALIVE:
2147768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_ping();
2157768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return 0;
2167768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_SETTIMEOUT:
2177768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (get_user(new_margin, (int __user *)arg))
2187768a13c252a97e13a552f88f642962768de1fa4Komal Shah			return -EFAULT;
2197768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_adjust_timeout(new_margin);
2207768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2217768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_disable();
2227768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_set_timeout();
2237768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_enable();
2247768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2257768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_ping();
2267768a13c252a97e13a552f88f642962768de1fa4Komal Shah		/* Fall */
2277768a13c252a97e13a552f88f642962768de1fa4Komal Shah	case WDIOC_GETTIMEOUT:
2287768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return put_user(timer_margin, (int __user *)arg);
2297768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
2307768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
2317768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2322b8693c0617e972fc0b2fd1ebf8de97e15b656c3Arjan van de Venstatic const struct file_operations omap_wdt_fops = {
2337768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.owner = THIS_MODULE,
2347768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.write = omap_wdt_write,
2357768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.ioctl = omap_wdt_ioctl,
2367768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.open = omap_wdt_open,
2377768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.release = omap_wdt_release,
2387768a13c252a97e13a552f88f642962768de1fa4Komal Shah};
2397768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2407768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic struct miscdevice omap_wdt_miscdev = {
2417768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.minor = WATCHDOG_MINOR,
2427768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.name = "watchdog",
2437768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.fops = &omap_wdt_fops
2447768a13c252a97e13a552f88f642962768de1fa4Komal Shah};
2457768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2467768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int __init omap_wdt_probe(struct platform_device *pdev)
2477768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
2487768a13c252a97e13a552f88f642962768de1fa4Komal Shah	struct resource *res, *mem;
2497768a13c252a97e13a552f88f642962768de1fa4Komal Shah	int ret;
2507768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2517768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* reserve static register mappings */
2527768a13c252a97e13a552f88f642962768de1fa4Komal Shah	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2537768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (!res)
2547768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return -ENOENT;
2557768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2567768a13c252a97e13a552f88f642962768de1fa4Komal Shah	mem = request_mem_region(res->start, res->end - res->start + 1,
2577768a13c252a97e13a552f88f642962768de1fa4Komal Shah				 pdev->name);
2587768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (mem == NULL)
2597768a13c252a97e13a552f88f642962768de1fa4Komal Shah		return -EBUSY;
2607768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2617768a13c252a97e13a552f88f642962768de1fa4Komal Shah	platform_set_drvdata(pdev, mem);
2627768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2637768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_users = 0;
2647768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2657768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap16xx()) {
2667768a13c252a97e13a552f88f642962768de1fa4Komal Shah		armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
2677768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (IS_ERR(armwdt_ck)) {
2687768a13c252a97e13a552f88f642962768de1fa4Komal Shah			ret = PTR_ERR(armwdt_ck);
2697768a13c252a97e13a552f88f642962768de1fa4Komal Shah			armwdt_ck = NULL;
2707768a13c252a97e13a552f88f642962768de1fa4Komal Shah			goto fail;
2717768a13c252a97e13a552f88f642962768de1fa4Komal Shah		}
2727768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
2737768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2747768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (cpu_is_omap24xx()) {
2757768a13c252a97e13a552f88f642962768de1fa4Komal Shah		mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
2767768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (IS_ERR(mpu_wdt_ick)) {
2777768a13c252a97e13a552f88f642962768de1fa4Komal Shah			ret = PTR_ERR(mpu_wdt_ick);
2787768a13c252a97e13a552f88f642962768de1fa4Komal Shah			mpu_wdt_ick = NULL;
2797768a13c252a97e13a552f88f642962768de1fa4Komal Shah			goto fail;
2807768a13c252a97e13a552f88f642962768de1fa4Komal Shah		}
2817768a13c252a97e13a552f88f642962768de1fa4Komal Shah		mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
2827768a13c252a97e13a552f88f642962768de1fa4Komal Shah		if (IS_ERR(mpu_wdt_fck)) {
2837768a13c252a97e13a552f88f642962768de1fa4Komal Shah			ret = PTR_ERR(mpu_wdt_fck);
2847768a13c252a97e13a552f88f642962768de1fa4Komal Shah			mpu_wdt_fck = NULL;
2857768a13c252a97e13a552f88f642962768de1fa4Komal Shah			goto fail;
2867768a13c252a97e13a552f88f642962768de1fa4Komal Shah		}
2877768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
2887768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2897768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_disable();
2907768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_adjust_timeout(timer_margin);
2917768a13c252a97e13a552f88f642962768de1fa4Komal Shah
292e0b79e0bc261ad320f6c218ac6823f7ca859171fAndrew Victor	omap_wdt_miscdev.parent = &pdev->dev;
2937768a13c252a97e13a552f88f642962768de1fa4Komal Shah	ret = misc_register(&omap_wdt_miscdev);
2947768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (ret)
2957768a13c252a97e13a552f88f642962768de1fa4Komal Shah		goto fail;
2967768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2977768a13c252a97e13a552f88f642962768de1fa4Komal Shah	pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
2987768a13c252a97e13a552f88f642962768de1fa4Komal Shah
2997768a13c252a97e13a552f88f642962768de1fa4Komal Shah	/* autogate OCP interface clock */
3007768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
3017768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return 0;
3027768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3037768a13c252a97e13a552f88f642962768de1fa4Komal Shahfail:
3047768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (armwdt_ck)
3057768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(armwdt_ck);
3067768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (mpu_wdt_ick)
3077768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_ick);
3087768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (mpu_wdt_fck)
3097768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_fck);
3107768a13c252a97e13a552f88f642962768de1fa4Komal Shah	release_resource(mem);
3117768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return ret;
3127768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3137768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3147768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void omap_wdt_shutdown(struct platform_device *pdev)
3157768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3167768a13c252a97e13a552f88f642962768de1fa4Komal Shah	omap_wdt_disable();
3177768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3187768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3197768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_remove(struct platform_device *pdev)
3207768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3217768a13c252a97e13a552f88f642962768de1fa4Komal Shah	struct resource *mem = platform_get_drvdata(pdev);
3227768a13c252a97e13a552f88f642962768de1fa4Komal Shah	misc_deregister(&omap_wdt_miscdev);
3237768a13c252a97e13a552f88f642962768de1fa4Komal Shah	release_resource(mem);
3247768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (armwdt_ck)
3257768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(armwdt_ck);
3267768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (mpu_wdt_ick)
3277768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_ick);
3287768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (mpu_wdt_fck)
3297768a13c252a97e13a552f88f642962768de1fa4Komal Shah		clk_put(mpu_wdt_fck);
3307768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return 0;
3317768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3327768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3337768a13c252a97e13a552f88f642962768de1fa4Komal Shah#ifdef	CONFIG_PM
3347768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3357768a13c252a97e13a552f88f642962768de1fa4Komal Shah/* REVISIT ... not clear this is the best way to handle system suspend; and
3367768a13c252a97e13a552f88f642962768de1fa4Komal Shah * it's very inappropriate for selective device suspend (e.g. suspending this
3377768a13c252a97e13a552f88f642962768de1fa4Komal Shah * through sysfs rather than by stopping the watchdog daemon).  Also, this
3387768a13c252a97e13a552f88f642962768de1fa4Komal Shah * may not play well enough with NOWAYOUT...
3397768a13c252a97e13a552f88f642962768de1fa4Komal Shah */
3407768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3417768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
3427768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3437768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (omap_wdt_users)
3447768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_disable();
3457768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return 0;
3467768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3477768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3487768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int omap_wdt_resume(struct platform_device *pdev)
3497768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3507768a13c252a97e13a552f88f642962768de1fa4Komal Shah	if (omap_wdt_users) {
3517768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_enable();
3527768a13c252a97e13a552f88f642962768de1fa4Komal Shah		omap_wdt_ping();
3537768a13c252a97e13a552f88f642962768de1fa4Komal Shah	}
3547768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return 0;
3557768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3567768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3577768a13c252a97e13a552f88f642962768de1fa4Komal Shah#else
3587768a13c252a97e13a552f88f642962768de1fa4Komal Shah#define	omap_wdt_suspend	NULL
3597768a13c252a97e13a552f88f642962768de1fa4Komal Shah#define	omap_wdt_resume		NULL
3607768a13c252a97e13a552f88f642962768de1fa4Komal Shah#endif
3617768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3627768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic struct platform_driver omap_wdt_driver = {
3637768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.probe		= omap_wdt_probe,
3647768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.remove		= omap_wdt_remove,
3657768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.shutdown	= omap_wdt_shutdown,
3667768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.suspend	= omap_wdt_suspend,
3677768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.resume		= omap_wdt_resume,
3687768a13c252a97e13a552f88f642962768de1fa4Komal Shah	.driver		= {
3697768a13c252a97e13a552f88f642962768de1fa4Komal Shah		.owner	= THIS_MODULE,
3707768a13c252a97e13a552f88f642962768de1fa4Komal Shah		.name	= "omap_wdt",
3717768a13c252a97e13a552f88f642962768de1fa4Komal Shah	},
3727768a13c252a97e13a552f88f642962768de1fa4Komal Shah};
3737768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3747768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic int __init omap_wdt_init(void)
3757768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3767768a13c252a97e13a552f88f642962768de1fa4Komal Shah	return platform_driver_register(&omap_wdt_driver);
3777768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3787768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3797768a13c252a97e13a552f88f642962768de1fa4Komal Shahstatic void __exit omap_wdt_exit(void)
3807768a13c252a97e13a552f88f642962768de1fa4Komal Shah{
3817768a13c252a97e13a552f88f642962768de1fa4Komal Shah	platform_driver_unregister(&omap_wdt_driver);
3827768a13c252a97e13a552f88f642962768de1fa4Komal Shah}
3837768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3847768a13c252a97e13a552f88f642962768de1fa4Komal Shahmodule_init(omap_wdt_init);
3857768a13c252a97e13a552f88f642962768de1fa4Komal Shahmodule_exit(omap_wdt_exit);
3867768a13c252a97e13a552f88f642962768de1fa4Komal Shah
3877768a13c252a97e13a552f88f642962768de1fa4Komal ShahMODULE_AUTHOR("George G. Davis");
3887768a13c252a97e13a552f88f642962768de1fa4Komal ShahMODULE_LICENSE("GPL");
3897768a13c252a97e13a552f88f642962768de1fa4Komal ShahMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
390f37d193c7c150c40059c7ce5de34e8b28a9cd4aeKay SieversMODULE_ALIAS("platform:omap_wdt");
391