mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-02 08:34:20 +08:00
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: "This patchset contains: - Various small clean-ups and fixes - boot logic hanegs for mpc8xxx_wdt - it87_wdt: Work around non-working CIR interrupts - iTCO_wdt: Fix the parent device - Kconfig dependencies - simplification of code with devm_ioremap_resource() or platform_driver_probe() - conversion of xilinx watchdog driver to Generic watchdog Framework - addition of extra functionality and devices for the xilinx watchdog driver - Addition of Tegra watchdog" * git://www.linux-watchdog.org/linux-watchdog: (38 commits) watchdog: Fix Elan SC520 dependencies watchdog: ib700wdt: Use platform_driver_probe watchdog: geodewdt: Use platform_driver_probe watchdog: advantechwdt: Use platform_driver_probe watchdog: acquirewdt: Use platform_driver_probe watchdog: iTCO_wdt: Fix the parent device watchdog: it87_wdt: Work around non-working CIR interrupts watchdog: bcm281xx: Fix Kconfig dependency watchdog: s3c2410_wdt: Check return value of clk_prepare_enable watchdog: s3c2410_wdt: Remove unneeded initialization watchdog: sunxi: Change compatibles watchdog: orion: prepare new Dove DT Kconfig variable watchdog: fix checkpatch warnings and error watchdog: Add tegra watchdog watchdog: xilinx: Remove no_timeout variable watchdog: xilinx: Enable this driver for Zynq watchdog: xilinx: Add missing binding watchdog: xilinx: Use correct comment indentation watchdog: xilinx: Use of_property_read_u32 watchdog: xilinx: Fix all printk messages ...
This commit is contained in:
commit
0c8cfbade0
23
Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
Normal file
23
Documentation/devicetree/bindings/watchdog/of-xilinx-wdt.txt
Normal file
@ -0,0 +1,23 @@
|
||||
Xilinx AXI/PLB soft-core watchdog Device Tree Bindings
|
||||
---------------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "xlnx,xps-timebase-wdt-1.00.a" or
|
||||
"xlnx,xps-timebase-wdt-1.01.a".
|
||||
- reg : Physical base address and size
|
||||
|
||||
Optional properties:
|
||||
- clock-frequency : Frequency of clock in Hz
|
||||
- xlnx,wdt-enable-once : 0 - Watchdog can be restarted
|
||||
1 - Watchdog can be enabled just once
|
||||
- xlnx,wdt-interval : Watchdog timeout interval in 2^<val> clock cycles,
|
||||
<val> is integer from 8 to 31.
|
||||
|
||||
Example:
|
||||
axi-timebase-wdt@40100000 {
|
||||
clock-frequency = <50000000>;
|
||||
compatible = "xlnx,xps-timebase-wdt-1.00.a";
|
||||
reg = <0x40100000 0x10000>;
|
||||
xlnx,wdt-enable-once = <0x0>;
|
||||
xlnx,wdt-interval = <0x1b>;
|
||||
} ;
|
@ -2,13 +2,13 @@ Allwinner SoCs Watchdog timer
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "allwinner,<soc-family>-wdt", the currently supported
|
||||
SoC families being sun4i and sun6i
|
||||
- compatible : should be either "allwinner,sun4i-a10-wdt" or
|
||||
"allwinner,sun6i-a31-wdt"
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
|
||||
Example:
|
||||
|
||||
wdt: watchdog@01c20c90 {
|
||||
compatible = "allwinner,sun4i-wdt";
|
||||
compatible = "allwinner,sun4i-a10-wdt";
|
||||
reg = <0x01c20c90 0x10>;
|
||||
};
|
||||
|
@ -150,6 +150,8 @@ nowayout: Disable watchdog shutdown on close
|
||||
-------------------------------------------------
|
||||
it87_wdt:
|
||||
nogameport: Forbid the activation of game port, default=0
|
||||
nocir: Forbid the use of CIR (workaround for some buggy setups); set to 1 if
|
||||
system resets despite watchdog daemon running, default=0
|
||||
exclusive: Watchdog exclusive device open, default=1
|
||||
timeout: Watchdog timeout in seconds, default=60
|
||||
testmode: Watchdog test mode (1 = no reboot), default=0
|
||||
@ -325,6 +327,11 @@ soft_noboot: Softdog action, set to 1 to ignore reboots, 0 to reboot
|
||||
stmp3xxx_wdt:
|
||||
heartbeat: Watchdog heartbeat period in seconds from 1 to 4194304, default 19
|
||||
-------------------------------------------------
|
||||
tegra_wdt:
|
||||
heartbeat: Watchdog heartbeats in seconds. (default = 120)
|
||||
nowayout: Watchdog cannot be stopped once started
|
||||
(default=kernel config parameter)
|
||||
-------------------------------------------------
|
||||
ts72xx_wdt:
|
||||
timeout: Watchdog timeout in seconds. (1 <= timeout <= 8, default=8)
|
||||
nowayout: Disable watchdog shutdown on close
|
||||
|
@ -111,6 +111,15 @@ config WM8350_WATCHDOG
|
||||
Support for the watchdog in the WM8350 AudioPlus PMIC. When
|
||||
the watchdog triggers the system will be reset.
|
||||
|
||||
config XILINX_WATCHDOG
|
||||
tristate "Xilinx Watchdog timer"
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Watchdog driver for the xps_timebase_wdt ip core.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called of_xilinx_wdt.
|
||||
|
||||
# ALPHA Architecture
|
||||
|
||||
# ARM Architecture
|
||||
@ -292,7 +301,7 @@ config DAVINCI_WATCHDOG
|
||||
|
||||
config ORION_WATCHDOG
|
||||
tristate "Orion watchdog"
|
||||
depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE
|
||||
depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE || MACH_DOVE
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Say Y here if to include support for the watchdog timer
|
||||
@ -421,6 +430,17 @@ config SIRFSOC_WATCHDOG
|
||||
Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When
|
||||
the watchdog triggers the system will be reset.
|
||||
|
||||
config TEGRA_WATCHDOG
|
||||
tristate "Tegra watchdog"
|
||||
depends on ARCH_TEGRA || COMPILE_TEST
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Say Y here to include support for the watchdog timer
|
||||
embedded in NVIDIA Tegra SoCs.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called tegra_wdt.
|
||||
|
||||
# AVR32 Architecture
|
||||
|
||||
config AT32AP700X_WDT
|
||||
@ -533,7 +553,7 @@ config GEODE_WDT
|
||||
|
||||
config SC520_WDT
|
||||
tristate "AMD Elan SC520 processor Watchdog"
|
||||
depends on X86
|
||||
depends on MELAN
|
||||
help
|
||||
This is the driver for the hardware watchdog built in to the
|
||||
AMD "Elan" SC520 microcomputer commonly used in embedded systems.
|
||||
@ -1023,18 +1043,6 @@ config M54xx_WATCHDOG
|
||||
|
||||
# MicroBlaze Architecture
|
||||
|
||||
config XILINX_WATCHDOG
|
||||
tristate "Xilinx Watchdog timer"
|
||||
depends on MICROBLAZE
|
||||
---help---
|
||||
Watchdog driver for the xps_timebase_wdt ip core.
|
||||
|
||||
IMPORTANT: The xps_timebase_wdt parent must have the property
|
||||
"clock-frequency" at device tree.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called of_xilinx_wdt.
|
||||
|
||||
# MIPS Architecture
|
||||
|
||||
config ATH79_WDT
|
||||
@ -1160,7 +1168,7 @@ config BCM2835_WDT
|
||||
|
||||
config BCM_KONA_WDT
|
||||
tristate "BCM Kona Watchdog"
|
||||
depends on ARCH_BCM
|
||||
depends on ARCH_BCM_MOBILE
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Support for the watchdog timer on the following Broadcom BCM281xx
|
||||
|
@ -58,6 +58,7 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
|
||||
obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
|
||||
obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
|
||||
obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
|
||||
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
|
||||
|
||||
# AVR32 Architecture
|
||||
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
|
||||
|
@ -239,7 +239,7 @@ static struct miscdevice acq_miscdev = {
|
||||
* Init & exit routines
|
||||
*/
|
||||
|
||||
static int acq_probe(struct platform_device *dev)
|
||||
static int __init acq_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -291,7 +291,6 @@ static void acq_shutdown(struct platform_device *dev)
|
||||
}
|
||||
|
||||
static struct platform_driver acquirewdt_driver = {
|
||||
.probe = acq_probe,
|
||||
.remove = acq_remove,
|
||||
.shutdown = acq_shutdown,
|
||||
.driver = {
|
||||
@ -306,20 +305,18 @@ static int __init acq_init(void)
|
||||
|
||||
pr_info("WDT driver for Acquire single board computer initialising\n");
|
||||
|
||||
err = platform_driver_register(&acquirewdt_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
acq_platform_device = platform_device_register_simple(DRV_NAME,
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(acq_platform_device)) {
|
||||
err = PTR_ERR(acq_platform_device);
|
||||
goto unreg_platform_driver;
|
||||
}
|
||||
if (IS_ERR(acq_platform_device))
|
||||
return PTR_ERR(acq_platform_device);
|
||||
|
||||
err = platform_driver_probe(&acquirewdt_driver, acq_probe);
|
||||
if (err)
|
||||
goto unreg_platform_device;
|
||||
return 0;
|
||||
|
||||
unreg_platform_driver:
|
||||
platform_driver_unregister(&acquirewdt_driver);
|
||||
unreg_platform_device:
|
||||
platform_device_unregister(acq_platform_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ static struct miscdevice advwdt_miscdev = {
|
||||
* Init & exit routines
|
||||
*/
|
||||
|
||||
static int advwdt_probe(struct platform_device *dev)
|
||||
static int __init advwdt_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -299,7 +299,6 @@ static void advwdt_shutdown(struct platform_device *dev)
|
||||
}
|
||||
|
||||
static struct platform_driver advwdt_driver = {
|
||||
.probe = advwdt_probe,
|
||||
.remove = advwdt_remove,
|
||||
.shutdown = advwdt_shutdown,
|
||||
.driver = {
|
||||
@ -314,21 +313,19 @@ static int __init advwdt_init(void)
|
||||
|
||||
pr_info("WDT driver for Advantech single board computer initialising\n");
|
||||
|
||||
err = platform_driver_register(&advwdt_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
advwdt_platform_device = platform_device_register_simple(DRV_NAME,
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(advwdt_platform_device)) {
|
||||
err = PTR_ERR(advwdt_platform_device);
|
||||
goto unreg_platform_driver;
|
||||
}
|
||||
if (IS_ERR(advwdt_platform_device))
|
||||
return PTR_ERR(advwdt_platform_device);
|
||||
|
||||
err = platform_driver_probe(&advwdt_driver, advwdt_probe);
|
||||
if (err)
|
||||
goto unreg_platform_device;
|
||||
|
||||
return 0;
|
||||
|
||||
unreg_platform_driver:
|
||||
platform_driver_unregister(&advwdt_driver);
|
||||
unreg_platform_device:
|
||||
platform_device_unregister(advwdt_platform_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
@ -323,10 +323,8 @@ static int __init at32_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x),
|
||||
GFP_KERNEL);
|
||||
if (!wdt) {
|
||||
dev_dbg(&pdev->dev, "no memory for wdt structure\n");
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
|
||||
if (!wdt->regs) {
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
@ -114,10 +114,8 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
|
||||
wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL);
|
||||
if (!wdt) {
|
||||
dev_err(dev, "Failed to allocate memory for watchdog device");
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
platform_set_drvdata(pdev, wdt);
|
||||
|
||||
spin_lock_init(&wdt->lock);
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/bcm47xx_wdt.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/miscdevice.h>
|
||||
@ -45,7 +44,6 @@
|
||||
static struct {
|
||||
void __iomem *regs;
|
||||
struct timer_list timer;
|
||||
int default_ticks;
|
||||
unsigned long inuse;
|
||||
atomic_t ticks;
|
||||
} bcm63xx_wdt_device;
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/completion.h>
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
|
@ -185,7 +185,6 @@ static int da9052_wdt_probe(struct platform_device *pdev)
|
||||
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
|
||||
GFP_KERNEL);
|
||||
if (!driver_data) {
|
||||
dev_err(da9052->dev, "Unable to alloacate watchdog device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
@ -151,10 +151,8 @@ static int da9055_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
|
||||
GFP_KERNEL);
|
||||
if (!driver_data) {
|
||||
dev_err(da9055->dev, "Failed to allocate watchdog device\n");
|
||||
if (!driver_data)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
driver_data->da9055 = da9055;
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -118,16 +118,9 @@ static int ep93xx_wdt_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENXIO;
|
||||
|
||||
if (!devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), pdev->name))
|
||||
return -EBUSY;
|
||||
|
||||
mmio_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!mmio_base)
|
||||
return -ENXIO;
|
||||
mmio_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(mmio_base))
|
||||
return PTR_ERR(mmio_base);
|
||||
|
||||
if (timeout < 1 || timeout > 3600) {
|
||||
timeout = WDT_TIMEOUT;
|
||||
@ -172,9 +165,9 @@ static struct platform_driver ep93xx_wdt_driver = {
|
||||
|
||||
module_platform_driver(ep93xx_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
|
||||
"Alessandro Zummo <a.zummo@towertech.it>,"
|
||||
"H Hartley Sweeten <hsweeten@visionengravers.com>");
|
||||
MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>");
|
||||
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
|
||||
MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
|
||||
MODULE_DESCRIPTION("EP93xx Watchdog");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(WDT_VERSION);
|
||||
|
@ -215,7 +215,7 @@ static struct miscdevice geodewdt_miscdev = {
|
||||
.fops = &geodewdt_fops,
|
||||
};
|
||||
|
||||
static int geodewdt_probe(struct platform_device *dev)
|
||||
static int __init geodewdt_probe(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@ -255,7 +255,6 @@ static void geodewdt_shutdown(struct platform_device *dev)
|
||||
}
|
||||
|
||||
static struct platform_driver geodewdt_driver = {
|
||||
.probe = geodewdt_probe,
|
||||
.remove = geodewdt_remove,
|
||||
.shutdown = geodewdt_shutdown,
|
||||
.driver = {
|
||||
@ -268,20 +267,18 @@ static int __init geodewdt_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&geodewdt_driver);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
geodewdt_platform_device = platform_device_register_simple(DRV_NAME,
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(geodewdt_platform_device)) {
|
||||
ret = PTR_ERR(geodewdt_platform_device);
|
||||
if (IS_ERR(geodewdt_platform_device))
|
||||
return PTR_ERR(geodewdt_platform_device);
|
||||
|
||||
ret = platform_driver_probe(&geodewdt_driver, geodewdt_probe);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
platform_driver_unregister(&geodewdt_driver);
|
||||
platform_device_unregister(geodewdt_platform_device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -36,7 +36,6 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
@ -347,15 +347,15 @@ static const struct watchdog_info ident = {
|
||||
static const struct watchdog_ops iTCO_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = iTCO_wdt_start,
|
||||
.stop = iTCO_wdt_stop,
|
||||
.ping = iTCO_wdt_ping,
|
||||
.stop = iTCO_wdt_stop,
|
||||
.ping = iTCO_wdt_ping,
|
||||
.set_timeout = iTCO_wdt_set_timeout,
|
||||
.get_timeleft = iTCO_wdt_get_timeleft,
|
||||
};
|
||||
|
||||
static struct watchdog_device iTCO_wdt_watchdog_dev = {
|
||||
.info = &ident,
|
||||
.ops = &iTCO_wdt_ops,
|
||||
.ops = &iTCO_wdt_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -485,7 +485,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
|
||||
iTCO_wdt_watchdog_dev.bootstatus = 0;
|
||||
iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
|
||||
watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
|
||||
iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
|
||||
iTCO_wdt_watchdog_dev.parent = &dev->dev;
|
||||
|
||||
/* Make sure the watchdog is not running */
|
||||
iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
|
||||
|
@ -277,7 +277,7 @@ static struct miscdevice ibwdt_miscdev = {
|
||||
* Init & exit routines
|
||||
*/
|
||||
|
||||
static int ibwdt_probe(struct platform_device *dev)
|
||||
static int __init ibwdt_probe(struct platform_device *dev)
|
||||
{
|
||||
int res;
|
||||
|
||||
@ -336,7 +336,6 @@ static void ibwdt_shutdown(struct platform_device *dev)
|
||||
}
|
||||
|
||||
static struct platform_driver ibwdt_driver = {
|
||||
.probe = ibwdt_probe,
|
||||
.remove = ibwdt_remove,
|
||||
.shutdown = ibwdt_shutdown,
|
||||
.driver = {
|
||||
@ -351,21 +350,19 @@ static int __init ibwdt_init(void)
|
||||
|
||||
pr_info("WDT driver for IB700 single board computer initialising\n");
|
||||
|
||||
err = platform_driver_register(&ibwdt_driver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ibwdt_platform_device = platform_device_register_simple(DRV_NAME,
|
||||
-1, NULL, 0);
|
||||
if (IS_ERR(ibwdt_platform_device)) {
|
||||
err = PTR_ERR(ibwdt_platform_device);
|
||||
goto unreg_platform_driver;
|
||||
}
|
||||
if (IS_ERR(ibwdt_platform_device))
|
||||
return PTR_ERR(ibwdt_platform_device);
|
||||
|
||||
err = platform_driver_probe(&ibwdt_driver, ibwdt_probe);
|
||||
if (err)
|
||||
goto unreg_platform_device;
|
||||
|
||||
return 0;
|
||||
|
||||
unreg_platform_driver:
|
||||
platform_driver_unregister(&ibwdt_driver);
|
||||
unreg_platform_device:
|
||||
platform_device_unregister(ibwdt_platform_device);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -360,7 +360,7 @@ struct ibmasr_id {
|
||||
int type;
|
||||
};
|
||||
|
||||
static struct ibmasr_id __initdata ibmasr_id_table[] = {
|
||||
static struct ibmasr_id ibmasr_id_table[] __initdata = {
|
||||
{ "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
|
||||
{ "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
|
||||
{ "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
|
||||
|
@ -41,24 +41,15 @@ MODULE_PARM_DESC(nowayout,
|
||||
|
||||
static void indydog_start(void)
|
||||
{
|
||||
u32 mc_ctrl0;
|
||||
|
||||
spin_lock(&indydog_lock);
|
||||
mc_ctrl0 = sgimc->cpuctrl0;
|
||||
mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
|
||||
sgimc->cpuctrl0 = mc_ctrl0;
|
||||
sgimc->cpuctrl0 |= SGIMC_CCTRL0_WDOG;
|
||||
spin_unlock(&indydog_lock);
|
||||
}
|
||||
|
||||
static void indydog_stop(void)
|
||||
{
|
||||
u32 mc_ctrl0;
|
||||
|
||||
spin_lock(&indydog_lock);
|
||||
|
||||
mc_ctrl0 = sgimc->cpuctrl0;
|
||||
mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
|
||||
sgimc->cpuctrl0 = mc_ctrl0;
|
||||
sgimc->cpuctrl0 &= ~SGIMC_CCTRL0_WDOG;
|
||||
spin_unlock(&indydog_lock);
|
||||
|
||||
pr_info("Stopped watchdog timer\n");
|
||||
|
@ -211,7 +211,6 @@ static int intel_scu_set_heartbeat(u32 t)
|
||||
int ipc_ret;
|
||||
int retry_count;
|
||||
u32 soft_value;
|
||||
u32 hw_pre_value;
|
||||
u32 hw_value;
|
||||
|
||||
watchdog_device.timer_set = t;
|
||||
@ -273,8 +272,7 @@ static int intel_scu_set_heartbeat(u32 t)
|
||||
watchdog_device.timer_load_count_addr);
|
||||
|
||||
/* read count value before starting timer */
|
||||
hw_pre_value = ioread32(watchdog_device.timer_load_count_addr);
|
||||
hw_pre_value = hw_pre_value & 0xFFFF0000;
|
||||
ioread32(watchdog_device.timer_load_count_addr);
|
||||
|
||||
/* Start the timer */
|
||||
iowrite32(0x00000003, watchdog_device.timer_control_addr);
|
||||
|
@ -54,6 +54,7 @@
|
||||
|
||||
/* Defaults for Module Parameter */
|
||||
#define DEFAULT_NOGAMEPORT 0
|
||||
#define DEFAULT_NOCIR 0
|
||||
#define DEFAULT_EXCLUSIVE 1
|
||||
#define DEFAULT_TIMEOUT 60
|
||||
#define DEFAULT_TESTMODE 0
|
||||
@ -136,11 +137,13 @@
|
||||
#define WDTS_LOCKED 3
|
||||
#define WDTS_USE_GP 4
|
||||
#define WDTS_EXPECTED 5
|
||||
#define WDTS_USE_CIR 6
|
||||
|
||||
static unsigned int base, gpact, ciract, max_units, chip_type;
|
||||
static unsigned long wdt_status;
|
||||
|
||||
static int nogameport = DEFAULT_NOGAMEPORT;
|
||||
static int nocir = DEFAULT_NOCIR;
|
||||
static int exclusive = DEFAULT_EXCLUSIVE;
|
||||
static int timeout = DEFAULT_TIMEOUT;
|
||||
static int testmode = DEFAULT_TESTMODE;
|
||||
@ -149,6 +152,9 @@ static bool nowayout = DEFAULT_NOWAYOUT;
|
||||
module_param(nogameport, int, 0);
|
||||
MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
|
||||
__MODULE_STRING(DEFAULT_NOGAMEPORT));
|
||||
module_param(nocir, int, 0);
|
||||
MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default="
|
||||
__MODULE_STRING(DEFAULT_NOCIR));
|
||||
module_param(exclusive, int, 0);
|
||||
MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
|
||||
__MODULE_STRING(DEFAULT_EXCLUSIVE));
|
||||
@ -258,9 +264,17 @@ static void wdt_keepalive(void)
|
||||
{
|
||||
if (test_bit(WDTS_USE_GP, &wdt_status))
|
||||
inb(base);
|
||||
else
|
||||
else if (test_bit(WDTS_USE_CIR, &wdt_status))
|
||||
/* The timer reloads with around 5 msec delay */
|
||||
outb(0x55, CIR_DR(base));
|
||||
else {
|
||||
if (superio_enter())
|
||||
return;
|
||||
|
||||
superio_select(GPIO);
|
||||
wdt_update_timeout();
|
||||
superio_exit();
|
||||
}
|
||||
set_bit(WDTS_KEEPALIVE, &wdt_status);
|
||||
}
|
||||
|
||||
@ -273,7 +287,7 @@ static int wdt_start(void)
|
||||
superio_select(GPIO);
|
||||
if (test_bit(WDTS_USE_GP, &wdt_status))
|
||||
superio_outb(WDT_GAMEPORT, WDTCTRL);
|
||||
else
|
||||
else if (test_bit(WDTS_USE_CIR, &wdt_status))
|
||||
superio_outb(WDT_CIRINT, WDTCTRL);
|
||||
wdt_update_timeout();
|
||||
|
||||
@ -660,7 +674,7 @@ static int __init it87_wdt_init(void)
|
||||
}
|
||||
|
||||
/* If we haven't Gameport support, try to get CIR support */
|
||||
if (!test_bit(WDTS_USE_GP, &wdt_status)) {
|
||||
if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) {
|
||||
if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
|
||||
if (gp_rreq_fail)
|
||||
pr_err("I/O Address 0x%04x and 0x%04x already in use\n",
|
||||
@ -682,6 +696,7 @@ static int __init it87_wdt_init(void)
|
||||
superio_select(GAMEPORT);
|
||||
superio_outb(gpact, ACTREG);
|
||||
}
|
||||
set_bit(WDTS_USE_CIR, &wdt_status);
|
||||
}
|
||||
|
||||
if (timeout < 1 || timeout > max_units * 60) {
|
||||
@ -707,7 +722,7 @@ static int __init it87_wdt_init(void)
|
||||
}
|
||||
|
||||
/* Initialize CIR to use it as keepalive source */
|
||||
if (!test_bit(WDTS_USE_GP, &wdt_status)) {
|
||||
if (test_bit(WDTS_USE_CIR, &wdt_status)) {
|
||||
outb(0x00, CIR_RCR(base));
|
||||
outb(0xc0, CIR_TCR1(base));
|
||||
outb(0x5c, CIR_TCR2(base));
|
||||
@ -717,9 +732,9 @@ static int __init it87_wdt_init(void)
|
||||
outb(0x09, CIR_IER(base));
|
||||
}
|
||||
|
||||
pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d)\n",
|
||||
pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n",
|
||||
chip_type, chip_rev, timeout,
|
||||
nowayout, testmode, exclusive, nogameport);
|
||||
nowayout, testmode, exclusive, nogameport, nocir);
|
||||
|
||||
superio_exit();
|
||||
return 0;
|
||||
@ -727,8 +742,10 @@ static int __init it87_wdt_init(void)
|
||||
err_out_reboot:
|
||||
unregister_reboot_notifier(&wdt_notifier);
|
||||
err_out_region:
|
||||
release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
|
||||
if (!test_bit(WDTS_USE_GP, &wdt_status)) {
|
||||
if (test_bit(WDTS_USE_GP, &wdt_status))
|
||||
release_region(base, 1);
|
||||
else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
|
||||
release_region(base, 8);
|
||||
superio_select(CIR);
|
||||
superio_outb(ciract, ACTREG);
|
||||
}
|
||||
@ -754,7 +771,7 @@ static void __exit it87_wdt_exit(void)
|
||||
if (test_bit(WDTS_USE_GP, &wdt_status)) {
|
||||
superio_select(GAMEPORT);
|
||||
superio_outb(gpact, ACTREG);
|
||||
} else {
|
||||
} else if (test_bit(WDTS_USE_CIR, &wdt_status)) {
|
||||
superio_select(CIR);
|
||||
superio_outb(ciract, ACTREG);
|
||||
}
|
||||
@ -763,7 +780,11 @@ static void __exit it87_wdt_exit(void)
|
||||
|
||||
misc_deregister(&wdt_miscdev);
|
||||
unregister_reboot_notifier(&wdt_notifier);
|
||||
release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
|
||||
|
||||
if (test_bit(WDTS_USE_GP, &wdt_status))
|
||||
release_region(base, 1);
|
||||
else if (test_bit(WDTS_USE_CIR, &wdt_status))
|
||||
release_region(base, 8);
|
||||
}
|
||||
|
||||
module_init(it87_wdt_init);
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -237,6 +237,7 @@ static const struct of_device_id mpc8xxx_wdt_match[] = {
|
||||
.compatible = "fsl,mpc823-wdt",
|
||||
.data = &(struct mpc8xxx_wdt_type) {
|
||||
.prescaler = 0x800,
|
||||
.hw_enabled = true,
|
||||
},
|
||||
},
|
||||
{},
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/completion.h>
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Watchdog Device Driver for Xilinx axi/xps_timebase_wdt
|
||||
*
|
||||
* (C) Copyright 2013 - 2014 Xilinx, Inc.
|
||||
* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -9,18 +10,13 @@
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
@ -43,102 +39,103 @@
|
||||
#define XWT_TIMER_FAILED 0xFFFFFFFF
|
||||
|
||||
#define WATCHDOG_NAME "Xilinx Watchdog"
|
||||
#define PFX WATCHDOG_NAME ": "
|
||||
|
||||
struct xwdt_device {
|
||||
struct resource res;
|
||||
void __iomem *base;
|
||||
u32 nowayout;
|
||||
u32 wdt_interval;
|
||||
u32 boot_status;
|
||||
spinlock_t spinlock;
|
||||
struct watchdog_device xilinx_wdt_wdd;
|
||||
};
|
||||
|
||||
static struct xwdt_device xdev;
|
||||
|
||||
static u32 timeout;
|
||||
static u32 control_status_reg;
|
||||
static u8 expect_close;
|
||||
static u8 no_timeout;
|
||||
static unsigned long driver_open;
|
||||
|
||||
static DEFINE_SPINLOCK(spinlock);
|
||||
|
||||
static void xwdt_start(void)
|
||||
static int xilinx_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
spin_lock(&spinlock);
|
||||
u32 control_status_reg;
|
||||
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||
|
||||
spin_lock(&xdev->spinlock);
|
||||
|
||||
/* Clean previous status and enable the watchdog timer */
|
||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
||||
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
||||
|
||||
iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
|
||||
xdev.base + XWT_TWCSR0_OFFSET);
|
||||
xdev->base + XWT_TWCSR0_OFFSET);
|
||||
|
||||
iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
|
||||
iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET);
|
||||
|
||||
spin_unlock(&spinlock);
|
||||
spin_unlock(&xdev->spinlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xwdt_stop(void)
|
||||
static int xilinx_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
spin_lock(&spinlock);
|
||||
u32 control_status_reg;
|
||||
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||
|
||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
||||
spin_lock(&xdev->spinlock);
|
||||
|
||||
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||
|
||||
iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
|
||||
xdev.base + XWT_TWCSR0_OFFSET);
|
||||
xdev->base + XWT_TWCSR0_OFFSET);
|
||||
|
||||
iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
|
||||
iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET);
|
||||
|
||||
spin_unlock(&spinlock);
|
||||
spin_unlock(&xdev->spinlock);
|
||||
pr_info("Stopped!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xwdt_keepalive(void)
|
||||
static int xilinx_wdt_keepalive(struct watchdog_device *wdd)
|
||||
{
|
||||
spin_lock(&spinlock);
|
||||
u32 control_status_reg;
|
||||
struct xwdt_device *xdev = watchdog_get_drvdata(wdd);
|
||||
|
||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
||||
spin_lock(&xdev->spinlock);
|
||||
|
||||
control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET);
|
||||
control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
|
||||
iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
|
||||
iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET);
|
||||
|
||||
spin_unlock(&spinlock);
|
||||
spin_unlock(&xdev->spinlock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void xwdt_get_status(int *status)
|
||||
{
|
||||
int new_status;
|
||||
static const struct watchdog_info xilinx_wdt_ident = {
|
||||
.options = WDIOF_MAGICCLOSE |
|
||||
WDIOF_KEEPALIVEPING,
|
||||
.firmware_version = 1,
|
||||
.identity = WATCHDOG_NAME,
|
||||
};
|
||||
|
||||
spin_lock(&spinlock);
|
||||
static const struct watchdog_ops xilinx_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = xilinx_wdt_start,
|
||||
.stop = xilinx_wdt_stop,
|
||||
.ping = xilinx_wdt_keepalive,
|
||||
};
|
||||
|
||||
control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
|
||||
new_status = ((control_status_reg &
|
||||
(XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
|
||||
spin_unlock(&spinlock);
|
||||
|
||||
*status = 0;
|
||||
if (new_status & 1)
|
||||
*status |= WDIOF_CARDRESET;
|
||||
}
|
||||
|
||||
static u32 xwdt_selftest(void)
|
||||
static u32 xwdt_selftest(struct xwdt_device *xdev)
|
||||
{
|
||||
int i;
|
||||
u32 timer_value1;
|
||||
u32 timer_value2;
|
||||
|
||||
spin_lock(&spinlock);
|
||||
spin_lock(&xdev->spinlock);
|
||||
|
||||
timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
||||
timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
||||
timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||
timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||
|
||||
for (i = 0;
|
||||
((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
|
||||
(timer_value2 == timer_value1)); i++) {
|
||||
timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
|
||||
timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET);
|
||||
}
|
||||
|
||||
spin_unlock(&spinlock);
|
||||
spin_unlock(&xdev->spinlock);
|
||||
|
||||
if (timer_value2 != timer_value1)
|
||||
return ~XWT_TIMER_FAILED;
|
||||
@ -146,238 +143,83 @@ static u32 xwdt_selftest(void)
|
||||
return XWT_TIMER_FAILED;
|
||||
}
|
||||
|
||||
static int xwdt_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
/* Only one process can handle the wdt at a time */
|
||||
if (test_and_set_bit(0, &driver_open))
|
||||
return -EBUSY;
|
||||
|
||||
/* Make sure that the module are always loaded...*/
|
||||
if (xdev.nowayout)
|
||||
__module_get(THIS_MODULE);
|
||||
|
||||
xwdt_start();
|
||||
pr_info("Started...\n");
|
||||
|
||||
return nonseekable_open(inode, file);
|
||||
}
|
||||
|
||||
static int xwdt_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
if (expect_close == 42) {
|
||||
xwdt_stop();
|
||||
} else {
|
||||
pr_crit("Unexpected close, not stopping watchdog!\n");
|
||||
xwdt_keepalive();
|
||||
}
|
||||
|
||||
clear_bit(0, &driver_open);
|
||||
expect_close = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* xwdt_write:
|
||||
* @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. Any
|
||||
* write of data will do, as we don't define content meaning.
|
||||
*/
|
||||
static ssize_t xwdt_write(struct file *file, const char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
if (len) {
|
||||
if (!xdev.nowayout) {
|
||||
size_t i;
|
||||
|
||||
/* In case it was set long ago */
|
||||
expect_close = 0;
|
||||
|
||||
for (i = 0; i != len; i++) {
|
||||
char c;
|
||||
|
||||
if (get_user(c, buf + i))
|
||||
return -EFAULT;
|
||||
if (c == 'V')
|
||||
expect_close = 42;
|
||||
}
|
||||
}
|
||||
xwdt_keepalive();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct watchdog_info ident = {
|
||||
.options = WDIOF_MAGICCLOSE |
|
||||
WDIOF_KEEPALIVEPING,
|
||||
.firmware_version = 1,
|
||||
.identity = WATCHDOG_NAME,
|
||||
};
|
||||
|
||||
/*
|
||||
* xwdt_ioctl:
|
||||
* @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.
|
||||
*/
|
||||
static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int status;
|
||||
|
||||
union {
|
||||
struct watchdog_info __user *ident;
|
||||
int __user *i;
|
||||
} uarg;
|
||||
|
||||
uarg.i = (int __user *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
case WDIOC_GETSUPPORT:
|
||||
return copy_to_user(uarg.ident, &ident,
|
||||
sizeof(ident)) ? -EFAULT : 0;
|
||||
|
||||
case WDIOC_GETBOOTSTATUS:
|
||||
return put_user(xdev.boot_status, uarg.i);
|
||||
|
||||
case WDIOC_GETSTATUS:
|
||||
xwdt_get_status(&status);
|
||||
return put_user(status, uarg.i);
|
||||
|
||||
case WDIOC_KEEPALIVE:
|
||||
xwdt_keepalive();
|
||||
return 0;
|
||||
|
||||
case WDIOC_GETTIMEOUT:
|
||||
if (no_timeout)
|
||||
return -ENOTTY;
|
||||
else
|
||||
return put_user(timeout, uarg.i);
|
||||
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct file_operations xwdt_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = no_llseek,
|
||||
.write = xwdt_write,
|
||||
.open = xwdt_open,
|
||||
.release = xwdt_release,
|
||||
.unlocked_ioctl = xwdt_ioctl,
|
||||
};
|
||||
|
||||
static struct miscdevice xwdt_miscdev = {
|
||||
.minor = WATCHDOG_MINOR,
|
||||
.name = "watchdog",
|
||||
.fops = &xwdt_fops,
|
||||
};
|
||||
|
||||
static int xwdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc;
|
||||
u32 *tmptr;
|
||||
u32 *pfreq;
|
||||
u32 pfreq = 0, enable_once = 0;
|
||||
struct resource *res;
|
||||
struct xwdt_device *xdev;
|
||||
struct watchdog_device *xilinx_wdt_wdd;
|
||||
|
||||
no_timeout = 0;
|
||||
xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
|
||||
if (!xdev)
|
||||
return -ENOMEM;
|
||||
|
||||
pfreq = (u32 *)of_get_property(pdev->dev.of_node,
|
||||
"clock-frequency", NULL);
|
||||
xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd;
|
||||
xilinx_wdt_wdd->info = &xilinx_wdt_ident;
|
||||
xilinx_wdt_wdd->ops = &xilinx_wdt_ops;
|
||||
xilinx_wdt_wdd->parent = &pdev->dev;
|
||||
|
||||
if (pfreq == NULL) {
|
||||
pr_warn("The watchdog clock frequency cannot be obtained!\n");
|
||||
no_timeout = 1;
|
||||
}
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
xdev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(xdev->base))
|
||||
return PTR_ERR(xdev->base);
|
||||
|
||||
rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
|
||||
if (rc) {
|
||||
pr_warn("invalid address!\n");
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq);
|
||||
if (rc)
|
||||
dev_warn(&pdev->dev,
|
||||
"The watchdog clock frequency cannot be obtained\n");
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval",
|
||||
&xdev->wdt_interval);
|
||||
if (rc)
|
||||
dev_warn(&pdev->dev,
|
||||
"Parameter \"xlnx,wdt-interval\" not found\n");
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once",
|
||||
&enable_once);
|
||||
if (rc)
|
||||
dev_warn(&pdev->dev,
|
||||
"Parameter \"xlnx,wdt-enable-once\" not found\n");
|
||||
|
||||
watchdog_set_nowayout(xilinx_wdt_wdd, enable_once);
|
||||
|
||||
/*
|
||||
* Twice of the 2^wdt_interval / freq because the first wdt overflow is
|
||||
* ignored (interrupt), reset is only generated at second wdt overflow
|
||||
*/
|
||||
if (pfreq && xdev->wdt_interval)
|
||||
xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) /
|
||||
pfreq);
|
||||
|
||||
spin_lock_init(&xdev->spinlock);
|
||||
watchdog_set_drvdata(xilinx_wdt_wdd, xdev);
|
||||
|
||||
rc = xwdt_selftest(xdev);
|
||||
if (rc == XWT_TIMER_FAILED) {
|
||||
dev_err(&pdev->dev, "SelfTest routine error\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
|
||||
"xlnx,wdt-interval", NULL);
|
||||
if (tmptr == NULL) {
|
||||
pr_warn("Parameter \"xlnx,wdt-interval\" not found in device tree!\n");
|
||||
no_timeout = 1;
|
||||
} else {
|
||||
xdev.wdt_interval = *tmptr;
|
||||
}
|
||||
|
||||
tmptr = (u32 *)of_get_property(pdev->dev.of_node,
|
||||
"xlnx,wdt-enable-once", NULL);
|
||||
if (tmptr == NULL) {
|
||||
pr_warn("Parameter \"xlnx,wdt-enable-once\" not found in device tree!\n");
|
||||
xdev.nowayout = WATCHDOG_NOWAYOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Twice of the 2^wdt_interval / freq because the first wdt overflow is
|
||||
* ignored (interrupt), reset is only generated at second wdt overflow
|
||||
*/
|
||||
if (!no_timeout)
|
||||
timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
|
||||
|
||||
if (!request_mem_region(xdev.res.start,
|
||||
xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
|
||||
rc = -ENXIO;
|
||||
pr_err("memory request failure!\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
|
||||
if (xdev.base == NULL) {
|
||||
rc = -ENOMEM;
|
||||
pr_err("ioremap failure!\n");
|
||||
goto release_mem;
|
||||
}
|
||||
|
||||
rc = xwdt_selftest();
|
||||
if (rc == XWT_TIMER_FAILED) {
|
||||
pr_err("SelfTest routine error!\n");
|
||||
goto unmap_io;
|
||||
}
|
||||
|
||||
xwdt_get_status(&xdev.boot_status);
|
||||
|
||||
rc = misc_register(&xwdt_miscdev);
|
||||
rc = watchdog_register_device(xilinx_wdt_wdd);
|
||||
if (rc) {
|
||||
pr_err("cannot register miscdev on minor=%d (err=%d)\n",
|
||||
xwdt_miscdev.minor, rc);
|
||||
goto unmap_io;
|
||||
dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (no_timeout)
|
||||
pr_info("driver loaded (timeout=? sec, nowayout=%d)\n",
|
||||
xdev.nowayout);
|
||||
else
|
||||
pr_info("driver loaded (timeout=%d sec, nowayout=%d)\n",
|
||||
timeout, xdev.nowayout);
|
||||
dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n",
|
||||
xdev->base, xilinx_wdt_wdd->timeout);
|
||||
|
||||
expect_close = 0;
|
||||
clear_bit(0, &driver_open);
|
||||
platform_set_drvdata(pdev, xdev);
|
||||
|
||||
return 0;
|
||||
|
||||
unmap_io:
|
||||
iounmap(xdev.base);
|
||||
release_mem:
|
||||
release_mem_region(xdev.res.start, resource_size(&xdev.res));
|
||||
err_out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int xwdt_remove(struct platform_device *dev)
|
||||
static int xwdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
misc_deregister(&xwdt_miscdev);
|
||||
iounmap(xdev.base);
|
||||
release_mem_region(xdev.res.start, resource_size(&xdev.res));
|
||||
struct xwdt_device *xdev = platform_get_drvdata(pdev);
|
||||
|
||||
watchdog_unregister_device(&xdev->xilinx_wdt_wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -58,7 +57,6 @@ struct omap_wdt_dev {
|
||||
void __iomem *base; /* physical */
|
||||
struct device *dev;
|
||||
bool omap_wdt_users;
|
||||
struct resource *mem;
|
||||
int wdt_trgr_pattern;
|
||||
struct mutex lock; /* to avoid races with PM */
|
||||
};
|
||||
@ -207,7 +205,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct watchdog_device *omap_wdt;
|
||||
struct resource *res, *mem;
|
||||
struct resource *res;
|
||||
struct omap_wdt_dev *wdev;
|
||||
u32 rs;
|
||||
int ret;
|
||||
@ -216,29 +214,20 @@ static int omap_wdt_probe(struct platform_device *pdev)
|
||||
if (!omap_wdt)
|
||||
return -ENOMEM;
|
||||
|
||||
/* reserve static register mappings */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
mem = devm_request_mem_region(&pdev->dev, res->start,
|
||||
resource_size(res), pdev->name);
|
||||
if (!mem)
|
||||
return -EBUSY;
|
||||
|
||||
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
|
||||
if (!wdev)
|
||||
return -ENOMEM;
|
||||
|
||||
wdev->omap_wdt_users = false;
|
||||
wdev->mem = mem;
|
||||
wdev->dev = &pdev->dev;
|
||||
wdev->wdt_trgr_pattern = 0x1234;
|
||||
mutex_init(&wdev->lock);
|
||||
|
||||
wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!wdev->base)
|
||||
return -ENOMEM;
|
||||
/* reserve static register mappings */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wdev->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(wdev->base))
|
||||
return PTR_ERR(wdev->base);
|
||||
|
||||
omap_wdt->info = &omap_wdt_info;
|
||||
omap_wdt->ops = &omap_wdt_ops;
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk.h>
|
||||
|
@ -512,9 +512,8 @@ static int __init pc87413_init(void)
|
||||
return -EBUSY;
|
||||
|
||||
ret = register_reboot_notifier(&pc87413_notifier);
|
||||
if (ret != 0) {
|
||||
if (ret != 0)
|
||||
pr_err("cannot register reboot notifier (err=%d)\n", ret);
|
||||
}
|
||||
|
||||
ret = misc_register(&pc87413_miscdev);
|
||||
if (ret != 0) {
|
||||
@ -575,8 +574,8 @@ static void __exit pc87413_exit(void)
|
||||
module_init(pc87413_init);
|
||||
module_exit(pc87413_exit);
|
||||
|
||||
MODULE_AUTHOR("Sven Anders <anders@anduras.de>, "
|
||||
"Marcus Junker <junker@anduras.de>,");
|
||||
MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
|
||||
MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
|
||||
MODULE_DESCRIPTION("PC87413 WDT driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -645,10 +645,8 @@ static int usb_pcwd_probe(struct usb_interface *interface,
|
||||
|
||||
/* allocate memory for our device and initialize it */
|
||||
usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL);
|
||||
if (usb_pcwd == NULL) {
|
||||
pr_err("Out of memory\n");
|
||||
if (usb_pcwd == NULL)
|
||||
goto error;
|
||||
}
|
||||
|
||||
usb_pcwd_device = usb_pcwd;
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/completion.h>
|
||||
|
@ -16,7 +16,6 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
|
@ -10,7 +10,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/of.h>
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
@ -526,7 +525,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
clk_prepare_enable(wdt->clock);
|
||||
ret = clk_prepare_enable(wdt->clock);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = s3c2410wdt_cpufreq_register(wdt);
|
||||
if (ret < 0) {
|
||||
@ -608,7 +611,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(wdt->clock);
|
||||
wdt->clock = NULL;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
@ -628,7 +630,6 @@ static int s3c2410wdt_remove(struct platform_device *dev)
|
||||
s3c2410wdt_cpufreq_deregister(wdt);
|
||||
|
||||
clk_disable_unprepare(wdt->clock);
|
||||
wdt->clock = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -158,12 +158,11 @@ static void wdt_timer_ping(unsigned long data)
|
||||
|
||||
static void wdt_config(int writeval)
|
||||
{
|
||||
__u16 dummy;
|
||||
unsigned long flags;
|
||||
|
||||
/* buy some time (ping) */
|
||||
spin_lock_irqsave(&wdt_spinlock, flags);
|
||||
dummy = readw(wdtmrctl); /* ensure write synchronization */
|
||||
readw(wdtmrctl); /* ensure write synchronization */
|
||||
writew(0xAAAA, wdtmrctl);
|
||||
writew(0x5555, wdtmrctl);
|
||||
/* unlock WDT = make WDT configuration register writable one time */
|
||||
|
@ -293,8 +293,6 @@ static int sh_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
static int sh_wdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_wdt *wdt = platform_get_drvdata(pdev);
|
||||
|
||||
watchdog_unregister_device(&sh_wdt_dev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
@ -62,7 +62,7 @@ MODULE_PARM_DESC(nowayout,
|
||||
"Watchdog cannot be stopped once started (default="
|
||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
|
||||
static int soft_noboot = 0;
|
||||
static int soft_noboot;
|
||||
module_param(soft_noboot, int, 0);
|
||||
MODULE_PARM_DESC(soft_noboot,
|
||||
"Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/amba/bus.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -209,27 +208,15 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
|
||||
struct sp805_wdt *wdt;
|
||||
int ret = 0;
|
||||
|
||||
if (!devm_request_mem_region(&adev->dev, adev->res.start,
|
||||
resource_size(&adev->res), "sp805_wdt")) {
|
||||
dev_warn(&adev->dev, "Failed to get memory region resource\n");
|
||||
ret = -ENOENT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
|
||||
if (!wdt) {
|
||||
dev_warn(&adev->dev, "Kzalloc failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
wdt->base = devm_ioremap(&adev->dev, adev->res.start,
|
||||
resource_size(&adev->res));
|
||||
if (!wdt->base) {
|
||||
ret = -ENOMEM;
|
||||
dev_warn(&adev->dev, "ioremap fail\n");
|
||||
goto err;
|
||||
}
|
||||
wdt->base = devm_ioremap_resource(&adev->dev, &adev->res);
|
||||
if (IS_ERR(wdt->base))
|
||||
return PTR_ERR(wdt->base);
|
||||
|
||||
wdt->clk = devm_clk_get(&adev->dev, NULL);
|
||||
if (IS_ERR(wdt->clk)) {
|
||||
|
@ -9,7 +9,6 @@
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
@ -205,7 +205,7 @@ static void sunxi_wdt_shutdown(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id sunxi_wdt_dt_ids[] = {
|
||||
{ .compatible = "allwinner,sun4i-wdt" },
|
||||
{ .compatible = "allwinner,sun4i-a10-wdt" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
|
||||
|
302
drivers/watchdog/tegra_wdt.c
Normal file
302
drivers/watchdog/tegra_wdt.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
/* minimum and maximum watchdog trigger timeout, in seconds */
|
||||
#define MIN_WDT_TIMEOUT 1
|
||||
#define MAX_WDT_TIMEOUT 255
|
||||
|
||||
/*
|
||||
* Base of the WDT registers, from the timer base address. There are
|
||||
* actually 5 watchdogs that can be configured (by pairing with an available
|
||||
* timer), at bases 0x100 + (WDT ID) * 0x20, where WDT ID is 0 through 4.
|
||||
* This driver only configures the first watchdog (WDT ID 0).
|
||||
*/
|
||||
#define WDT_BASE 0x100
|
||||
#define WDT_ID 0
|
||||
|
||||
/*
|
||||
* Register base of the timer that's selected for pairing with the watchdog.
|
||||
* This driver arbitrarily uses timer 5, which is currently unused by
|
||||
* other drivers (in particular, the Tegra clocksource driver). If this
|
||||
* needs to change, take care that the new timer is not used by the
|
||||
* clocksource driver.
|
||||
*/
|
||||
#define WDT_TIMER_BASE 0x60
|
||||
#define WDT_TIMER_ID 5
|
||||
|
||||
/* WDT registers */
|
||||
#define WDT_CFG 0x0
|
||||
#define WDT_CFG_PERIOD_SHIFT 4
|
||||
#define WDT_CFG_PERIOD_MASK 0xff
|
||||
#define WDT_CFG_INT_EN (1 << 12)
|
||||
#define WDT_CFG_PMC2CAR_RST_EN (1 << 15)
|
||||
#define WDT_STS 0x4
|
||||
#define WDT_STS_COUNT_SHIFT 4
|
||||
#define WDT_STS_COUNT_MASK 0xff
|
||||
#define WDT_STS_EXP_SHIFT 12
|
||||
#define WDT_STS_EXP_MASK 0x3
|
||||
#define WDT_CMD 0x8
|
||||
#define WDT_CMD_START_COUNTER (1 << 0)
|
||||
#define WDT_CMD_DISABLE_COUNTER (1 << 1)
|
||||
#define WDT_UNLOCK (0xc)
|
||||
#define WDT_UNLOCK_PATTERN (0xc45a << 0)
|
||||
|
||||
/* Timer registers */
|
||||
#define TIMER_PTV 0x0
|
||||
#define TIMER_EN (1 << 31)
|
||||
#define TIMER_PERIODIC (1 << 30)
|
||||
|
||||
struct tegra_wdt {
|
||||
struct watchdog_device wdd;
|
||||
void __iomem *wdt_regs;
|
||||
void __iomem *tmr_regs;
|
||||
};
|
||||
|
||||
#define WDT_HEARTBEAT 120
|
||||
static int heartbeat = WDT_HEARTBEAT;
|
||||
module_param(heartbeat, int, 0);
|
||||
MODULE_PARM_DESC(heartbeat,
|
||||
"Watchdog heartbeats in seconds. (default = "
|
||||
__MODULE_STRING(WDT_HEARTBEAT) ")");
|
||||
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
module_param(nowayout, bool, 0);
|
||||
MODULE_PARM_DESC(nowayout,
|
||||
"Watchdog cannot be stopped once started (default="
|
||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
|
||||
static int tegra_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
* This thing has a fixed 1MHz clock. Normally, we would set the
|
||||
* period to 1 second by writing 1000000ul, but the watchdog system
|
||||
* reset actually occurs on the 4th expiration of this counter,
|
||||
* so we set the period to 1/4 of this amount.
|
||||
*/
|
||||
val = 1000000ul / 4;
|
||||
val |= (TIMER_EN | TIMER_PERIODIC);
|
||||
writel(val, wdt->tmr_regs + TIMER_PTV);
|
||||
|
||||
/*
|
||||
* Set number of periods and start counter.
|
||||
*
|
||||
* Interrupt handler is not required for user space
|
||||
* WDT accesses, since the caller is responsible to ping the
|
||||
* WDT to reset the counter before expiration, through ioctls.
|
||||
*/
|
||||
val = WDT_TIMER_ID |
|
||||
(wdd->timeout << WDT_CFG_PERIOD_SHIFT) |
|
||||
WDT_CFG_PMC2CAR_RST_EN;
|
||||
writel(val, wdt->wdt_regs + WDT_CFG);
|
||||
|
||||
writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
writel(WDT_UNLOCK_PATTERN, wdt->wdt_regs + WDT_UNLOCK);
|
||||
writel(WDT_CMD_DISABLE_COUNTER, wdt->wdt_regs + WDT_CMD);
|
||||
writel(0, wdt->tmr_regs + TIMER_PTV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
writel(WDT_CMD_START_COUNTER, wdt->wdt_regs + WDT_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
|
||||
unsigned int timeout)
|
||||
{
|
||||
wdd->timeout = timeout;
|
||||
|
||||
if (watchdog_active(wdd))
|
||||
return tegra_wdt_start(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int tegra_wdt_get_timeleft(struct watchdog_device *wdd)
|
||||
{
|
||||
struct tegra_wdt *wdt = watchdog_get_drvdata(wdd);
|
||||
u32 val;
|
||||
int count;
|
||||
int exp;
|
||||
|
||||
val = readl(wdt->wdt_regs + WDT_STS);
|
||||
|
||||
/* Current countdown (from timeout) */
|
||||
count = (val >> WDT_STS_COUNT_SHIFT) & WDT_STS_COUNT_MASK;
|
||||
|
||||
/* Number of expirations (we are waiting for the 4th expiration) */
|
||||
exp = (val >> WDT_STS_EXP_SHIFT) & WDT_STS_EXP_MASK;
|
||||
|
||||
/*
|
||||
* The entire thing is divided by 4 because we are ticking down 4 times
|
||||
* faster due to needing to wait for the 4th expiration.
|
||||
*/
|
||||
return (((3 - exp) * wdd->timeout) + count) / 4;
|
||||
}
|
||||
|
||||
static const struct watchdog_info tegra_wdt_info = {
|
||||
.options = WDIOF_SETTIMEOUT |
|
||||
WDIOF_MAGICCLOSE |
|
||||
WDIOF_KEEPALIVEPING,
|
||||
.firmware_version = 0,
|
||||
.identity = "Tegra Watchdog",
|
||||
};
|
||||
|
||||
static struct watchdog_ops tegra_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = tegra_wdt_start,
|
||||
.stop = tegra_wdt_stop,
|
||||
.ping = tegra_wdt_ping,
|
||||
.set_timeout = tegra_wdt_set_timeout,
|
||||
.get_timeleft = tegra_wdt_get_timeleft,
|
||||
};
|
||||
|
||||
static int tegra_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct watchdog_device *wdd;
|
||||
struct tegra_wdt *wdt;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
int ret;
|
||||
|
||||
/* This is the timer base. */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
/*
|
||||
* Allocate our watchdog driver data, which has the
|
||||
* struct watchdog_device nested within it.
|
||||
*/
|
||||
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Initialize struct tegra_wdt. */
|
||||
wdt->wdt_regs = regs + WDT_BASE;
|
||||
wdt->tmr_regs = regs + WDT_TIMER_BASE;
|
||||
|
||||
/* Initialize struct watchdog_device. */
|
||||
wdd = &wdt->wdd;
|
||||
wdd->timeout = heartbeat;
|
||||
wdd->info = &tegra_wdt_info;
|
||||
wdd->ops = &tegra_wdt_ops;
|
||||
wdd->min_timeout = MIN_WDT_TIMEOUT;
|
||||
wdd->max_timeout = MAX_WDT_TIMEOUT;
|
||||
|
||||
watchdog_set_drvdata(wdd, wdt);
|
||||
|
||||
watchdog_set_nowayout(wdd, nowayout);
|
||||
|
||||
ret = watchdog_register_device(wdd);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to register watchdog device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, wdt);
|
||||
|
||||
dev_info(&pdev->dev,
|
||||
"initialized (heartbeat = %d sec, nowayout = %d)\n",
|
||||
heartbeat, nowayout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_wdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_wdt *wdt = platform_get_drvdata(pdev);
|
||||
|
||||
tegra_wdt_stop(&wdt->wdd);
|
||||
|
||||
watchdog_unregister_device(&wdt->wdd);
|
||||
|
||||
dev_info(&pdev->dev, "removed wdt\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tegra_wdt_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct tegra_wdt *wdt = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&wdt->wdd))
|
||||
tegra_wdt_stop(&wdt->wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_wdt_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct tegra_wdt *wdt = dev_get_drvdata(dev);
|
||||
|
||||
if (watchdog_active(&wdt->wdd))
|
||||
tegra_wdt_start(&wdt->wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct of_device_id tegra_wdt_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra30-timer", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_wdt_of_match);
|
||||
|
||||
static const struct dev_pm_ops tegra_wdt_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(tegra_wdt_runtime_suspend,
|
||||
tegra_wdt_runtime_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver tegra_wdt_driver = {
|
||||
.probe = tegra_wdt_probe,
|
||||
.remove = tegra_wdt_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tegra-wdt",
|
||||
.pm = &tegra_wdt_pm_ops,
|
||||
.of_match_table = tegra_wdt_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(tegra_wdt_driver);
|
||||
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_DESCRIPTION("Tegra Watchdog Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -61,7 +61,7 @@ struct ts72xx_wdt {
|
||||
struct platform_device *pdev;
|
||||
};
|
||||
|
||||
struct platform_device *ts72xx_wdt_pdev;
|
||||
static struct platform_device *ts72xx_wdt_pdev;
|
||||
|
||||
/*
|
||||
* TS-72xx Watchdog supports following timeouts (value written
|
||||
@ -394,10 +394,8 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
|
||||
int error = 0;
|
||||
|
||||
wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
|
||||
if (!wdt) {
|
||||
dev_err(&pdev->dev, "failed to allocate memory\n");
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
|
||||
|
@ -455,6 +455,6 @@ module_init(wdt_init);
|
||||
module_exit(wdt_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, "
|
||||
"Samuel Tardieu <sam@rfc1149.net>");
|
||||
MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
|
||||
MODULE_AUTHOR("Samuel Tardieu <sam@rfc1149.net>");
|
||||
MODULE_DESCRIPTION("w83697hf/hg WDT driver");
|
||||
|
@ -139,9 +139,8 @@ static const struct watchdog_info ident = {
|
||||
static long watchdog_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
unsigned int new_margin;
|
||||
int __user *int_arg = (int __user *)arg;
|
||||
int ret = -ENOTTY;
|
||||
int new_margin, ret = -ENOTTY;
|
||||
|
||||
switch (cmd) {
|
||||
case WDIOC_GETSUPPORT:
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -204,7 +204,6 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
|
||||
driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
|
||||
GFP_KERNEL);
|
||||
if (!driver_data) {
|
||||
dev_err(wm831x->dev, "Unable to alloacate watchdog device\n");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user