diff options
Diffstat (limited to 'target/linux/brcm2708/patches-3.3/0003-bcm2708-watchdog-driver.patch')
-rw-r--r-- | target/linux/brcm2708/patches-3.3/0003-bcm2708-watchdog-driver.patch | 436 |
1 files changed, 0 insertions, 436 deletions
diff --git a/target/linux/brcm2708/patches-3.3/0003-bcm2708-watchdog-driver.patch b/target/linux/brcm2708/patches-3.3/0003-bcm2708-watchdog-driver.patch deleted file mode 100644 index cde3eef..0000000 --- a/target/linux/brcm2708/patches-3.3/0003-bcm2708-watchdog-driver.patch +++ /dev/null @@ -1,436 +0,0 @@ -From ed8c2d720954efc5a440912292ed11da2f50aaea Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 17 Jan 2012 19:20:57 +0000 -Subject: [PATCH 3/7] bcm2708 watchdog driver - -Signed-off-by: popcornmix <popcornmix@gmail.com> ---- - drivers/watchdog/Kconfig | 6 + - drivers/watchdog/Makefile | 1 + - drivers/watchdog/bcm2708_wdog.c | 385 +++++++++++++++++++++++++++++++++++++++ - 3 files changed, 392 insertions(+), 0 deletions(-) - create mode 100644 drivers/watchdog/bcm2708_wdog.c - -diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 86b0735..7675ebc 100644 ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -348,6 +348,12 @@ config IMX2_WDT - To compile this driver as a module, choose M here: the - module will be called imx2_wdt. - -+config BCM2708_WDT -+ tristate "BCM2708 Watchdog" -+ depends on ARCH_BCM2708 -+ help -+ Enables BCM2708 watchdog support. -+ - # AVR32 Architecture - - config AT32AP700X_WDT -diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index 55bd574..803f0bc 100644 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -54,6 +54,7 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o - obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o - obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o - obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o -+obj-$(CONFIG_BCM2708_WDT) += bcm2708_wdog.o - - # AVR32 Architecture - obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o -diff --git a/drivers/watchdog/bcm2708_wdog.c b/drivers/watchdog/bcm2708_wdog.c -new file mode 100644 -index 0000000..dd33c35 ---- /dev/null -+++ b/drivers/watchdog/bcm2708_wdog.c -@@ -0,0 +1,385 @@ -+/* -+ * Broadcom BCM2708 watchdog driver. -+ * -+ * (c) Copyright 2010 Broadcom Europe Ltd -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ * -+ * BCM2708 watchdog driver. Loosely based on wdt driver. -+ */ -+ -+#include <linux/interrupt.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/types.h> -+#include <linux/miscdevice.h> -+#include <linux/watchdog.h> -+#include <linux/fs.h> -+#include <linux/ioport.h> -+#include <linux/notifier.h> -+#include <linux/reboot.h> -+#include <linux/init.h> -+#include <linux/io.h> -+#include <linux/uaccess.h> -+#include <mach/platform.h> -+ -+#include <asm/system.h> -+ -+#define SECS_TO_WDOG_TICKS(x) ((x) << 16) -+#define WDOG_TICKS_TO_SECS(x) ((x) >> 16) -+ -+static unsigned long wdog_is_open; -+static uint32_t wdog_ticks; /* Ticks to load into wdog timer */ -+static char expect_close; -+ -+/* -+ * Module parameters -+ */ -+ -+#define WD_TIMO 10 /* Default heartbeat = 60 seconds */ -+static int heartbeat = WD_TIMO; /* Heartbeat in seconds */ -+ -+module_param(heartbeat, int, 0); -+MODULE_PARM_DESC(heartbeat, -+ "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default=" -+ __MODULE_STRING(WD_TIMO) ")"); -+ -+static int nowayout = WATCHDOG_NOWAYOUT; -+module_param(nowayout, int, 0); -+MODULE_PARM_DESC(nowayout, -+ "Watchdog cannot be stopped once started (default=" -+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -+ -+static DEFINE_SPINLOCK(wdog_lock); -+ -+/** -+ * Start the watchdog driver. -+ */ -+ -+static int wdog_start(unsigned long timeout) -+{ -+ uint32_t cur; -+ unsigned long flags; -+ spin_lock_irqsave(&wdog_lock, flags); -+ -+ /* enable the watchdog */ -+ iowrite32(PM_PASSWORD | (timeout & PM_WDOG_TIME_SET), -+ __io_address(PM_WDOG)); -+ cur = ioread32(__io_address(PM_RSTC)); -+ iowrite32(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | -+ PM_RSTC_WRCFG_FULL_RESET, __io_address(PM_RSTC)); -+ -+ spin_unlock_irqrestore(&wdog_lock, flags); -+ return 0; -+} -+ -+/** -+ * Stop the watchdog driver. -+ */ -+ -+static int wdog_stop(void) -+{ -+ iowrite32(PM_PASSWORD | PM_RSTC_RESET, __io_address(PM_RSTC)); -+ printk(KERN_INFO "watchdog stopped\n"); -+ return 0; -+} -+ -+/** -+ * Reload counter one with the watchdog heartbeat. We don't bother -+ * reloading the cascade counter. -+ */ -+ -+static void wdog_ping(void) -+{ -+ wdog_start(wdog_ticks); -+} -+ -+/** -+ * @t: the new heartbeat value that needs to be set. -+ * -+ * Set a new heartbeat value for the watchdog device. If the heartbeat -+ * value is incorrect we keep the old value and return -EINVAL. If -+ * successful we return 0. -+ */ -+ -+static int wdog_set_heartbeat(int t) -+{ -+ if (t < 1 || t > WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET)) -+ return -EINVAL; -+ -+ heartbeat = t; -+ wdog_ticks = SECS_TO_WDOG_TICKS(t); -+ return 0; -+} -+ -+/** -+ * @file: file handle to the watchdog -+ * @buf: buffer to write (unused as data does not matter here -+ * @count: count of bytes -+ * @ppos: pointer to the position to write. No seeks allowed -+ * -+ * A write to a watchdog device is defined as a keepalive signal. -+ * -+ * if 'nowayout' is set then normally a close() is ignored. But -+ * if you write 'V' first then the close() will stop the timer. -+ */ -+ -+static ssize_t wdog_write(struct file *file, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ if (count) { -+ if (!nowayout) { -+ size_t i; -+ -+ /* In case it was set long ago */ -+ expect_close = 0; -+ -+ for (i = 0; i != count; i++) { -+ char c; -+ if (get_user(c, buf + i)) -+ return -EFAULT; -+ if (c == 'V') -+ expect_close = 42; -+ } -+ } -+ wdog_ping(); -+ } -+ return count; -+} -+ -+static int wdog_get_status(void) -+{ -+ unsigned long flags; -+ int status = 0; -+ spin_lock_irqsave(&wdog_lock, flags); -+ /* FIXME: readback reset reason */ -+ spin_unlock_irqrestore(&wdog_lock, flags); -+ return status; -+} -+ -+static uint32_t wdog_get_remaining(void) -+{ -+ uint32_t ret = ioread32(__io_address(PM_WDOG)); -+ return ret & PM_WDOG_TIME_SET; -+} -+ -+/** -+ * @file: file handle to the device -+ * @cmd: watchdog command -+ * @arg: argument pointer -+ * -+ * The watchdog API defines a common set of functions for all watchdogs -+ * according to their available features. We only actually usefully support -+ * querying capabilities and current status. -+ */ -+ -+static long wdog_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = argp; -+ int new_heartbeat; -+ int status; -+ int options; -+ uint32_t remaining; -+ -+ struct watchdog_info ident = { -+ .options = WDIOF_SETTIMEOUT| -+ WDIOF_MAGICCLOSE| -+ WDIOF_KEEPALIVEPING, -+ .firmware_version = 1, -+ .identity = "BCM2708", -+ }; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; -+ case WDIOC_GETSTATUS: -+ status = wdog_get_status(); -+ return put_user(status, p); -+ case WDIOC_GETBOOTSTATUS: -+ return put_user(0, p); -+ case WDIOC_KEEPALIVE: -+ wdog_ping(); -+ return 0; -+ case WDIOC_SETTIMEOUT: -+ if (get_user(new_heartbeat, p)) -+ return -EFAULT; -+ if (wdog_set_heartbeat(new_heartbeat)) -+ return -EINVAL; -+ wdog_ping(); -+ /* Fall */ -+ case WDIOC_GETTIMEOUT: -+ return put_user(heartbeat, p); -+ case WDIOC_GETTIMELEFT: -+ remaining = WDOG_TICKS_TO_SECS(wdog_get_remaining()); -+ return put_user(remaining, p); -+ case WDIOC_SETOPTIONS: -+ if (get_user(options, p)) -+ return -EFAULT; -+ if (options & WDIOS_DISABLECARD) -+ wdog_stop(); -+ if (options & WDIOS_ENABLECARD) -+ wdog_start(wdog_ticks); -+ return 0; -+ default: -+ return -ENOTTY; -+ } -+} -+ -+/** -+ * @inode: inode of device -+ * @file: file handle to device -+ * -+ * The watchdog device has been opened. The watchdog device is single -+ * open and on opening we load the counters. -+ */ -+ -+static int wdog_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(0, &wdog_is_open)) -+ return -EBUSY; -+ /* -+ * Activate -+ */ -+ wdog_start(wdog_ticks); -+ return nonseekable_open(inode, file); -+} -+ -+/** -+ * @inode: inode to board -+ * @file: file handle to board -+ * -+ * The watchdog has a configurable API. There is a religious dispute -+ * between people who want their watchdog to be able to shut down and -+ * those who want to be sure if the watchdog manager dies the machine -+ * reboots. In the former case we disable the counters, in the latter -+ * case you have to open it again very soon. -+ */ -+ -+static int wdog_release(struct inode *inode, struct file *file) -+{ -+ if (expect_close == 42) { -+ wdog_stop(); -+ } else { -+ printk(KERN_CRIT -+ "wdt: WDT device closed unexpectedly. WDT will not stop!\n"); -+ wdog_ping(); -+ } -+ clear_bit(0, &wdog_is_open); -+ expect_close = 0; -+ return 0; -+} -+ -+/** -+ * @this: our notifier block -+ * @code: the event being reported -+ * @unused: unused -+ * -+ * Our notifier is called on system shutdowns. Turn the watchdog -+ * off so that it does not fire during the next reboot. -+ */ -+ -+static int wdog_notify_sys(struct notifier_block *this, unsigned long code, -+ void *unused) -+{ -+ if (code == SYS_DOWN || code == SYS_HALT) -+ wdog_stop(); -+ return NOTIFY_DONE; -+} -+ -+/* -+ * Kernel Interfaces -+ */ -+ -+ -+static const struct file_operations wdog_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .write = wdog_write, -+ .unlocked_ioctl = wdog_ioctl, -+ .open = wdog_open, -+ .release = wdog_release, -+}; -+ -+static struct miscdevice wdog_miscdev = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &wdog_fops, -+}; -+ -+/* -+ * The WDT card needs to learn about soft shutdowns in order to -+ * turn the timebomb registers off. -+ */ -+ -+static struct notifier_block wdog_notifier = { -+ .notifier_call = wdog_notify_sys, -+}; -+ -+/** -+ * cleanup_module: -+ * -+ * Unload the watchdog. You cannot do this with any file handles open. -+ * If your watchdog is set to continue ticking on close and you unload -+ * it, well it keeps ticking. We won't get the interrupt but the board -+ * will not touch PC memory so all is fine. You just have to load a new -+ * module in 60 seconds or reboot. -+ */ -+ -+static void __exit wdog_exit(void) -+{ -+ misc_deregister(&wdog_miscdev); -+ unregister_reboot_notifier(&wdog_notifier); -+} -+ -+static int __init wdog_init(void) -+{ -+ int ret; -+ -+ /* Check that the heartbeat value is within it's range; -+ if not reset to the default */ -+ if (wdog_set_heartbeat(heartbeat)) { -+ wdog_set_heartbeat(WD_TIMO); -+ printk(KERN_INFO "bcm2708_wdog: heartbeat value must be " -+ "0 < heartbeat < %d, using %d\n", -+ WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), -+ WD_TIMO); -+ } -+ -+ ret = register_reboot_notifier(&wdog_notifier); -+ if (ret) { -+ printk(KERN_ERR -+ "wdt: cannot register reboot notifier (err=%d)\n", ret); -+ goto out_reboot; -+ } -+ -+ ret = misc_register(&wdog_miscdev); -+ if (ret) { -+ printk(KERN_ERR -+ "wdt: cannot register miscdev on minor=%d (err=%d)\n", -+ WATCHDOG_MINOR, ret); -+ goto out_misc; -+ } -+ -+ printk(KERN_INFO "bcm2708 watchdog, heartbeat=%d sec (nowayout=%d)\n", -+ heartbeat, nowayout); -+ return 0; -+ -+out_misc: -+ unregister_reboot_notifier(&wdog_notifier); -+out_reboot: -+ return ret; -+} -+ -+module_init(wdog_init); -+module_exit(wdog_exit); -+ -+MODULE_AUTHOR("Luke Diamand"); -+MODULE_DESCRIPTION("Driver for BCM2708 watchdog"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -+MODULE_ALIAS_MISCDEV(TEMP_MINOR); -+MODULE_LICENSE("GPL"); -+ --- -1.7.5.4 - |