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