[go: nahoru, domu]

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