13268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch/* 2cda61c9420028ddd251b60f1445c9eed756991c7Martyn Welch * GE watchdog userspace interface 33268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 4cda61c9420028ddd251b60f1445c9eed756991c7Martyn Welch * Author: Martyn Welch <martyn.welch@ge.com> 53268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 6cda61c9420028ddd251b60f1445c9eed756991c7Martyn Welch * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. 73268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 83268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * This program is free software; you can redistribute it and/or modify it 93268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * under the terms of the GNU General Public License as published by the 103268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * Free Software Foundation; either version 2 of the License, or (at your 113268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * option) any later version. 123268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 133268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * Based on: mv64x60_wdt.c (MV64X60 watchdog userspace interface) 143268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * Author: James Chapman <jchapman@katalix.com> 153268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch */ 163268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 173268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch/* TODO: 183268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * This driver does not provide support for the hardwares capability of sending 193268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * an interrupt at a programmable threshold. 203268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 213268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * This driver currently can only support 1 watchdog - there are 2 in the 223268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * hardware that this driver supports. Thus one could be configured as a 233268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * process-based watchdog (via /dev/watchdog), the second (using the interrupt 243268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * capabilities) a kernel-based watchdog. 253268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch */ 263268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2727c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 2827c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches 293268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/kernel.h> 303268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/compiler.h> 313268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/init.h> 323268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/module.h> 333268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/miscdevice.h> 343268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/watchdog.h> 35f6e0722fc3a35ff818c86ffbc414f7592a8119cfWolfram Sang & Martyn Welch <w.sang@pengutronix.de,#include <linux/fs.h> 363268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/of.h> 375af5073004071cedd0343eee51d77955037ec6f3Rob Herring#include <linux/of_address.h> 383268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/of_platform.h> 393268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/io.h> 403268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <linux/uaccess.h> 413268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 423268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#include <sysdev/fsl_soc.h> 433268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 443268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch/* 453268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * The watchdog configuration register contains a pair of 2-bit fields, 463268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 1. a reload field, bits 27-26, which triggers a reload of 473268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * the countdown register, and 483268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 2. an enable field, bits 25-24, which toggles between 493268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * enabling and disabling the watchdog timer. 503268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * Bit 31 is a read-only field which indicates whether the 513268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * watchdog timer is currently enabled. 523268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * 533268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch * The low 24 bits contain the timer reload value. 543268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch */ 553268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDC_ENABLE_SHIFT 24 563268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDC_SERVICE_SHIFT 26 573268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDC_ENABLED_SHIFT 31 583268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 593268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDC_ENABLED_TRUE 1 603268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDC_ENABLED_FALSE 0 613268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 623268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch/* Flags bits */ 633268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch#define GEF_WDOG_FLAG_OPENED 0 643268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 653268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic unsigned long wdt_flags; 663268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int wdt_status; 673268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void __iomem *gef_wdt_regs; 683268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int gef_wdt_timeout; 693268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int gef_wdt_count; 703268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic unsigned int bus_clk; 713268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic char expect_close; 723268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic DEFINE_SPINLOCK(gef_wdt_spinlock); 733268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 7486a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT; 7586a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0); 763268b5618f387c6b78b8f8b1190d43380c8170acMartyn WelchMODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 773268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 783268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 793268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 803268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int gef_wdt_toggle_wdc(int enabled_predicate, int field_shift) 813268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 823268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch u32 data; 833268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch u32 enabled; 843268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch int ret = 0; 853268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 863268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch spin_lock(&gef_wdt_spinlock); 873268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch data = ioread32be(gef_wdt_regs); 883268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch enabled = (data >> GEF_WDC_ENABLED_SHIFT) & 1; 893268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 903268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* only toggle the requested field if enabled state matches predicate */ 913268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if ((enabled ^ enabled_predicate) == 0) { 923268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* We write a 1, then a 2 -- to the appropriate field */ 933268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch data = (1 << field_shift) | gef_wdt_count; 943268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch iowrite32be(data, gef_wdt_regs); 953268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 963268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch data = (2 << field_shift) | gef_wdt_count; 973268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch iowrite32be(data, gef_wdt_regs); 983268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch ret = 1; 993268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 1003268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch spin_unlock(&gef_wdt_spinlock); 1013268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1023268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return ret; 1033268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1043268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1053268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void gef_wdt_service(void) 1063268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1073268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE, 1083268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch GEF_WDC_SERVICE_SHIFT); 1093268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1103268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1113268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void gef_wdt_handler_enable(void) 1123268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1133268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE, 1143268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch GEF_WDC_ENABLE_SHIFT)) { 1153268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_service(); 11627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_notice("watchdog activated\n"); 1173268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 1183268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1193268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1203268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void gef_wdt_handler_disable(void) 1213268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1223268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE, 1233268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch GEF_WDC_ENABLE_SHIFT)) 12427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_notice("watchdog deactivated\n"); 1253268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1263268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1273268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void gef_wdt_set_timeout(unsigned int timeout) 1283268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1293268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* maximum bus cycle count is 0xFFFFFFFF */ 1303268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (timeout > 0xFFFFFFFF / bus_clk) 1313268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch timeout = 0xFFFFFFFF / bus_clk; 1323268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1333268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* Register only holds upper 24 bits, bit shifted into lower 24 */ 1343268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_count = (timeout * bus_clk) >> 8; 1353268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_timeout = timeout; 1363268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1373268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1383268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1393268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic ssize_t gef_wdt_write(struct file *file, const char __user *data, 1403268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch size_t len, loff_t *ppos) 1413268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1423268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (len) { 1433268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (!nowayout) { 1443268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch size_t i; 1453268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1463268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch expect_close = 0; 1473268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1483268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch for (i = 0; i != len; i++) { 1493268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch char c; 1503268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (get_user(c, data + i)) 1513268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 1523268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (c == 'V') 1533268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch expect_close = 42; 1543268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 1553268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 1563268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_service(); 1573268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 1583268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1593268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return len; 1603268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 1613268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1623268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic long gef_wdt_ioctl(struct file *file, unsigned int cmd, 1633268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch unsigned long arg) 1643268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 1653268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch int timeout; 1663268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch int options; 1673268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch void __user *argp = (void __user *)arg; 16842747d712de56cf2087b702d2ad90af114c53138Wim Van Sebroeck static const struct watchdog_info info = { 1693268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | 1703268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch WDIOF_KEEPALIVEPING, 1713268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .firmware_version = 0, 172cda61c9420028ddd251b60f1445c9eed756991c7Martyn Welch .identity = "GE watchdog", 1733268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch }; 1743268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1753268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch switch (cmd) { 1763268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_GETSUPPORT: 1773268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (copy_to_user(argp, &info, sizeof(info))) 1783268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 1793268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch break; 1803268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1813268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_GETSTATUS: 1823268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_GETBOOTSTATUS: 1833268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (put_user(wdt_status, (int __user *)argp)) 1843268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 1853268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch wdt_status &= ~WDIOF_KEEPALIVEPING; 1863268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch break; 1873268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1883268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_SETOPTIONS: 1893268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (get_user(options, (int __user *)argp)) 1903268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 1913268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1923268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (options & WDIOS_DISABLECARD) 1933268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_disable(); 1943268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1953268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (options & WDIOS_ENABLECARD) 1963268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_enable(); 1973268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch break; 1983268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 1993268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_KEEPALIVE: 2003268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_service(); 2013268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch wdt_status |= WDIOF_KEEPALIVEPING; 2023268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch break; 2033268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2043268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_SETTIMEOUT: 2053268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (get_user(timeout, (int __user *)argp)) 2063268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 2073268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_set_timeout(timeout); 2083268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* Fall through */ 2093268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2103268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch case WDIOC_GETTIMEOUT: 2113268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (put_user(gef_wdt_timeout, (int __user *)argp)) 2123268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EFAULT; 2133268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch break; 2143268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2153268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch default: 2163268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -ENOTTY; 2173268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 2183268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2193268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return 0; 2203268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 2213268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2223268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int gef_wdt_open(struct inode *inode, struct file *file) 2233268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 2243268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (test_and_set_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags)) 2253268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -EBUSY; 2263268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2273268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (nowayout) 2283268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch __module_get(THIS_MODULE); 2293268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2303268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_enable(); 2313268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2323268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return nonseekable_open(inode, file); 2333268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 2343268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2353268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int gef_wdt_release(struct inode *inode, struct file *file) 2363268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 2373268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (expect_close == 42) 2383268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_disable(); 2393268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch else { 24027c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_crit("unexpected close, not stopping timer!\n"); 2413268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_service(); 2423268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch } 2433268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch expect_close = 0; 2443268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2453268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch clear_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags); 2463268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2473268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return 0; 2483268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 2493268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2503268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic const struct file_operations gef_wdt_fops = { 2513268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .owner = THIS_MODULE, 2523268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .llseek = no_llseek, 2533268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .write = gef_wdt_write, 2543268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .unlocked_ioctl = gef_wdt_ioctl, 2553268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .open = gef_wdt_open, 2563268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .release = gef_wdt_release, 2573268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch}; 2583268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2593268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic struct miscdevice gef_wdt_miscdev = { 2603268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .minor = WATCHDOG_MINOR, 2613268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .name = "watchdog", 2623268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .fops = &gef_wdt_fops, 2633268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch}; 2643268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2653268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2662d991a164a61858012651e13c59521975504e260Bill Pembertonstatic int gef_wdt_probe(struct platform_device *dev) 2673268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 2683268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch int timeout = 10; 2693268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch u32 freq; 2703268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2713268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch bus_clk = 133; /* in MHz */ 2723268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2733268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch freq = fsl_get_sys_freq(); 27426952669f01646c3e7d0832c99b310b199fe2b20Roel Kluin if (freq != -1) 2753268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch bus_clk = freq; 2763268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2773268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch /* Map devices registers into memory */ 278b74dbf2aed8d8c4f93ac2c44bab5c81f65be62a0Anatolij Gustschin gef_wdt_regs = of_iomap(dev->dev.of_node, 0); 2793268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch if (gef_wdt_regs == NULL) 2803268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return -ENOMEM; 2813268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2823268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_set_timeout(timeout); 2833268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2843268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_disable(); /* in case timer was already running */ 2853268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2863268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return misc_register(&gef_wdt_miscdev); 2873268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 2883268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2894b12b896c27c3b54592816606679f5b02f638930Bill Pembertonstatic int gef_wdt_remove(struct platform_device *dev) 2903268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 2913268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch misc_deregister(&gef_wdt_miscdev); 2923268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2933268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch gef_wdt_handler_disable(); 2943268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2953268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch iounmap(gef_wdt_regs); 2963268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 2973268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch return 0; 2983268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 2993268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 3003268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic const struct of_device_id gef_wdt_ids[] = { 3013268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch { 3023268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .compatible = "gef,fpga-wdt", 3033268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch }, 3043268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch {}, 3053268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch}; 3063268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 3071c48a5c93da63132b92c4bbcd18e690c51539df6Grant Likelystatic struct platform_driver gef_wdt_driver = { 3084018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .driver = { 3094018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .name = "gef_wdt", 3104018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .owner = THIS_MODULE, 3114018294b53d1dae026880e45f174c1cc63b5d435Grant Likely .of_match_table = gef_wdt_ids, 3124018294b53d1dae026880e45f174c1cc63b5d435Grant Likely }, 3133268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch .probe = gef_wdt_probe, 3146737176569d1d6356c644694d60ea2b265cb3870Devendra Naga .remove = gef_wdt_remove, 3153268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch}; 3163268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 3173268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic int __init gef_wdt_init(void) 3183268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 31927c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("GE watchdog driver\n"); 3201c48a5c93da63132b92c4bbcd18e690c51539df6Grant Likely return platform_driver_register(&gef_wdt_driver); 3213268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 3223268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 3233268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchstatic void __exit gef_wdt_exit(void) 3243268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch{ 3251c48a5c93da63132b92c4bbcd18e690c51539df6Grant Likely platform_driver_unregister(&gef_wdt_driver); 3263268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch} 3273268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 3283268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchmodule_init(gef_wdt_init); 3293268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welchmodule_exit(gef_wdt_exit); 3303268b5618f387c6b78b8f8b1190d43380c8170acMartyn Welch 331cda61c9420028ddd251b60f1445c9eed756991c7Martyn WelchMODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com>"); 332cda61c9420028ddd251b60f1445c9eed756991c7Martyn WelchMODULE_DESCRIPTION("GE watchdog driver"); 3333268b5618f387c6b78b8f8b1190d43380c8170acMartyn WelchMODULE_LICENSE("GPL"); 334ae2a00607463ceb647ada550d7f34ba33177ef38Axel LinMODULE_ALIAS("platform:gef_wdt"); 335