From: Felix Fietkau Date: Thu, 12 May 2016 16:10:08 +0000 (+0200) Subject: kernel: move the old gpio watchdog driver from generic to brcm47xx X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fstaging%2Fyousong.git;a=commitdiff_plain;h=05459a004a7e96c54123f5816fc15408df9b9f53 kernel: move the old gpio watchdog driver from generic to brcm47xx brcm47xx is the only user Signed-off-by: Felix Fietkau --- diff --git a/target/linux/brcm47xx/patches-4.1/831-old_gpio_wdt.patch b/target/linux/brcm47xx/patches-4.1/831-old_gpio_wdt.patch new file mode 100644 index 0000000000..9f5e7faf00 --- /dev/null +++ b/target/linux/brcm47xx/patches-4.1/831-old_gpio_wdt.patch @@ -0,0 +1,360 @@ +This generic GPIO watchdog is used on Huawei E970 (brcm47xx) + +Signed-off-by: Mathias Adam + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1150,6 +1150,15 @@ config WDT_MTX1 + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + ++config GPIO_WDT ++ tristate "GPIO Hardware Watchdog" ++ help ++ Hardware driver for GPIO-controlled watchdogs. GPIO pin and ++ toggle interval settings are platform-specific. The driver ++ will stop toggling the GPIO (i.e. machine reboots) after a ++ 100 second timer expired and no process has written to ++ /dev/watchdog during that time. ++ + config PNX833X_WDT + tristate "PNX833x Hardware Watchdog" + depends on SOC_PNX8335 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -135,6 +135,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o ++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +--- /dev/null ++++ b/drivers/watchdog/old_gpio_wdt.c +@@ -0,0 +1,301 @@ ++/* ++ * Driver for GPIO-controlled Hardware Watchdogs. ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): ++ * ++ * (C) Copyright 2005 4G Systems , ++ * All Rights Reserved. ++ * http://www.4g-systems.biz ++ * ++ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli ++ * ++ * 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. ++ * ++ * Neither Michael Stickel nor 4G Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 2005 4G Systems ++ * ++ * Release 0.01. ++ * Author: Michael Stickel michael.stickel@4g-systems.biz ++ * ++ * Release 0.02. ++ * Author: Florian Fainelli florian@openwrt.org ++ * use the Linux watchdog/timer APIs ++ * ++ * Release 0.03. ++ * Author: Mathias Adam ++ * make it a generic gpio watchdog driver ++ * ++ * The Watchdog is configured to reset the MTX-1 ++ * if it is not triggered for 100 seconds. ++ * It should not be triggered more often than 1.6 seconds. ++ * ++ * A timer triggers the watchdog every 5 seconds, until ++ * it is opened for the first time. After the first open ++ * it MUST be triggered every 2..95 seconds. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ticks = 100 * HZ; ++ ++static struct { ++ struct completion stop; ++ spinlock_t lock; ++ int running; ++ struct timer_list timer; ++ int queue; ++ int default_ticks; ++ unsigned long inuse; ++ unsigned gpio; ++ unsigned int gstate; ++ int interval; ++ int first_interval; ++} gpio_wdt_device; ++ ++static void gpio_wdt_trigger(unsigned long unused) ++{ ++ spin_lock(&gpio_wdt_device.lock); ++ if (gpio_wdt_device.running && ticks > 0) ++ ticks -= gpio_wdt_device.interval; ++ ++ /* toggle wdt gpio */ ++ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; ++ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); ++ ++ if (gpio_wdt_device.queue && ticks > 0) ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); ++ else ++ complete(&gpio_wdt_device.stop); ++ spin_unlock(&gpio_wdt_device.lock); ++} ++ ++static void gpio_wdt_reset(void) ++{ ++ ticks = gpio_wdt_device.default_ticks; ++} ++ ++ ++static void gpio_wdt_start(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (!gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 1; ++ gpio_wdt_device.gstate = 1; ++ gpio_set_value(gpio_wdt_device.gpio, 1); ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); ++ } ++ gpio_wdt_device.running++; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++} ++ ++static int gpio_wdt_stop(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ gpio_wdt_device.gstate = 0; ++ gpio_set_value(gpio_wdt_device.gpio, 0); ++ } ++ ticks = gpio_wdt_device.default_ticks; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++ return 0; ++} ++ ++/* Filesystem functions */ ++ ++static int gpio_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++ ++static int gpio_wdt_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &gpio_wdt_device.inuse); ++ return 0; ++} ++ ++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = (int __user *)argp; ++ unsigned int value; ++ static const struct watchdog_info ident = { ++ .options = WDIOF_CARDRESET, ++ .identity = "GPIO WDT", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user(argp, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ put_user(0, p); ++ break; ++ case WDIOC_SETOPTIONS: ++ if (get_user(value, p)) ++ return -EFAULT; ++ if (value & WDIOS_ENABLECARD) ++ gpio_wdt_start(); ++ else if (value & WDIOS_DISABLECARD) ++ gpio_wdt_stop(); ++ else ++ return -EINVAL; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ gpio_wdt_reset(); ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++ ++static ssize_t gpio_wdt_write(struct file *file, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (!count) ++ return -EIO; ++ gpio_wdt_reset(); ++ return count; ++} ++ ++static const struct file_operations gpio_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = gpio_wdt_ioctl, ++ .open = gpio_wdt_open, ++ .write = gpio_wdt_write, ++ .release = gpio_wdt_release, ++}; ++ ++ ++static struct miscdevice gpio_wdt_misc = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &gpio_wdt_fops, ++}; ++ ++ ++static int gpio_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; ++ ++ gpio_wdt_device.gpio = gpio_wdt_data->gpio; ++ gpio_wdt_device.interval = gpio_wdt_data->interval; ++ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; ++ if (gpio_wdt_device.first_interval <= 0) { ++ gpio_wdt_device.first_interval = gpio_wdt_device.interval; ++ } ++ ++ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio"); ++ return ret; ++ } ++ ++ spin_lock_init(&gpio_wdt_device.lock); ++ init_completion(&gpio_wdt_device.stop); ++ gpio_wdt_device.queue = 0; ++ clear_bit(0, &gpio_wdt_device.inuse); ++ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); ++ gpio_wdt_device.default_ticks = ticks; ++ ++ gpio_wdt_start(); ++ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", ++ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); ++ return 0; ++} ++ ++static int gpio_wdt_remove(struct platform_device *pdev) ++{ ++ /* FIXME: do we need to lock this test ? */ ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ wait_for_completion(&gpio_wdt_device.stop); ++ } ++ ++ gpio_free(gpio_wdt_device.gpio); ++ misc_deregister(&gpio_wdt_misc); ++ return 0; ++} ++ ++static struct platform_driver gpio_wdt_driver = { ++ .probe = gpio_wdt_probe, ++ .remove = gpio_wdt_remove, ++ .driver.name = "gpio-wdt", ++ .driver.owner = THIS_MODULE, ++}; ++ ++static int __init gpio_wdt_init(void) ++{ ++ return platform_driver_register(&gpio_wdt_driver); ++} ++arch_initcall(gpio_wdt_init); ++ ++/* ++ * We do wdt initialization in two steps: arch_initcall probes the wdt ++ * very early to start pinging the watchdog (misc devices are not yet ++ * available), and later module_init() just registers the misc device. ++ */ ++static int gpio_wdt_init_late(void) ++{ ++ int ret; ++ ++ ret = misc_register(&gpio_wdt_misc); ++ if (ret < 0) { ++ pr_err("GPIO_WDT: failed to register misc device\n"); ++ return ret; ++ } ++ return 0; ++} ++#ifndef MODULE ++module_init(gpio_wdt_init_late); ++#endif ++ ++static void __exit gpio_wdt_exit(void) ++{ ++ platform_driver_unregister(&gpio_wdt_driver); ++} ++module_exit(gpio_wdt_exit); ++ ++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); ++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gpio-wdt"); +--- /dev/null ++++ b/include/linux/old_gpio_wdt.h +@@ -0,0 +1,21 @@ ++/* ++ * Definitions for the GPIO watchdog driver ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _GPIO_WDT_H_ ++#define _GPIO_WDT_H_ ++ ++struct gpio_wdt_platform_data { ++ int gpio; /* GPIO line number */ ++ int interval; /* watchdog reset interval in system ticks */ ++ int first_interval; /* first wd reset interval in system ticks */ ++}; ++ ++#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/brcm47xx/patches-4.4/831-old_gpio_wdt.patch b/target/linux/brcm47xx/patches-4.4/831-old_gpio_wdt.patch new file mode 100644 index 0000000000..5856a5c50e --- /dev/null +++ b/target/linux/brcm47xx/patches-4.4/831-old_gpio_wdt.patch @@ -0,0 +1,360 @@ +This generic GPIO watchdog is used on Huawei E970 (brcm47xx) + +Signed-off-by: Mathias Adam + +--- a/drivers/watchdog/Kconfig ++++ b/drivers/watchdog/Kconfig +@@ -1216,6 +1216,15 @@ config WDT_MTX1 + Hardware driver for the MTX-1 boards. This is a watchdog timer that + will reboot the machine after a 100 seconds timer expired. + ++config GPIO_WDT ++ tristate "GPIO Hardware Watchdog" ++ help ++ Hardware driver for GPIO-controlled watchdogs. GPIO pin and ++ toggle interval settings are platform-specific. The driver ++ will stop toggling the GPIO (i.e. machine reboots) after a ++ 100 second timer expired and no process has written to ++ /dev/watchdog during that time. ++ + config PNX833X_WDT + tristate "PNX833x Hardware Watchdog" + depends on SOC_PNX8335 +--- a/drivers/watchdog/Makefile ++++ b/drivers/watchdog/Makefile +@@ -140,6 +140,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt + obj-$(CONFIG_INDYDOG) += indydog.o + obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o + obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o ++obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o + obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o + obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o + obj-$(CONFIG_AR7_WDT) += ar7_wdt.o +--- /dev/null ++++ b/drivers/watchdog/old_gpio_wdt.c +@@ -0,0 +1,301 @@ ++/* ++ * Driver for GPIO-controlled Hardware Watchdogs. ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): ++ * ++ * (C) Copyright 2005 4G Systems , ++ * All Rights Reserved. ++ * http://www.4g-systems.biz ++ * ++ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli ++ * ++ * 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. ++ * ++ * Neither Michael Stickel nor 4G Systems admit liability nor provide ++ * warranty for any of this software. This material is provided ++ * "AS-IS" and at no charge. ++ * ++ * (c) Copyright 2005 4G Systems ++ * ++ * Release 0.01. ++ * Author: Michael Stickel michael.stickel@4g-systems.biz ++ * ++ * Release 0.02. ++ * Author: Florian Fainelli florian@openwrt.org ++ * use the Linux watchdog/timer APIs ++ * ++ * Release 0.03. ++ * Author: Mathias Adam ++ * make it a generic gpio watchdog driver ++ * ++ * The Watchdog is configured to reset the MTX-1 ++ * if it is not triggered for 100 seconds. ++ * It should not be triggered more often than 1.6 seconds. ++ * ++ * A timer triggers the watchdog every 5 seconds, until ++ * it is opened for the first time. After the first open ++ * it MUST be triggered every 2..95 seconds. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ticks = 100 * HZ; ++ ++static struct { ++ struct completion stop; ++ spinlock_t lock; ++ int running; ++ struct timer_list timer; ++ int queue; ++ int default_ticks; ++ unsigned long inuse; ++ unsigned gpio; ++ unsigned int gstate; ++ int interval; ++ int first_interval; ++} gpio_wdt_device; ++ ++static void gpio_wdt_trigger(unsigned long unused) ++{ ++ spin_lock(&gpio_wdt_device.lock); ++ if (gpio_wdt_device.running && ticks > 0) ++ ticks -= gpio_wdt_device.interval; ++ ++ /* toggle wdt gpio */ ++ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; ++ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); ++ ++ if (gpio_wdt_device.queue && ticks > 0) ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); ++ else ++ complete(&gpio_wdt_device.stop); ++ spin_unlock(&gpio_wdt_device.lock); ++} ++ ++static void gpio_wdt_reset(void) ++{ ++ ticks = gpio_wdt_device.default_ticks; ++} ++ ++ ++static void gpio_wdt_start(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (!gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 1; ++ gpio_wdt_device.gstate = 1; ++ gpio_set_value(gpio_wdt_device.gpio, 1); ++ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); ++ } ++ gpio_wdt_device.running++; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++} ++ ++static int gpio_wdt_stop(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&gpio_wdt_device.lock, flags); ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ gpio_wdt_device.gstate = 0; ++ gpio_set_value(gpio_wdt_device.gpio, 0); ++ } ++ ticks = gpio_wdt_device.default_ticks; ++ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); ++ return 0; ++} ++ ++/* Filesystem functions */ ++ ++static int gpio_wdt_open(struct inode *inode, struct file *file) ++{ ++ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) ++ return -EBUSY; ++ return nonseekable_open(inode, file); ++} ++ ++ ++static int gpio_wdt_release(struct inode *inode, struct file *file) ++{ ++ clear_bit(0, &gpio_wdt_device.inuse); ++ return 0; ++} ++ ++static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, ++ unsigned long arg) ++{ ++ void __user *argp = (void __user *)arg; ++ int __user *p = (int __user *)argp; ++ unsigned int value; ++ static const struct watchdog_info ident = { ++ .options = WDIOF_CARDRESET, ++ .identity = "GPIO WDT", ++ }; ++ ++ switch (cmd) { ++ case WDIOC_GETSUPPORT: ++ if (copy_to_user(argp, &ident, sizeof(ident))) ++ return -EFAULT; ++ break; ++ case WDIOC_GETSTATUS: ++ case WDIOC_GETBOOTSTATUS: ++ put_user(0, p); ++ break; ++ case WDIOC_SETOPTIONS: ++ if (get_user(value, p)) ++ return -EFAULT; ++ if (value & WDIOS_ENABLECARD) ++ gpio_wdt_start(); ++ else if (value & WDIOS_DISABLECARD) ++ gpio_wdt_stop(); ++ else ++ return -EINVAL; ++ return 0; ++ case WDIOC_KEEPALIVE: ++ gpio_wdt_reset(); ++ break; ++ default: ++ return -ENOTTY; ++ } ++ return 0; ++} ++ ++ ++static ssize_t gpio_wdt_write(struct file *file, const char *buf, ++ size_t count, loff_t *ppos) ++{ ++ if (!count) ++ return -EIO; ++ gpio_wdt_reset(); ++ return count; ++} ++ ++static const struct file_operations gpio_wdt_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .unlocked_ioctl = gpio_wdt_ioctl, ++ .open = gpio_wdt_open, ++ .write = gpio_wdt_write, ++ .release = gpio_wdt_release, ++}; ++ ++ ++static struct miscdevice gpio_wdt_misc = { ++ .minor = WATCHDOG_MINOR, ++ .name = "watchdog", ++ .fops = &gpio_wdt_fops, ++}; ++ ++ ++static int gpio_wdt_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; ++ ++ gpio_wdt_device.gpio = gpio_wdt_data->gpio; ++ gpio_wdt_device.interval = gpio_wdt_data->interval; ++ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; ++ if (gpio_wdt_device.first_interval <= 0) { ++ gpio_wdt_device.first_interval = gpio_wdt_device.interval; ++ } ++ ++ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); ++ if (ret < 0) { ++ dev_err(&pdev->dev, "failed to request gpio"); ++ return ret; ++ } ++ ++ spin_lock_init(&gpio_wdt_device.lock); ++ init_completion(&gpio_wdt_device.stop); ++ gpio_wdt_device.queue = 0; ++ clear_bit(0, &gpio_wdt_device.inuse); ++ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); ++ gpio_wdt_device.default_ticks = ticks; ++ ++ gpio_wdt_start(); ++ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", ++ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); ++ return 0; ++} ++ ++static int gpio_wdt_remove(struct platform_device *pdev) ++{ ++ /* FIXME: do we need to lock this test ? */ ++ if (gpio_wdt_device.queue) { ++ gpio_wdt_device.queue = 0; ++ wait_for_completion(&gpio_wdt_device.stop); ++ } ++ ++ gpio_free(gpio_wdt_device.gpio); ++ misc_deregister(&gpio_wdt_misc); ++ return 0; ++} ++ ++static struct platform_driver gpio_wdt_driver = { ++ .probe = gpio_wdt_probe, ++ .remove = gpio_wdt_remove, ++ .driver.name = "gpio-wdt", ++ .driver.owner = THIS_MODULE, ++}; ++ ++static int __init gpio_wdt_init(void) ++{ ++ return platform_driver_register(&gpio_wdt_driver); ++} ++arch_initcall(gpio_wdt_init); ++ ++/* ++ * We do wdt initialization in two steps: arch_initcall probes the wdt ++ * very early to start pinging the watchdog (misc devices are not yet ++ * available), and later module_init() just registers the misc device. ++ */ ++static int gpio_wdt_init_late(void) ++{ ++ int ret; ++ ++ ret = misc_register(&gpio_wdt_misc); ++ if (ret < 0) { ++ pr_err("GPIO_WDT: failed to register misc device\n"); ++ return ret; ++ } ++ return 0; ++} ++#ifndef MODULE ++module_init(gpio_wdt_init_late); ++#endif ++ ++static void __exit gpio_wdt_exit(void) ++{ ++ platform_driver_unregister(&gpio_wdt_driver); ++} ++module_exit(gpio_wdt_exit); ++ ++MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); ++MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); ++MODULE_ALIAS("platform:gpio-wdt"); +--- /dev/null ++++ b/include/linux/old_gpio_wdt.h +@@ -0,0 +1,21 @@ ++/* ++ * Definitions for the GPIO watchdog driver ++ * ++ * Copyright (C) 2013 Mathias Adam ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef _GPIO_WDT_H_ ++#define _GPIO_WDT_H_ ++ ++struct gpio_wdt_platform_data { ++ int gpio; /* GPIO line number */ ++ int interval; /* watchdog reset interval in system ticks */ ++ int first_interval; /* first wd reset interval in system ticks */ ++}; ++ ++#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/generic/config-4.1 b/target/linux/generic/config-4.1 index 3247b24e90..b5575cd2b0 100644 --- a/target/linux/generic/config-4.1 +++ b/target/linux/generic/config-4.1 @@ -1234,7 +1234,6 @@ CONFIG_GENERIC_TIME=y # CONFIG_GPIO_TS5500 is not set # CONFIG_GPIO_VX855 is not set # CONFIG_GPIO_WATCHDOG is not set -# CONFIG_GPIO_WDT is not set # CONFIG_GPIO_XILINX is not set # CONFIG_GPIO_ZEVIO is not set # CONFIG_GREENASIA_FF is not set diff --git a/target/linux/generic/config-4.4 b/target/linux/generic/config-4.4 index ed7ae3ee15..3f4c03fd49 100644 --- a/target/linux/generic/config-4.4 +++ b/target/linux/generic/config-4.4 @@ -1230,7 +1230,6 @@ CONFIG_GENERIC_NET_UTILS=y # CONFIG_GPIO_TS5500 is not set # CONFIG_GPIO_VX855 is not set # CONFIG_GPIO_WATCHDOG is not set -# CONFIG_GPIO_WDT is not set # CONFIG_GPIO_XILINX is not set # CONFIG_GPIO_ZEVIO is not set # CONFIG_GPIO_ZX is not set diff --git a/target/linux/generic/patches-4.1/990-gpio_wdt.patch b/target/linux/generic/patches-4.1/990-gpio_wdt.patch deleted file mode 100644 index 9f5e7faf00..0000000000 --- a/target/linux/generic/patches-4.1/990-gpio_wdt.patch +++ /dev/null @@ -1,360 +0,0 @@ -This generic GPIO watchdog is used on Huawei E970 (brcm47xx) - -Signed-off-by: Mathias Adam - ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -1150,6 +1150,15 @@ config WDT_MTX1 - Hardware driver for the MTX-1 boards. This is a watchdog timer that - will reboot the machine after a 100 seconds timer expired. - -+config GPIO_WDT -+ tristate "GPIO Hardware Watchdog" -+ help -+ Hardware driver for GPIO-controlled watchdogs. GPIO pin and -+ toggle interval settings are platform-specific. The driver -+ will stop toggling the GPIO (i.e. machine reboots) after a -+ 100 second timer expired and no process has written to -+ /dev/watchdog during that time. -+ - config PNX833X_WDT - tristate "PNX833x Hardware Watchdog" - depends on SOC_PNX8335 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -135,6 +135,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt - obj-$(CONFIG_INDYDOG) += indydog.o - obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o - obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o -+obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o - obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o - obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o - obj-$(CONFIG_AR7_WDT) += ar7_wdt.o ---- /dev/null -+++ b/drivers/watchdog/old_gpio_wdt.c -@@ -0,0 +1,301 @@ -+/* -+ * Driver for GPIO-controlled Hardware Watchdogs. -+ * -+ * Copyright (C) 2013 Mathias Adam -+ * -+ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): -+ * -+ * (C) Copyright 2005 4G Systems , -+ * All Rights Reserved. -+ * http://www.4g-systems.biz -+ * -+ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli -+ * -+ * 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. -+ * -+ * Neither Michael Stickel nor 4G Systems admit liability nor provide -+ * warranty for any of this software. This material is provided -+ * "AS-IS" and at no charge. -+ * -+ * (c) Copyright 2005 4G Systems -+ * -+ * Release 0.01. -+ * Author: Michael Stickel michael.stickel@4g-systems.biz -+ * -+ * Release 0.02. -+ * Author: Florian Fainelli florian@openwrt.org -+ * use the Linux watchdog/timer APIs -+ * -+ * Release 0.03. -+ * Author: Mathias Adam -+ * make it a generic gpio watchdog driver -+ * -+ * The Watchdog is configured to reset the MTX-1 -+ * if it is not triggered for 100 seconds. -+ * It should not be triggered more often than 1.6 seconds. -+ * -+ * A timer triggers the watchdog every 5 seconds, until -+ * it is opened for the first time. After the first open -+ * it MUST be triggered every 2..95 seconds. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int ticks = 100 * HZ; -+ -+static struct { -+ struct completion stop; -+ spinlock_t lock; -+ int running; -+ struct timer_list timer; -+ int queue; -+ int default_ticks; -+ unsigned long inuse; -+ unsigned gpio; -+ unsigned int gstate; -+ int interval; -+ int first_interval; -+} gpio_wdt_device; -+ -+static void gpio_wdt_trigger(unsigned long unused) -+{ -+ spin_lock(&gpio_wdt_device.lock); -+ if (gpio_wdt_device.running && ticks > 0) -+ ticks -= gpio_wdt_device.interval; -+ -+ /* toggle wdt gpio */ -+ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; -+ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); -+ -+ if (gpio_wdt_device.queue && ticks > 0) -+ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); -+ else -+ complete(&gpio_wdt_device.stop); -+ spin_unlock(&gpio_wdt_device.lock); -+} -+ -+static void gpio_wdt_reset(void) -+{ -+ ticks = gpio_wdt_device.default_ticks; -+} -+ -+ -+static void gpio_wdt_start(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&gpio_wdt_device.lock, flags); -+ if (!gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 1; -+ gpio_wdt_device.gstate = 1; -+ gpio_set_value(gpio_wdt_device.gpio, 1); -+ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); -+ } -+ gpio_wdt_device.running++; -+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); -+} -+ -+static int gpio_wdt_stop(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&gpio_wdt_device.lock, flags); -+ if (gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 0; -+ gpio_wdt_device.gstate = 0; -+ gpio_set_value(gpio_wdt_device.gpio, 0); -+ } -+ ticks = gpio_wdt_device.default_ticks; -+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); -+ return 0; -+} -+ -+/* Filesystem functions */ -+ -+static int gpio_wdt_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) -+ return -EBUSY; -+ return nonseekable_open(inode, file); -+} -+ -+ -+static int gpio_wdt_release(struct inode *inode, struct file *file) -+{ -+ clear_bit(0, &gpio_wdt_device.inuse); -+ return 0; -+} -+ -+static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = (int __user *)argp; -+ unsigned int value; -+ static const struct watchdog_info ident = { -+ .options = WDIOF_CARDRESET, -+ .identity = "GPIO WDT", -+ }; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ if (copy_to_user(argp, &ident, sizeof(ident))) -+ return -EFAULT; -+ break; -+ case WDIOC_GETSTATUS: -+ case WDIOC_GETBOOTSTATUS: -+ put_user(0, p); -+ break; -+ case WDIOC_SETOPTIONS: -+ if (get_user(value, p)) -+ return -EFAULT; -+ if (value & WDIOS_ENABLECARD) -+ gpio_wdt_start(); -+ else if (value & WDIOS_DISABLECARD) -+ gpio_wdt_stop(); -+ else -+ return -EINVAL; -+ return 0; -+ case WDIOC_KEEPALIVE: -+ gpio_wdt_reset(); -+ break; -+ default: -+ return -ENOTTY; -+ } -+ return 0; -+} -+ -+ -+static ssize_t gpio_wdt_write(struct file *file, const char *buf, -+ size_t count, loff_t *ppos) -+{ -+ if (!count) -+ return -EIO; -+ gpio_wdt_reset(); -+ return count; -+} -+ -+static const struct file_operations gpio_wdt_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .unlocked_ioctl = gpio_wdt_ioctl, -+ .open = gpio_wdt_open, -+ .write = gpio_wdt_write, -+ .release = gpio_wdt_release, -+}; -+ -+ -+static struct miscdevice gpio_wdt_misc = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &gpio_wdt_fops, -+}; -+ -+ -+static int gpio_wdt_probe(struct platform_device *pdev) -+{ -+ int ret; -+ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; -+ -+ gpio_wdt_device.gpio = gpio_wdt_data->gpio; -+ gpio_wdt_device.interval = gpio_wdt_data->interval; -+ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; -+ if (gpio_wdt_device.first_interval <= 0) { -+ gpio_wdt_device.first_interval = gpio_wdt_device.interval; -+ } -+ -+ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to request gpio"); -+ return ret; -+ } -+ -+ spin_lock_init(&gpio_wdt_device.lock); -+ init_completion(&gpio_wdt_device.stop); -+ gpio_wdt_device.queue = 0; -+ clear_bit(0, &gpio_wdt_device.inuse); -+ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); -+ gpio_wdt_device.default_ticks = ticks; -+ -+ gpio_wdt_start(); -+ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", -+ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); -+ return 0; -+} -+ -+static int gpio_wdt_remove(struct platform_device *pdev) -+{ -+ /* FIXME: do we need to lock this test ? */ -+ if (gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 0; -+ wait_for_completion(&gpio_wdt_device.stop); -+ } -+ -+ gpio_free(gpio_wdt_device.gpio); -+ misc_deregister(&gpio_wdt_misc); -+ return 0; -+} -+ -+static struct platform_driver gpio_wdt_driver = { -+ .probe = gpio_wdt_probe, -+ .remove = gpio_wdt_remove, -+ .driver.name = "gpio-wdt", -+ .driver.owner = THIS_MODULE, -+}; -+ -+static int __init gpio_wdt_init(void) -+{ -+ return platform_driver_register(&gpio_wdt_driver); -+} -+arch_initcall(gpio_wdt_init); -+ -+/* -+ * We do wdt initialization in two steps: arch_initcall probes the wdt -+ * very early to start pinging the watchdog (misc devices are not yet -+ * available), and later module_init() just registers the misc device. -+ */ -+static int gpio_wdt_init_late(void) -+{ -+ int ret; -+ -+ ret = misc_register(&gpio_wdt_misc); -+ if (ret < 0) { -+ pr_err("GPIO_WDT: failed to register misc device\n"); -+ return ret; -+ } -+ return 0; -+} -+#ifndef MODULE -+module_init(gpio_wdt_init_late); -+#endif -+ -+static void __exit gpio_wdt_exit(void) -+{ -+ platform_driver_unregister(&gpio_wdt_driver); -+} -+module_exit(gpio_wdt_exit); -+ -+MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); -+MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -+MODULE_ALIAS("platform:gpio-wdt"); ---- /dev/null -+++ b/include/linux/old_gpio_wdt.h -@@ -0,0 +1,21 @@ -+/* -+ * Definitions for the GPIO watchdog driver -+ * -+ * Copyright (C) 2013 Mathias Adam -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef _GPIO_WDT_H_ -+#define _GPIO_WDT_H_ -+ -+struct gpio_wdt_platform_data { -+ int gpio; /* GPIO line number */ -+ int interval; /* watchdog reset interval in system ticks */ -+ int first_interval; /* first wd reset interval in system ticks */ -+}; -+ -+#endif /* _GPIO_WDT_H_ */ diff --git a/target/linux/generic/patches-4.4/990-gpio_wdt.patch b/target/linux/generic/patches-4.4/990-gpio_wdt.patch deleted file mode 100644 index 5856a5c50e..0000000000 --- a/target/linux/generic/patches-4.4/990-gpio_wdt.patch +++ /dev/null @@ -1,360 +0,0 @@ -This generic GPIO watchdog is used on Huawei E970 (brcm47xx) - -Signed-off-by: Mathias Adam - ---- a/drivers/watchdog/Kconfig -+++ b/drivers/watchdog/Kconfig -@@ -1216,6 +1216,15 @@ config WDT_MTX1 - Hardware driver for the MTX-1 boards. This is a watchdog timer that - will reboot the machine after a 100 seconds timer expired. - -+config GPIO_WDT -+ tristate "GPIO Hardware Watchdog" -+ help -+ Hardware driver for GPIO-controlled watchdogs. GPIO pin and -+ toggle interval settings are platform-specific. The driver -+ will stop toggling the GPIO (i.e. machine reboots) after a -+ 100 second timer expired and no process has written to -+ /dev/watchdog during that time. -+ - config PNX833X_WDT - tristate "PNX833x Hardware Watchdog" - depends on SOC_PNX8335 ---- a/drivers/watchdog/Makefile -+++ b/drivers/watchdog/Makefile -@@ -140,6 +140,7 @@ obj-$(CONFIG_RC32434_WDT) += rc32434_wdt - obj-$(CONFIG_INDYDOG) += indydog.o - obj-$(CONFIG_JZ4740_WDT) += jz4740_wdt.o - obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o -+obj-$(CONFIG_GPIO_WDT) += old_gpio_wdt.o - obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o - obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o - obj-$(CONFIG_AR7_WDT) += ar7_wdt.o ---- /dev/null -+++ b/drivers/watchdog/old_gpio_wdt.c -@@ -0,0 +1,301 @@ -+/* -+ * Driver for GPIO-controlled Hardware Watchdogs. -+ * -+ * Copyright (C) 2013 Mathias Adam -+ * -+ * Replaces mtx1_wdt (driver for the MTX-1 Watchdog): -+ * -+ * (C) Copyright 2005 4G Systems , -+ * All Rights Reserved. -+ * http://www.4g-systems.biz -+ * -+ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli -+ * -+ * 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. -+ * -+ * Neither Michael Stickel nor 4G Systems admit liability nor provide -+ * warranty for any of this software. This material is provided -+ * "AS-IS" and at no charge. -+ * -+ * (c) Copyright 2005 4G Systems -+ * -+ * Release 0.01. -+ * Author: Michael Stickel michael.stickel@4g-systems.biz -+ * -+ * Release 0.02. -+ * Author: Florian Fainelli florian@openwrt.org -+ * use the Linux watchdog/timer APIs -+ * -+ * Release 0.03. -+ * Author: Mathias Adam -+ * make it a generic gpio watchdog driver -+ * -+ * The Watchdog is configured to reset the MTX-1 -+ * if it is not triggered for 100 seconds. -+ * It should not be triggered more often than 1.6 seconds. -+ * -+ * A timer triggers the watchdog every 5 seconds, until -+ * it is opened for the first time. After the first open -+ * it MUST be triggered every 2..95 seconds. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int ticks = 100 * HZ; -+ -+static struct { -+ struct completion stop; -+ spinlock_t lock; -+ int running; -+ struct timer_list timer; -+ int queue; -+ int default_ticks; -+ unsigned long inuse; -+ unsigned gpio; -+ unsigned int gstate; -+ int interval; -+ int first_interval; -+} gpio_wdt_device; -+ -+static void gpio_wdt_trigger(unsigned long unused) -+{ -+ spin_lock(&gpio_wdt_device.lock); -+ if (gpio_wdt_device.running && ticks > 0) -+ ticks -= gpio_wdt_device.interval; -+ -+ /* toggle wdt gpio */ -+ gpio_wdt_device.gstate = !gpio_wdt_device.gstate; -+ gpio_set_value(gpio_wdt_device.gpio, gpio_wdt_device.gstate); -+ -+ if (gpio_wdt_device.queue && ticks > 0) -+ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.interval); -+ else -+ complete(&gpio_wdt_device.stop); -+ spin_unlock(&gpio_wdt_device.lock); -+} -+ -+static void gpio_wdt_reset(void) -+{ -+ ticks = gpio_wdt_device.default_ticks; -+} -+ -+ -+static void gpio_wdt_start(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&gpio_wdt_device.lock, flags); -+ if (!gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 1; -+ gpio_wdt_device.gstate = 1; -+ gpio_set_value(gpio_wdt_device.gpio, 1); -+ mod_timer(&gpio_wdt_device.timer, jiffies + gpio_wdt_device.first_interval); -+ } -+ gpio_wdt_device.running++; -+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); -+} -+ -+static int gpio_wdt_stop(void) -+{ -+ unsigned long flags; -+ -+ spin_lock_irqsave(&gpio_wdt_device.lock, flags); -+ if (gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 0; -+ gpio_wdt_device.gstate = 0; -+ gpio_set_value(gpio_wdt_device.gpio, 0); -+ } -+ ticks = gpio_wdt_device.default_ticks; -+ spin_unlock_irqrestore(&gpio_wdt_device.lock, flags); -+ return 0; -+} -+ -+/* Filesystem functions */ -+ -+static int gpio_wdt_open(struct inode *inode, struct file *file) -+{ -+ if (test_and_set_bit(0, &gpio_wdt_device.inuse)) -+ return -EBUSY; -+ return nonseekable_open(inode, file); -+} -+ -+ -+static int gpio_wdt_release(struct inode *inode, struct file *file) -+{ -+ clear_bit(0, &gpio_wdt_device.inuse); -+ return 0; -+} -+ -+static long gpio_wdt_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ int __user *p = (int __user *)argp; -+ unsigned int value; -+ static const struct watchdog_info ident = { -+ .options = WDIOF_CARDRESET, -+ .identity = "GPIO WDT", -+ }; -+ -+ switch (cmd) { -+ case WDIOC_GETSUPPORT: -+ if (copy_to_user(argp, &ident, sizeof(ident))) -+ return -EFAULT; -+ break; -+ case WDIOC_GETSTATUS: -+ case WDIOC_GETBOOTSTATUS: -+ put_user(0, p); -+ break; -+ case WDIOC_SETOPTIONS: -+ if (get_user(value, p)) -+ return -EFAULT; -+ if (value & WDIOS_ENABLECARD) -+ gpio_wdt_start(); -+ else if (value & WDIOS_DISABLECARD) -+ gpio_wdt_stop(); -+ else -+ return -EINVAL; -+ return 0; -+ case WDIOC_KEEPALIVE: -+ gpio_wdt_reset(); -+ break; -+ default: -+ return -ENOTTY; -+ } -+ return 0; -+} -+ -+ -+static ssize_t gpio_wdt_write(struct file *file, const char *buf, -+ size_t count, loff_t *ppos) -+{ -+ if (!count) -+ return -EIO; -+ gpio_wdt_reset(); -+ return count; -+} -+ -+static const struct file_operations gpio_wdt_fops = { -+ .owner = THIS_MODULE, -+ .llseek = no_llseek, -+ .unlocked_ioctl = gpio_wdt_ioctl, -+ .open = gpio_wdt_open, -+ .write = gpio_wdt_write, -+ .release = gpio_wdt_release, -+}; -+ -+ -+static struct miscdevice gpio_wdt_misc = { -+ .minor = WATCHDOG_MINOR, -+ .name = "watchdog", -+ .fops = &gpio_wdt_fops, -+}; -+ -+ -+static int gpio_wdt_probe(struct platform_device *pdev) -+{ -+ int ret; -+ struct gpio_wdt_platform_data *gpio_wdt_data = pdev->dev.platform_data; -+ -+ gpio_wdt_device.gpio = gpio_wdt_data->gpio; -+ gpio_wdt_device.interval = gpio_wdt_data->interval; -+ gpio_wdt_device.first_interval = gpio_wdt_data->first_interval; -+ if (gpio_wdt_device.first_interval <= 0) { -+ gpio_wdt_device.first_interval = gpio_wdt_device.interval; -+ } -+ -+ ret = gpio_request(gpio_wdt_device.gpio, "gpio-wdt"); -+ if (ret < 0) { -+ dev_err(&pdev->dev, "failed to request gpio"); -+ return ret; -+ } -+ -+ spin_lock_init(&gpio_wdt_device.lock); -+ init_completion(&gpio_wdt_device.stop); -+ gpio_wdt_device.queue = 0; -+ clear_bit(0, &gpio_wdt_device.inuse); -+ setup_timer(&gpio_wdt_device.timer, gpio_wdt_trigger, 0L); -+ gpio_wdt_device.default_ticks = ticks; -+ -+ gpio_wdt_start(); -+ dev_info(&pdev->dev, "GPIO Hardware Watchdog driver (gpio=%i interval=%i/%i)\n", -+ gpio_wdt_data->gpio, gpio_wdt_data->first_interval, gpio_wdt_data->interval); -+ return 0; -+} -+ -+static int gpio_wdt_remove(struct platform_device *pdev) -+{ -+ /* FIXME: do we need to lock this test ? */ -+ if (gpio_wdt_device.queue) { -+ gpio_wdt_device.queue = 0; -+ wait_for_completion(&gpio_wdt_device.stop); -+ } -+ -+ gpio_free(gpio_wdt_device.gpio); -+ misc_deregister(&gpio_wdt_misc); -+ return 0; -+} -+ -+static struct platform_driver gpio_wdt_driver = { -+ .probe = gpio_wdt_probe, -+ .remove = gpio_wdt_remove, -+ .driver.name = "gpio-wdt", -+ .driver.owner = THIS_MODULE, -+}; -+ -+static int __init gpio_wdt_init(void) -+{ -+ return platform_driver_register(&gpio_wdt_driver); -+} -+arch_initcall(gpio_wdt_init); -+ -+/* -+ * We do wdt initialization in two steps: arch_initcall probes the wdt -+ * very early to start pinging the watchdog (misc devices are not yet -+ * available), and later module_init() just registers the misc device. -+ */ -+static int gpio_wdt_init_late(void) -+{ -+ int ret; -+ -+ ret = misc_register(&gpio_wdt_misc); -+ if (ret < 0) { -+ pr_err("GPIO_WDT: failed to register misc device\n"); -+ return ret; -+ } -+ return 0; -+} -+#ifndef MODULE -+module_init(gpio_wdt_init_late); -+#endif -+ -+static void __exit gpio_wdt_exit(void) -+{ -+ platform_driver_unregister(&gpio_wdt_driver); -+} -+module_exit(gpio_wdt_exit); -+ -+MODULE_AUTHOR("Michael Stickel, Florian Fainelli, Mathias Adam"); -+MODULE_DESCRIPTION("Driver for GPIO hardware watchdogs"); -+MODULE_LICENSE("GPL"); -+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -+MODULE_ALIAS("platform:gpio-wdt"); ---- /dev/null -+++ b/include/linux/old_gpio_wdt.h -@@ -0,0 +1,21 @@ -+/* -+ * Definitions for the GPIO watchdog driver -+ * -+ * Copyright (C) 2013 Mathias Adam -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ */ -+ -+#ifndef _GPIO_WDT_H_ -+#define _GPIO_WDT_H_ -+ -+struct gpio_wdt_platform_data { -+ int gpio; /* GPIO line number */ -+ int interval; /* watchdog reset interval in system ticks */ -+ int first_interval; /* first wd reset interval in system ticks */ -+}; -+ -+#endif /* _GPIO_WDT_H_ */