mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-08-18 02:22:47 -07:00
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck:
"This adds following items:
- watchdog restart handler support
- watchdog reboot notifier support
- watchdog sysfs attributes
- support for the following new devices: AMD Mullins platform, AMD
Carrizo platform, meson8b SoC, CSRatlas7, TS-4800, Alphascale
asm9260-wdt, Zodiac, Sigma Designs SMP86xx/SMP87xx
- Changes in refcounting for the watchdog core
- watchdog core improvements
- and small fixes"
* git://www.linux-watchdog.org/linux-watchdog: (60 commits)
watchdog: asm9260: remove __init and __exit annotations
watchdog: Drop pointer to watchdog device from struct watchdog_device
watchdog: ziirave: Use watchdog infrastructure to create sysfs attributes
watchdog: Add support for creating driver specific sysfs attributes
watchdog: kill unref/ref ops
watchdog: stmp3xxx: Remove unused variables
watchdog: add MT7621 watchdog support
hwmon: (sch56xx) Drop watchdog driver data reference count callbacks
watchdog: da9055_wdt: Drop reference counting
watchdog: da9052_wdt: Drop reference counting
watchdog: Separate and maintain variables based on variable lifetime
watchdog: diag288: Stop re-using watchdog core internal flags
watchdog: Create watchdog device in watchdog_dev.c
watchdog: qcom-wdt: Do not set 'dev' in struct watchdog_device
watchdog: mena21: Do not use device pointer from struct watchdog_device
watchdog: gpio: Do not use device pointer from struct watchdog_device
watchdog: tangox: Print info message using pointer to platform device
watchdog: bcm2835_wdt: Drop log message if watchdog is stopped
devicetree: watchdog: add binding for Sigma Designs SMP8642 watchdog
watchdog: add support for Sigma Designs SMP86xx/SMP87xx
...
This commit is contained in:
commit
6606b342fe
48 files changed
+2693
-837
No files matched your search
@@ -0,0 +1,51 @@
|
||||
What: /sys/class/watchdog/watchdogn/bootstatus
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It contains status of the watchdog
|
||||
device at boot. It is equivalent to WDIOC_GETBOOTSTATUS of
|
||||
ioctl interface.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/identity
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It contains identity string of
|
||||
watchdog device.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/nowayout
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. While reading, it gives '1' if that
|
||||
device supports nowayout feature else, it gives '0'.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/state
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It gives active/inactive status of
|
||||
watchdog device.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/status
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It contains watchdog device's
|
||||
internal status bits. It is equivalent to WDIOC_GETSTATUS
|
||||
of ioctl interface.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/timeleft
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It contains value of time left for
|
||||
reset generation. It is equivalent to WDIOC_GETTIMELEFT of
|
||||
ioctl interface.
|
||||
|
||||
What: /sys/class/watchdog/watchdogn/timeout
|
||||
Date: August 2015
|
||||
Contact: Wim Van Sebroeck <wim@iguana.be>
|
||||
Description:
|
||||
It is a read only file. It is read to know about current
|
||||
value of timeout programmed.
|
||||
@@ -0,0 +1,35 @@
|
||||
Alphascale asm9260 Watchdog timer
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "alphascale,asm9260-wdt".
|
||||
- reg : Specifies base physical address and size of the registers.
|
||||
- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt
|
||||
- clock-names : should be set to
|
||||
"mod" - source for tick counter.
|
||||
"ahb" - ahb gate.
|
||||
- resets : phandle pointing to the system reset controller with
|
||||
line index for the watchdog.
|
||||
- reset-names : should be set to "wdt_rst".
|
||||
|
||||
Optional properties:
|
||||
- timeout-sec : shall contain the default watchdog timeout in seconds,
|
||||
if unset, the default timeout is 30 seconds.
|
||||
- alphascale,mode : three modes are supported
|
||||
"hw" - hw reset (default).
|
||||
"sw" - sw reset.
|
||||
"debug" - no action is taken.
|
||||
|
||||
Example:
|
||||
|
||||
watchdog0: watchdog@80048000 {
|
||||
compatible = "alphascale,asm9260-wdt";
|
||||
reg = <0x80048000 0x10>;
|
||||
clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>;
|
||||
clock-names = "mod", "ahb";
|
||||
interrupts = <55>;
|
||||
resets = <&rst WDT_RESET>;
|
||||
reset-names = "wdt_rst";
|
||||
timeout-sec = <30>;
|
||||
alphascale,mode = "hw";
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
Ralink Watchdog Timers
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "mediatek,mt7621-wdt"
|
||||
- reg: physical base address of the controller and length of the register range
|
||||
|
||||
Example:
|
||||
|
||||
watchdog@100 {
|
||||
compatible = "mediatek,mt7621-wdt";
|
||||
reg = <0x100 0x10>;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
Sigma Designs SMP86xx/SMP87xx watchdog
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "sigma,smp8642-wdt"
|
||||
- reg: Specifies the physical address region
|
||||
- clocks: Should be a phandle to the clock
|
||||
|
||||
Optional properties:
|
||||
- timeout-sec: watchdog timeout in seconds
|
||||
|
||||
Example:
|
||||
|
||||
watchdog@1fd00 {
|
||||
compatible = "sigma,smp8642-wdt";
|
||||
reg = <0x1fd00 8>;
|
||||
clocks = <&xtal_in_clk>;
|
||||
timeout-sec = <30>;
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
Technologic Systems Watchdog
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "technologic,ts4800-wdt"
|
||||
- syscon: phandle / integer array that points to the syscon node which
|
||||
describes the FPGA's syscon registers.
|
||||
- phandle to FPGA's syscon
|
||||
- offset to the watchdog register
|
||||
|
||||
Optional property:
|
||||
- timeout-sec: contains the watchdog timeout in seconds.
|
||||
|
||||
Example:
|
||||
|
||||
syscon: syscon@b0010000 {
|
||||
compatible = "syscon", "simple-mfd";
|
||||
reg = <0xb0010000 0x3d>;
|
||||
reg-io-width = <2>;
|
||||
|
||||
wdt@e {
|
||||
compatible = "technologic,ts4800-wdt";
|
||||
syscon = <&syscon 0xe>;
|
||||
timeout-sec = <10>;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
Zodiac RAVE Watchdog Timer
|
||||
|
||||
Required properties:
|
||||
- compatible: must be "zii,rave-wdt"
|
||||
- reg: i2c slave address of device, usually 0x38
|
||||
|
||||
Optional Properties:
|
||||
- timeout-sec: Watchdog timeout value in seconds.
|
||||
- reset-duration-ms: Duration of the pulse generated when the watchdog times
|
||||
out. Value in milliseconds.
|
||||
|
||||
Example:
|
||||
|
||||
watchdog@38 {
|
||||
compatible = "zii,rave-wdt";
|
||||
reg = <0x38>;
|
||||
timeout-sec = <30>;
|
||||
reset-duration-ms = <30>;
|
||||
};
|
||||
@@ -44,17 +44,18 @@ The watchdog device structure looks like this:
|
||||
|
||||
struct watchdog_device {
|
||||
int id;
|
||||
struct cdev cdev;
|
||||
struct device *dev;
|
||||
struct device *parent;
|
||||
const struct attribute_group **groups;
|
||||
const struct watchdog_info *info;
|
||||
const struct watchdog_ops *ops;
|
||||
unsigned int bootstatus;
|
||||
unsigned int timeout;
|
||||
unsigned int min_timeout;
|
||||
unsigned int max_timeout;
|
||||
struct notifier_block reboot_nb;
|
||||
struct notifier_block restart_nb;
|
||||
void *driver_data;
|
||||
struct mutex lock;
|
||||
struct watchdog_core_data *wd_data;
|
||||
unsigned long status;
|
||||
struct list_head deferred;
|
||||
};
|
||||
@@ -64,27 +65,32 @@ It contains following fields:
|
||||
/dev/watchdog0 cdev (dynamic major, minor 0) as well as the old
|
||||
/dev/watchdog miscdev. The id is set automatically when calling
|
||||
watchdog_register_device.
|
||||
* cdev: cdev for the dynamic /dev/watchdog<id> device nodes. This
|
||||
field is also populated by watchdog_register_device.
|
||||
* dev: device under the watchdog class (created by watchdog_register_device).
|
||||
* parent: set this to the parent device (or NULL) before calling
|
||||
watchdog_register_device.
|
||||
* groups: List of sysfs attribute groups to create when creating the watchdog
|
||||
device.
|
||||
* info: a pointer to a watchdog_info structure. This structure gives some
|
||||
additional information about the watchdog timer itself. (Like it's unique name)
|
||||
* ops: a pointer to the list of watchdog operations that the watchdog supports.
|
||||
* timeout: the watchdog timer's timeout value (in seconds).
|
||||
* min_timeout: the watchdog timer's minimum timeout value (in seconds).
|
||||
* max_timeout: the watchdog timer's maximum timeout value (in seconds).
|
||||
* reboot_nb: notifier block that is registered for reboot notifications, for
|
||||
internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core
|
||||
will stop the watchdog on such notifications.
|
||||
* restart_nb: notifier block that is registered for machine restart, for
|
||||
internal use only. If a watchdog is capable of restarting the machine, it
|
||||
should define ops->restart. Priority can be changed through
|
||||
watchdog_set_restart_priority.
|
||||
* bootstatus: status of the device after booting (reported with watchdog
|
||||
WDIOF_* status bits).
|
||||
* driver_data: a pointer to the drivers private data of a watchdog device.
|
||||
This data should only be accessed via the watchdog_set_drvdata and
|
||||
watchdog_get_drvdata routines.
|
||||
* lock: Mutex for WatchDog Timer Driver Core internal use only.
|
||||
* wd_data: a pointer to watchdog core internal data.
|
||||
* status: this field contains a number of status bits that give extra
|
||||
information about the status of the device (Like: is the watchdog timer
|
||||
running/active, is the nowayout bit set, is the device opened via
|
||||
the /dev/watchdog interface or not, ...).
|
||||
running/active, or is the nowayout bit set).
|
||||
* deferred: entry in wtd_deferred_reg_list which is used to
|
||||
register early initialized watchdogs.
|
||||
|
||||
@@ -100,8 +106,9 @@ struct watchdog_ops {
|
||||
unsigned int (*status)(struct watchdog_device *);
|
||||
int (*set_timeout)(struct watchdog_device *, unsigned int);
|
||||
unsigned int (*get_timeleft)(struct watchdog_device *);
|
||||
void (*ref)(struct watchdog_device *);
|
||||
void (*unref)(struct watchdog_device *);
|
||||
int (*restart)(struct watchdog_device *);
|
||||
void (*ref)(struct watchdog_device *) __deprecated;
|
||||
void (*unref)(struct watchdog_device *) __deprecated;
|
||||
long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
|
||||
};
|
||||
|
||||
@@ -110,20 +117,6 @@ driver's operations. This module owner will be used to lock the module when
|
||||
the watchdog is active. (This to avoid a system crash when you unload the
|
||||
module and /dev/watchdog is still open).
|
||||
|
||||
If the watchdog_device struct is dynamically allocated, just locking the module
|
||||
is not enough and a driver also needs to define the ref and unref operations to
|
||||
ensure the structure holding the watchdog_device does not go away.
|
||||
|
||||
The simplest (and usually sufficient) implementation of this is to:
|
||||
1) Add a kref struct to the same structure which is holding the watchdog_device
|
||||
2) Define a release callback for the kref which frees the struct holding both
|
||||
3) Call kref_init on this kref *before* calling watchdog_register_device()
|
||||
4) Define a ref operation calling kref_get on this kref
|
||||
5) Define a unref operation calling kref_put on this kref
|
||||
6) When it is time to cleanup:
|
||||
* Do not kfree() the struct holding both, the last kref_put will do this!
|
||||
* *After* calling watchdog_unregister_device() call kref_put on the kref
|
||||
|
||||
Some operations are mandatory and some are optional. The mandatory operations
|
||||
are:
|
||||
* start: this is a pointer to the routine that starts the watchdog timer
|
||||
@@ -164,34 +157,23 @@ they are supported. These optional routines/operations are:
|
||||
(Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
|
||||
watchdog's info structure).
|
||||
* get_timeleft: this routines returns the time that's left before a reset.
|
||||
* ref: the operation that calls kref_get on the kref of a dynamically
|
||||
allocated watchdog_device struct.
|
||||
* unref: the operation that calls kref_put on the kref of a dynamically
|
||||
allocated watchdog_device struct.
|
||||
* restart: this routine restarts the machine. It returns 0 on success or a
|
||||
negative errno code for failure.
|
||||
* ioctl: if this routine is present then it will be called first before we do
|
||||
our own internal ioctl call handling. This routine should return -ENOIOCTLCMD
|
||||
if a command is not supported. The parameters that are passed to the ioctl
|
||||
call are: watchdog_device, cmd and arg.
|
||||
|
||||
The 'ref' and 'unref' operations are no longer used and deprecated.
|
||||
|
||||
The status bits should (preferably) be set with the set_bit and clear_bit alike
|
||||
bit-operations. The status bits that are defined are:
|
||||
* WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
|
||||
is active or not. When the watchdog is active after booting, then you should
|
||||
set this status bit (Note: when you register the watchdog timer device with
|
||||
this bit set, then opening /dev/watchdog will skip the start operation)
|
||||
* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device
|
||||
was opened via /dev/watchdog.
|
||||
(This bit should only be used by the WatchDog Timer Driver Core).
|
||||
* WDOG_ALLOW_RELEASE: this bit stores whether or not the magic close character
|
||||
has been sent (so that we can support the magic close feature).
|
||||
(This bit should only be used by the WatchDog Timer Driver Core).
|
||||
* WDOG_NO_WAY_OUT: this bit stores the nowayout setting for the watchdog.
|
||||
If this bit is set then the watchdog timer will not be able to stop.
|
||||
* WDOG_UNREGISTERED: this bit gets set by the WatchDog Timer Driver Core
|
||||
after calling watchdog_unregister_device, and then checked before calling
|
||||
any watchdog_ops, so that you can be sure that no operations (other then
|
||||
unref) will get called after unregister, even if userspace still holds a
|
||||
reference to /dev/watchdog
|
||||
|
||||
To set the WDOG_NO_WAY_OUT status bit (before registering your watchdog
|
||||
timer device) you can either:
|
||||
@@ -231,3 +213,18 @@ the device tree (if the module timeout parameter is invalid). Best practice is
|
||||
to set the default timeout value as timeout value in the watchdog_device and
|
||||
then use this function to set the user "preferred" timeout value.
|
||||
This routine returns zero on success and a negative errno code for failure.
|
||||
|
||||
To disable the watchdog on reboot, the user must call the following helper:
|
||||
|
||||
static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
|
||||
|
||||
To change the priority of the restart handler the following helper should be
|
||||
used:
|
||||
|
||||
void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
|
||||
|
||||
User should follow the following guidelines for setting the priority:
|
||||
* 0: should be called in last resort, has limited restart capabilities
|
||||
* 128: default restart handler, use if no other handler is expected to be
|
||||
available, and/or if restart is sufficient to restart the entire system
|
||||
* 255: highest priority, will preempt all other restart handlers
|
||||
@@ -11676,6 +11676,7 @@ F: drivers/input/tablet/wacom_serial4.c
|
||||
|
||||
WATCHDOG DEVICE DRIVERS
|
||||
M: Wim Van Sebroeck <wim@iguana.be>
|
||||
R: Guenter Roeck <linux@roeck-us.net>
|
||||
L: linux-watchdog@vger.kernel.org
|
||||
W: http://www.linux-watchdog.org/
|
||||
T: git git://www.linux-watchdog.org/linux-watchdog.git
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include "sch56xx-common.h"
|
||||
|
||||
@@ -67,7 +66,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||
struct sch56xx_watchdog_data {
|
||||
u16 addr;
|
||||
struct mutex *io_lock;
|
||||
struct kref kref;
|
||||
struct watchdog_info wdinfo;
|
||||
struct watchdog_device wddev;
|
||||
u8 watchdog_preset;
|
||||
@@ -258,15 +256,6 @@ EXPORT_SYMBOL(sch56xx_read_virtual_reg12);
|
||||
* Watchdog routines
|
||||
*/
|
||||
|
||||
/* Release our data struct when we're unregistered *and*
|
||||
all references to our watchdog device are released */
|
||||
static void watchdog_release_resources(struct kref *r)
|
||||
{
|
||||
struct sch56xx_watchdog_data *data =
|
||||
container_of(r, struct sch56xx_watchdog_data, kref);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int watchdog_set_timeout(struct watchdog_device *wddev,
|
||||
unsigned int timeout)
|
||||
{
|
||||
@@ -395,28 +384,12 @@ static int watchdog_stop(struct watchdog_device *wddev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void watchdog_ref(struct watchdog_device *wddev)
|
||||
{
|
||||
struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
|
||||
|
||||
kref_get(&data->kref);
|
||||
}
|
||||
|
||||
static void watchdog_unref(struct watchdog_device *wddev)
|
||||
{
|
||||
struct sch56xx_watchdog_data *data = watchdog_get_drvdata(wddev);
|
||||
|
||||
kref_put(&data->kref, watchdog_release_resources);
|
||||
}
|
||||
|
||||
static const struct watchdog_ops watchdog_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = watchdog_start,
|
||||
.stop = watchdog_stop,
|
||||
.ping = watchdog_trigger,
|
||||
.set_timeout = watchdog_set_timeout,
|
||||
.ref = watchdog_ref,
|
||||
.unref = watchdog_unref,
|
||||
};
|
||||
|
||||
struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
|
||||
@@ -448,7 +421,6 @@ struct sch56xx_watchdog_data *sch56xx_watchdog_register(struct device *parent,
|
||||
|
||||
data->addr = addr;
|
||||
data->io_lock = io_lock;
|
||||
kref_init(&data->kref);
|
||||
|
||||
strlcpy(data->wdinfo.identity, "sch56xx watchdog",
|
||||
sizeof(data->wdinfo.identity));
|
||||
@@ -494,8 +466,7 @@ EXPORT_SYMBOL(sch56xx_watchdog_register);
|
||||
void sch56xx_watchdog_unregister(struct sch56xx_watchdog_data *data)
|
||||
{
|
||||
watchdog_unregister_device(&data->wddev);
|
||||
kref_put(&data->kref, watchdog_release_resources);
|
||||
/* Don't touch data after this it may have been free-ed! */
|
||||
kfree(data);
|
||||
}
|
||||
EXPORT_SYMBOL(sch56xx_watchdog_unregister);
|
||||
|
||||
|
||||
@@ -46,6 +46,13 @@ config WATCHDOG_NOWAYOUT
|
||||
get killed. If you say Y here, the watchdog cannot be stopped once
|
||||
it has been started.
|
||||
|
||||
config WATCHDOG_SYSFS
|
||||
bool "Read different watchdog information through sysfs"
|
||||
default n
|
||||
help
|
||||
Say Y here if you want to enable watchdog device status read through
|
||||
sysfs attributes.
|
||||
|
||||
#
|
||||
# General Watchdog drivers
|
||||
#
|
||||
@@ -135,6 +142,16 @@ config MENF21BMC_WATCHDOG
|
||||
This driver can also be built as a module. If so the module
|
||||
will be called menf21bmc_wdt.
|
||||
|
||||
config TANGOX_WATCHDOG
|
||||
tristate "Sigma Designs SMP86xx/SMP87xx watchdog"
|
||||
select WATCHDOG_CORE
|
||||
depends on ARCH_TANGOX || COMPILE_TEST
|
||||
help
|
||||
Support for the watchdog in Sigma Designs SMP86xx (tango3)
|
||||
and SMP87xx (tango4) family chips.
|
||||
|
||||
This driver can be built as a module. The module name is tangox_wdt.
|
||||
|
||||
config WM831X_WATCHDOG
|
||||
tristate "WM831x watchdog"
|
||||
depends on MFD_WM831X
|
||||
@@ -161,6 +178,17 @@ config XILINX_WATCHDOG
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called of_xilinx_wdt.
|
||||
|
||||
config ZIIRAVE_WATCHDOG
|
||||
tristate "Zodiac RAVE Watchdog Timer"
|
||||
depends on I2C
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Watchdog driver for the Zodiac Aerospace RAVE Switch Watchdog
|
||||
Processor.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ziirave_wdt.
|
||||
|
||||
# ALPHA Architecture
|
||||
|
||||
# ARM Architecture
|
||||
@@ -173,6 +201,16 @@ config ARM_SP805_WATCHDOG
|
||||
ARM Primecell SP805 Watchdog timer. This will reboot your system when
|
||||
the timeout is reached.
|
||||
|
||||
config ASM9260_WATCHDOG
|
||||
tristate "Alphascale ASM9260 watchdog"
|
||||
depends on MACH_ASM9260
|
||||
depends on OF
|
||||
select WATCHDOG_CORE
|
||||
select RESET_CONTROLLER
|
||||
help
|
||||
Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your
|
||||
system when the timeout is reached.
|
||||
|
||||
config AT91RM9200_WATCHDOG
|
||||
tristate "AT91RM9200 watchdog"
|
||||
depends on SOC_AT91RM9200 && MFD_SYSCON
|
||||
@@ -426,6 +464,16 @@ config NUC900_WATCHDOG
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called nuc900_wdt.
|
||||
|
||||
config TS4800_WATCHDOG
|
||||
tristate "TS-4800 Watchdog"
|
||||
depends on HAS_IOMEM && OF
|
||||
select WATCHDOG_CORE
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Technologic Systems TS-4800 has watchdog timer implemented in
|
||||
an external FPGA. Say Y here if you want to support for the
|
||||
watchdog timer on TS-4800 board.
|
||||
|
||||
config TS72XX_WATCHDOG
|
||||
tristate "TS-72XX SBC Watchdog"
|
||||
depends on MACH_TS72XX
|
||||
@@ -578,6 +626,16 @@ config LPC18XX_WATCHDOG
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called lpc18xx_wdt.
|
||||
|
||||
config ATLAS7_WATCHDOG
|
||||
tristate "CSRatlas7 watchdog"
|
||||
depends on ARCH_ATLAS7
|
||||
help
|
||||
Say Y here to include Watchdog timer support for the watchdog
|
||||
existing on the CSRatlas7 series platforms.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called atlas7_wdt.
|
||||
|
||||
# AVR32 Architecture
|
||||
|
||||
config AT32AP700X_WDT
|
||||
@@ -1345,6 +1403,13 @@ config RALINK_WDT
|
||||
help
|
||||
Hardware driver for the Ralink SoC Watchdog Timer.
|
||||
|
||||
config MT7621_WDT
|
||||
tristate "Mediatek SoC watchdog"
|
||||
select WATCHDOG_CORE
|
||||
depends on SOC_MT7620 || SOC_MT7621
|
||||
help
|
||||
Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer.
|
||||
|
||||
# PARISC Architecture
|
||||
|
||||
# POWERPC Architecture
|
||||
|
||||
@@ -30,6 +30,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
|
||||
|
||||
# ARM Architecture
|
||||
obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
|
||||
obj-$(CONFIG_ASM9260_WATCHDOG) += asm9260_wdt.o
|
||||
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
|
||||
obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
|
||||
obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
|
||||
@@ -53,6 +54,7 @@ obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o
|
||||
obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
|
||||
obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
|
||||
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
|
||||
obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
|
||||
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
|
||||
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
|
||||
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
|
||||
@@ -69,6 +71,7 @@ obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
|
||||
obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
|
||||
obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
|
||||
obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
|
||||
obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
|
||||
|
||||
# AVR32 Architecture
|
||||
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
|
||||
@@ -149,6 +152,7 @@ octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
|
||||
obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
|
||||
obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
|
||||
obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
|
||||
obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
|
||||
|
||||
# PARISC Architecture
|
||||
|
||||
@@ -187,8 +191,10 @@ obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
|
||||
obj-$(CONFIG_DA9062_WATCHDOG) += da9062_wdt.o
|
||||
obj-$(CONFIG_DA9063_WATCHDOG) += da9063_wdt.o
|
||||
obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
|
||||
obj-$(CONFIG_TANGOX_WATCHDOG) += tangox_wdt.o
|
||||
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
|
||||
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
|
||||
obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
|
||||
obj-$(CONFIG_ZIIRAVE_WATCHDOG) += ziirave_wdt.o
|
||||
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
|
||||
obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
|
||||
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* Watchdog driver for Alphascale ASM9260.
|
||||
*
|
||||
* Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>
|
||||
*
|
||||
* Licensed under GPLv2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define CLOCK_FREQ 1000000
|
||||
|
||||
/* Watchdog Mode register */
|
||||
#define HW_WDMOD 0x00
|
||||
/* Wake interrupt. Set by HW, can't be cleared. */
|
||||
#define BM_MOD_WDINT BIT(3)
|
||||
/* This bit set if timeout reached. Cleared by SW. */
|
||||
#define BM_MOD_WDTOF BIT(2)
|
||||
/* HW Reset on timeout */
|
||||
#define BM_MOD_WDRESET BIT(1)
|
||||
/* WD enable */
|
||||
#define BM_MOD_WDEN BIT(0)
|
||||
|
||||
/*
|
||||
* Watchdog Timer Constant register
|
||||
* Minimal value is 0xff, the meaning of this value
|
||||
* depends on used clock: T = WDCLK * (0xff + 1) * 4
|
||||
*/
|
||||
#define HW_WDTC 0x04
|
||||
#define BM_WDTC_MAX(freq) (0x7fffffff / (freq))
|
||||
|
||||
/* Watchdog Feed register */
|
||||
#define HW_WDFEED 0x08
|
||||
|
||||
/* Watchdog Timer Value register */
|
||||
#define HW_WDTV 0x0c
|
||||
|
||||
#define ASM9260_WDT_DEFAULT_TIMEOUT 30
|
||||
|
||||
enum asm9260_wdt_mode {
|
||||
HW_RESET,
|
||||
SW_RESET,
|
||||
DEBUG,
|
||||
};
|
||||
|
||||
struct asm9260_wdt_priv {
|
||||
struct device *dev;
|
||||
struct watchdog_device wdd;
|
||||
struct clk *clk;
|
||||
struct clk *clk_ahb;
|
||||
struct reset_control *rst;
|
||||
struct notifier_block restart_handler;
|
||||
|
||||
void __iomem *iobase;
|
||||
int irq;
|
||||
unsigned long wdt_freq;
|
||||
enum asm9260_wdt_mode mode;
|
||||
};
|
||||
|
||||
static int asm9260_wdt_feed(struct watchdog_device *wdd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
iowrite32(0xaa, priv->iobase + HW_WDFEED);
|
||||
iowrite32(0x55, priv->iobase + HW_WDFEED);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int asm9260_wdt_gettimeleft(struct watchdog_device *wdd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
u32 counter;
|
||||
|
||||
counter = ioread32(priv->iobase + HW_WDTV);
|
||||
|
||||
return DIV_ROUND_CLOSEST(counter, priv->wdt_freq);
|
||||
}
|
||||
|
||||
static int asm9260_wdt_updatetimeout(struct watchdog_device *wdd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
u32 counter;
|
||||
|
||||
counter = wdd->timeout * priv->wdt_freq;
|
||||
|
||||
iowrite32(counter, priv->iobase + HW_WDTC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asm9260_wdt_enable(struct watchdog_device *wdd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
u32 mode = 0;
|
||||
|
||||
if (priv->mode == HW_RESET)
|
||||
mode = BM_MOD_WDRESET;
|
||||
|
||||
iowrite32(BM_MOD_WDEN | mode, priv->iobase + HW_WDMOD);
|
||||
|
||||
asm9260_wdt_updatetimeout(wdd);
|
||||
|
||||
asm9260_wdt_feed(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asm9260_wdt_disable(struct watchdog_device *wdd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
/* The only way to disable WD is to reset it. */
|
||||
reset_control_assert(priv->rst);
|
||||
reset_control_deassert(priv->rst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asm9260_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
|
||||
{
|
||||
wdd->timeout = to;
|
||||
asm9260_wdt_updatetimeout(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asm9260_wdt_sys_reset(struct asm9260_wdt_priv *priv)
|
||||
{
|
||||
/* init WD if it was not started */
|
||||
|
||||
iowrite32(BM_MOD_WDEN | BM_MOD_WDRESET, priv->iobase + HW_WDMOD);
|
||||
|
||||
iowrite32(0xff, priv->iobase + HW_WDTC);
|
||||
/* first pass correct sequence */
|
||||
asm9260_wdt_feed(&priv->wdd);
|
||||
/*
|
||||
* Then write wrong pattern to the feed to trigger reset
|
||||
* ASAP.
|
||||
*/
|
||||
iowrite32(0xff, priv->iobase + HW_WDFEED);
|
||||
|
||||
mdelay(1000);
|
||||
}
|
||||
|
||||
static irqreturn_t asm9260_wdt_irq(int irq, void *devid)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = devid;
|
||||
u32 stat;
|
||||
|
||||
stat = ioread32(priv->iobase + HW_WDMOD);
|
||||
if (!(stat & BM_MOD_WDINT))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (priv->mode == DEBUG) {
|
||||
dev_info(priv->dev, "Watchdog Timeout. Do nothing.\n");
|
||||
} else {
|
||||
dev_info(priv->dev, "Watchdog Timeout. Doing SW Reset.\n");
|
||||
asm9260_wdt_sys_reset(priv);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int asm9260_restart_handler(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv =
|
||||
container_of(this, struct asm9260_wdt_priv, restart_handler);
|
||||
|
||||
asm9260_wdt_sys_reset(priv);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static const struct watchdog_info asm9260_wdt_ident = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
|
||||
| WDIOF_MAGICCLOSE,
|
||||
.identity = "Alphascale asm9260 Watchdog",
|
||||
};
|
||||
|
||||
static struct watchdog_ops asm9260_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = asm9260_wdt_enable,
|
||||
.stop = asm9260_wdt_disable,
|
||||
.get_timeleft = asm9260_wdt_gettimeleft,
|
||||
.ping = asm9260_wdt_feed,
|
||||
.set_timeout = asm9260_wdt_settimeout,
|
||||
};
|
||||
|
||||
static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
|
||||
{
|
||||
int err;
|
||||
unsigned long clk;
|
||||
|
||||
priv->clk = devm_clk_get(priv->dev, "mod");
|
||||
if (IS_ERR(priv->clk)) {
|
||||
dev_err(priv->dev, "Failed to get \"mod\" clk\n");
|
||||
return PTR_ERR(priv->clk);
|
||||
}
|
||||
|
||||
/* configure AHB clock */
|
||||
priv->clk_ahb = devm_clk_get(priv->dev, "ahb");
|
||||
if (IS_ERR(priv->clk_ahb)) {
|
||||
dev_err(priv->dev, "Failed to get \"ahb\" clk\n");
|
||||
return PTR_ERR(priv->clk_ahb);
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(priv->clk_ahb);
|
||||
if (err) {
|
||||
dev_err(priv->dev, "Failed to enable ahb_clk!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_set_rate(priv->clk, CLOCK_FREQ);
|
||||
if (err) {
|
||||
clk_disable_unprepare(priv->clk_ahb);
|
||||
dev_err(priv->dev, "Failed to set rate!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(priv->clk);
|
||||
if (err) {
|
||||
clk_disable_unprepare(priv->clk_ahb);
|
||||
dev_err(priv->dev, "Failed to enable clk!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* wdt has internal divider */
|
||||
clk = clk_get_rate(priv->clk);
|
||||
if (!clk) {
|
||||
clk_disable_unprepare(priv->clk);
|
||||
clk_disable_unprepare(priv->clk_ahb);
|
||||
dev_err(priv->dev, "Failed, clk is 0!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->wdt_freq = clk / 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void asm9260_wdt_get_dt_mode(struct asm9260_wdt_priv *priv)
|
||||
{
|
||||
const char *tmp;
|
||||
int ret;
|
||||
|
||||
/* default mode */
|
||||
priv->mode = HW_RESET;
|
||||
|
||||
ret = of_property_read_string(priv->dev->of_node,
|
||||
"alphascale,mode", &tmp);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
if (!strcmp(tmp, "hw"))
|
||||
priv->mode = HW_RESET;
|
||||
else if (!strcmp(tmp, "sw"))
|
||||
priv->mode = SW_RESET;
|
||||
else if (!strcmp(tmp, "debug"))
|
||||
priv->mode = DEBUG;
|
||||
else
|
||||
dev_warn(priv->dev, "unknown reset-type: %s. Using default \"hw\" mode.",
|
||||
tmp);
|
||||
}
|
||||
|
||||
static int asm9260_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv;
|
||||
struct watchdog_device *wdd;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
const char * const mode_name[] = { "hw", "sw", "debug", };
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv),
|
||||
GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->iobase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->iobase))
|
||||
return PTR_ERR(priv->iobase);
|
||||
|
||||
ret = asm9260_wdt_get_dt_clks(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->rst = devm_reset_control_get(&pdev->dev, "wdt_rst");
|
||||
if (IS_ERR(priv->rst))
|
||||
return PTR_ERR(priv->rst);
|
||||
|
||||
wdd = &priv->wdd;
|
||||
wdd->info = &asm9260_wdt_ident;
|
||||
wdd->ops = &asm9260_wdt_ops;
|
||||
wdd->min_timeout = 1;
|
||||
wdd->max_timeout = BM_WDTC_MAX(priv->wdt_freq);
|
||||
wdd->parent = &pdev->dev;
|
||||
|
||||
watchdog_set_drvdata(wdd, priv);
|
||||
|
||||
/*
|
||||
* If 'timeout-sec' unspecified in devicetree, assume a 30 second
|
||||
* default, unless the max timeout is less than 30 seconds, then use
|
||||
* the max instead.
|
||||
*/
|
||||
wdd->timeout = ASM9260_WDT_DEFAULT_TIMEOUT;
|
||||
watchdog_init_timeout(wdd, 0, &pdev->dev);
|
||||
|
||||
asm9260_wdt_get_dt_mode(priv);
|
||||
|
||||
if (priv->mode != HW_RESET)
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (priv->irq > 0) {
|
||||
/*
|
||||
* Not all supported platforms specify an interrupt for the
|
||||
* watchdog, so let's make it optional.
|
||||
*/
|
||||
ret = devm_request_irq(&pdev->dev, priv->irq,
|
||||
asm9260_wdt_irq, 0, pdev->name, priv);
|
||||
if (ret < 0)
|
||||
dev_warn(&pdev->dev, "failed to request IRQ\n");
|
||||
}
|
||||
|
||||
ret = watchdog_register_device(wdd);
|
||||
if (ret)
|
||||
goto clk_off;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->restart_handler.notifier_call = asm9260_restart_handler;
|
||||
priv->restart_handler.priority = 128;
|
||||
ret = register_restart_handler(&priv->restart_handler);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "cannot register restart handler\n");
|
||||
|
||||
dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
|
||||
wdd->timeout, mode_name[priv->mode]);
|
||||
return 0;
|
||||
|
||||
clk_off:
|
||||
clk_disable_unprepare(priv->clk);
|
||||
clk_disable_unprepare(priv->clk_ahb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void asm9260_wdt_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
asm9260_wdt_disable(&priv->wdd);
|
||||
}
|
||||
|
||||
static int asm9260_wdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct asm9260_wdt_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
asm9260_wdt_disable(&priv->wdd);
|
||||
|
||||
unregister_restart_handler(&priv->restart_handler);
|
||||
|
||||
watchdog_unregister_device(&priv->wdd);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
clk_disable_unprepare(priv->clk_ahb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id asm9260_wdt_of_match[] = {
|
||||
{ .compatible = "alphascale,asm9260-wdt"},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, asm9260_wdt_of_match);
|
||||
|
||||
static struct platform_driver asm9260_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "asm9260-wdt",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = asm9260_wdt_of_match,
|
||||
},
|
||||
.probe = asm9260_wdt_probe,
|
||||
.remove = asm9260_wdt_remove,
|
||||
.shutdown = asm9260_wdt_shutdown,
|
||||
};
|
||||
module_platform_driver(asm9260_wdt_driver);
|
||||
|
||||
MODULE_DESCRIPTION("asm9260 WatchDog Timer Driver");
|
||||
MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Watchdog driver for CSR Atlas7
|
||||
*
|
||||
* Copyright (c) 2015 Cambridge Silicon Radio Limited, a CSR plc group company.
|
||||
*
|
||||
* Licensed under GPLv2.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define ATLAS7_TIMER_WDT_INDEX 5
|
||||
#define ATLAS7_WDT_DEFAULT_TIMEOUT 20
|
||||
|
||||
#define ATLAS7_WDT_CNT_CTRL (0 + 4 * ATLAS7_TIMER_WDT_INDEX)
|
||||
#define ATLAS7_WDT_CNT_MATCH (0x18 + 4 * ATLAS7_TIMER_WDT_INDEX)
|
||||
#define ATLAS7_WDT_CNT (0x48 + 4 * ATLAS7_TIMER_WDT_INDEX)
|
||||
#define ATLAS7_WDT_CNT_EN (BIT(0) | BIT(1))
|
||||
#define ATLAS7_WDT_EN 0x64
|
||||
|
||||
static unsigned int timeout = ATLAS7_WDT_DEFAULT_TIMEOUT;
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
|
||||
module_param(timeout, uint, 0);
|
||||
module_param(nowayout, bool, 0);
|
||||
|
||||
MODULE_PARM_DESC(timeout, "Default watchdog timeout (in seconds)");
|
||||
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
|
||||
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
|
||||
|
||||
struct atlas7_wdog {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
unsigned long tick_rate;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static unsigned int atlas7_wdt_gettimeleft(struct watchdog_device *wdd)
|
||||
{
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
u32 counter, match, delta;
|
||||
|
||||
counter = readl(wdt->base + ATLAS7_WDT_CNT);
|
||||
match = readl(wdt->base + ATLAS7_WDT_CNT_MATCH);
|
||||
delta = match - counter;
|
||||
|
||||
return delta / wdt->tick_rate;
|
||||
}
|
||||
|
||||
static int atlas7_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
u32 counter, match, delta;
|
||||
|
||||
counter = readl(wdt->base + ATLAS7_WDT_CNT);
|
||||
delta = wdd->timeout * wdt->tick_rate;
|
||||
match = counter + delta;
|
||||
|
||||
writel(match, wdt->base + ATLAS7_WDT_CNT_MATCH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atlas7_wdt_enable(struct watchdog_device *wdd)
|
||||
{
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
atlas7_wdt_ping(wdd);
|
||||
|
||||
writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) | ATLAS7_WDT_CNT_EN,
|
||||
wdt->base + ATLAS7_WDT_CNT_CTRL);
|
||||
writel(1, wdt->base + ATLAS7_WDT_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atlas7_wdt_disable(struct watchdog_device *wdd)
|
||||
{
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
writel(0, wdt->base + ATLAS7_WDT_EN);
|
||||
writel(readl(wdt->base + ATLAS7_WDT_CNT_CTRL) & ~ATLAS7_WDT_CNT_EN,
|
||||
wdt->base + ATLAS7_WDT_CNT_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atlas7_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
|
||||
{
|
||||
wdd->timeout = to;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
|
||||
|
||||
static const struct watchdog_info atlas7_wdt_ident = {
|
||||
.options = OPTIONS,
|
||||
.firmware_version = 0,
|
||||
.identity = "atlas7 Watchdog",
|
||||
};
|
||||
|
||||
static struct watchdog_ops atlas7_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = atlas7_wdt_enable,
|
||||
.stop = atlas7_wdt_disable,
|
||||
.get_timeleft = atlas7_wdt_gettimeleft,
|
||||
.ping = atlas7_wdt_ping,
|
||||
.set_timeout = atlas7_wdt_settimeout,
|
||||
};
|
||||
|
||||
static struct watchdog_device atlas7_wdd = {
|
||||
.info = &atlas7_wdt_ident,
|
||||
.ops = &atlas7_wdt_ops,
|
||||
.timeout = ATLAS7_WDT_DEFAULT_TIMEOUT,
|
||||
};
|
||||
|
||||
static const struct of_device_id atlas7_wdt_ids[] = {
|
||||
{ .compatible = "sirf,atlas7-tick"},
|
||||
{}
|
||||
};
|
||||
|
||||
static int atlas7_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct atlas7_wdog *wdt;
|
||||
struct resource *res;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
|
||||
if (!wdt)
|
||||
return -ENOMEM;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wdt->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(wdt->base))
|
||||
return PTR_ERR(wdt->base);
|
||||
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "clk enable failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* disable watchdog hardware */
|
||||
writel(0, wdt->base + ATLAS7_WDT_CNT_CTRL);
|
||||
|
||||
wdt->tick_rate = clk_get_rate(clk);
|
||||
wdt->clk = clk;
|
||||
atlas7_wdd.min_timeout = 1;
|
||||
atlas7_wdd.max_timeout = UINT_MAX / wdt->tick_rate;
|
||||
|
||||
watchdog_init_timeout(&atlas7_wdd, 0, &pdev->dev);
|
||||
watchdog_set_nowayout(&atlas7_wdd, nowayout);
|
||||
|
||||
watchdog_set_drvdata(&atlas7_wdd, wdt);
|
||||
platform_set_drvdata(pdev, &atlas7_wdd);
|
||||
|
||||
ret = watchdog_register_device(&atlas7_wdd);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
return 0;
|
||||
|
||||
err1:
|
||||
clk_disable_unprepare(clk);
|
||||
err:
|
||||
clk_put(clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void atlas7_wdt_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct watchdog_device *wdd = platform_get_drvdata(pdev);
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
atlas7_wdt_disable(wdd);
|
||||
clk_disable_unprepare(wdt->clk);
|
||||
}
|
||||
|
||||
static int atlas7_wdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct watchdog_device *wdd = platform_get_drvdata(pdev);
|
||||
struct atlas7_wdog *wdt = watchdog_get_drvdata(wdd);
|
||||
|
||||
atlas7_wdt_shutdown(pdev);
|
||||
clk_put(wdt->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused atlas7_wdt_suspend(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* NOTE:timer controller registers settings are saved
|
||||
* and restored back by the timer-atlas7.c
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused atlas7_wdt_resume(struct device *dev)
|
||||
{
|
||||
struct watchdog_device *wdd = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* NOTE: Since timer controller registers settings are saved
|
||||
* and restored back by the timer-atlas7.c, so we need not
|
||||
* update WD settings except refreshing timeout.
|
||||
*/
|
||||
atlas7_wdt_ping(wdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(atlas7_wdt_pm_ops,
|
||||
atlas7_wdt_suspend, atlas7_wdt_resume);
|
||||
|
||||
MODULE_DEVICE_TABLE(of, atlas7_wdt_ids);
|
||||
|
||||
static struct platform_driver atlas7_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "atlas7-wdt",
|
||||
.pm = &atlas7_wdt_pm_ops,
|
||||
.of_match_table = atlas7_wdt_ids,
|
||||
},
|
||||
.probe = atlas7_wdt_probe,
|
||||
.remove = atlas7_wdt_remove,
|
||||
.shutdown = atlas7_wdt_shutdown,
|
||||
};
|
||||
module_platform_driver(atlas7_wdt_driver);
|
||||
|
||||
MODULE_DESCRIPTION("CSRatlas7 watchdog driver");
|
||||
MODULE_AUTHOR("Guo Zeng <Guo.Zeng@csr.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:atlas7-wdt");
|
||||
@@ -79,7 +79,6 @@ static int bcm2835_wdt_stop(struct watchdog_device *wdog)
|
||||
struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
|
||||
|
||||
writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC);
|
||||
dev_info(wdog->dev, "Watchdog timer stopped");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/timer.h>
|
||||
@@ -88,12 +87,22 @@ static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bcm47xx_wdt_restart(struct watchdog_device *wdd)
|
||||
{
|
||||
struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
|
||||
|
||||
wdt->timer_set(wdt, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct watchdog_ops bcm47xx_wdt_hard_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = bcm47xx_wdt_hard_start,
|
||||
.stop = bcm47xx_wdt_hard_stop,
|
||||
.ping = bcm47xx_wdt_hard_keepalive,
|
||||
.set_timeout = bcm47xx_wdt_hard_set_timeout,
|
||||
.restart = bcm47xx_wdt_restart,
|
||||
};
|
||||
|
||||
static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
|
||||
@@ -158,34 +167,13 @@ static const struct watchdog_info bcm47xx_wdt_info = {
|
||||
WDIOF_MAGICCLOSE,
|
||||
};
|
||||
|
||||
static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
|
||||
unsigned long code, void *unused)
|
||||
{
|
||||
struct bcm47xx_wdt *wdt;
|
||||
|
||||
wdt = container_of(this, struct bcm47xx_wdt, notifier);
|
||||
if (code == SYS_DOWN || code == SYS_HALT)
|
||||
wdt->wdd.ops->stop(&wdt->wdd);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
struct bcm47xx_wdt *wdt;
|
||||
|
||||
wdt = container_of(this, struct bcm47xx_wdt, restart_handler);
|
||||
wdt->timer_set(wdt, 1);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static struct watchdog_ops bcm47xx_wdt_soft_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = bcm47xx_wdt_soft_start,
|
||||
.stop = bcm47xx_wdt_soft_stop,
|
||||
.ping = bcm47xx_wdt_soft_keepalive,
|
||||
.set_timeout = bcm47xx_wdt_soft_set_timeout,
|
||||
.restart = bcm47xx_wdt_restart,
|
||||
};
|
||||
|
||||
static int bcm47xx_wdt_probe(struct platform_device *pdev)
|
||||
@@ -214,32 +202,18 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_timer;
|
||||
watchdog_set_nowayout(&wdt->wdd, nowayout);
|
||||
|
||||
wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
|
||||
|
||||
ret = register_reboot_notifier(&wdt->notifier);
|
||||
if (ret)
|
||||
goto err_timer;
|
||||
|
||||
wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart;
|
||||
wdt->restart_handler.priority = 64;
|
||||
ret = register_restart_handler(&wdt->restart_handler);
|
||||
if (ret)
|
||||
goto err_notifier;
|
||||
watchdog_set_restart_priority(&wdt->wdd, 64);
|
||||
watchdog_stop_on_reboot(&wdt->wdd);
|
||||
|
||||
ret = watchdog_register_device(&wdt->wdd);
|
||||
if (ret)
|
||||
goto err_handler;
|
||||
goto err_timer;
|
||||
|
||||
dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
|
||||
timeout, nowayout ? ", nowayout" : "",
|
||||
soft ? ", Software Timer" : "");
|
||||
return 0;
|
||||
|
||||
err_handler:
|
||||
unregister_restart_handler(&wdt->restart_handler);
|
||||
err_notifier:
|
||||
unregister_reboot_notifier(&wdt->notifier);
|
||||
err_timer:
|
||||
if (soft)
|
||||
del_timer_sync(&wdt->soft_timer);
|
||||
@@ -255,7 +229,6 @@ static int bcm47xx_wdt_remove(struct platform_device *pdev)
|
||||
return -ENXIO;
|
||||
|
||||
watchdog_unregister_device(&wdt->wdd);
|
||||
unregister_reboot_notifier(&wdt->notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define CDNS_WDT_DEFAULT_TIMEOUT 10
|
||||
@@ -72,7 +71,6 @@ MODULE_PARM_DESC(nowayout,
|
||||
* @ctrl_clksel: counter clock prescaler selection
|
||||
* @io_lock: spinlock for IO register access
|
||||
* @cdns_wdt_device: watchdog device structure
|
||||
* @cdns_wdt_notifier: notifier structure
|
||||
*
|
||||
* Structure containing parameters specific to cadence watchdog.
|
||||
*/
|
||||
@@ -84,7 +82,6 @@ struct cdns_wdt {
|
||||
u32 ctrl_clksel;
|
||||
spinlock_t io_lock;
|
||||
struct watchdog_device cdns_wdt_device;
|
||||
struct notifier_block cdns_wdt_notifier;
|
||||
};
|
||||
|
||||
/* Write access to Registers */
|
||||
@@ -280,29 +277,6 @@ static struct watchdog_ops cdns_wdt_ops = {
|
||||
.set_timeout = cdns_wdt_settimeout,
|
||||
};
|
||||
|
||||
/**
|
||||
* cdns_wdt_notify_sys - Notifier for reboot or shutdown.
|
||||
*
|
||||
* @this: handle to notifier block
|
||||
* @code: turn off indicator
|
||||
* @unused: unused
|
||||
* Return: NOTIFY_DONE
|
||||
*
|
||||
* This notifier is invoked whenever the system reboot or shutdown occur
|
||||
* because we need to disable the WDT before system goes down as WDT might
|
||||
* reset on the next boot.
|
||||
*/
|
||||
static int cdns_wdt_notify_sys(struct notifier_block *this, unsigned long code,
|
||||
void *unused)
|
||||
{
|
||||
struct cdns_wdt *wdt = container_of(this, struct cdns_wdt,
|
||||
cdns_wdt_notifier);
|
||||
if (code == SYS_DOWN || code == SYS_HALT)
|
||||
cdns_wdt_stop(&wdt->cdns_wdt_device);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/************************Platform Operations*****************************/
|
||||
/**
|
||||
* cdns_wdt_probe - Probe call for the device.
|
||||
@@ -360,6 +334,7 @@ static int cdns_wdt_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
watchdog_set_nowayout(cdns_wdt_device, nowayout);
|
||||
watchdog_stop_on_reboot(cdns_wdt_device);
|
||||
watchdog_set_drvdata(cdns_wdt_device, wdt);
|
||||
|
||||
wdt->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
@@ -386,14 +361,6 @@ static int cdns_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&wdt->io_lock);
|
||||
|
||||
wdt->cdns_wdt_notifier.notifier_call = &cdns_wdt_notify_sys;
|
||||
ret = register_reboot_notifier(&wdt->cdns_wdt_notifier);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n",
|
||||
ret);
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
ret = watchdog_register_device(cdns_wdt_device);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register wdt device\n");
|
||||
@@ -427,7 +394,6 @@ static int cdns_wdt_remove(struct platform_device *pdev)
|
||||
|
||||
cdns_wdt_stop(&wdt->cdns_wdt_device);
|
||||
watchdog_unregister_device(&wdt->cdns_wdt_device);
|
||||
unregister_reboot_notifier(&wdt->cdns_wdt_notifier);
|
||||
clk_disable_unprepare(wdt->clk);
|
||||
|
||||
return 0;
|
||||
@@ -455,8 +421,7 @@ static void cdns_wdt_shutdown(struct platform_device *pdev)
|
||||
*/
|
||||
static int __maybe_unused cdns_wdt_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = container_of(dev,
|
||||
struct platform_device, dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_wdt *wdt = platform_get_drvdata(pdev);
|
||||
|
||||
cdns_wdt_stop(&wdt->cdns_wdt_device);
|
||||
@@ -474,8 +439,7 @@ static int __maybe_unused cdns_wdt_suspend(struct device *dev)
|
||||
static int __maybe_unused cdns_wdt_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev = container_of(dev,
|
||||
struct platform_device, dev);
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct cdns_wdt *wdt = platform_get_drvdata(pdev);
|
||||
|
||||
ret = clk_prepare_enable(wdt->clk);
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
struct da9052_wdt_data {
|
||||
struct watchdog_device wdt;
|
||||
struct da9052 *da9052;
|
||||
struct kref kref;
|
||||
unsigned long jpast;
|
||||
};
|
||||
|
||||
@@ -51,10 +50,6 @@ static const struct {
|
||||
};
|
||||
|
||||
|
||||
static void da9052_wdt_release_resources(struct kref *r)
|
||||
{
|
||||
}
|
||||
|
||||
static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
|
||||
unsigned int timeout)
|
||||
{
|
||||
@@ -104,20 +99,6 @@ static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void da9052_wdt_ref(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
kref_get(&driver_data->kref);
|
||||
}
|
||||
|
||||
static void da9052_wdt_unref(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct da9052_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
kref_put(&driver_data->kref, da9052_wdt_release_resources);
|
||||
}
|
||||
|
||||
static int da9052_wdt_start(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
return da9052_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
|
||||
@@ -170,8 +151,6 @@ static const struct watchdog_ops da9052_wdt_ops = {
|
||||
.stop = da9052_wdt_stop,
|
||||
.ping = da9052_wdt_ping,
|
||||
.set_timeout = da9052_wdt_set_timeout,
|
||||
.ref = da9052_wdt_ref,
|
||||
.unref = da9052_wdt_unref,
|
||||
};
|
||||
|
||||
|
||||
@@ -198,8 +177,6 @@ static int da9052_wdt_probe(struct platform_device *pdev)
|
||||
da9052_wdt->parent = &pdev->dev;
|
||||
watchdog_set_drvdata(da9052_wdt, driver_data);
|
||||
|
||||
kref_init(&driver_data->kref);
|
||||
|
||||
ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
|
||||
DA9052_CONTROLD_TWDSCALE, 0);
|
||||
if (ret < 0) {
|
||||
@@ -225,7 +202,6 @@ static int da9052_wdt_remove(struct platform_device *pdev)
|
||||
struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
|
||||
|
||||
watchdog_unregister_device(&driver_data->wdt);
|
||||
kref_put(&driver_data->kref, da9052_wdt_release_resources);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ MODULE_PARM_DESC(nowayout,
|
||||
struct da9055_wdt_data {
|
||||
struct watchdog_device wdt;
|
||||
struct da9055 *da9055;
|
||||
struct kref kref;
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@@ -99,24 +98,6 @@ static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
|
||||
DA9055_WATCHDOG_MASK, 1);
|
||||
}
|
||||
|
||||
static void da9055_wdt_release_resources(struct kref *r)
|
||||
{
|
||||
}
|
||||
|
||||
static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
kref_get(&driver_data->kref);
|
||||
}
|
||||
|
||||
static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
|
||||
|
||||
kref_put(&driver_data->kref, da9055_wdt_release_resources);
|
||||
}
|
||||
|
||||
static int da9055_wdt_start(struct watchdog_device *wdt_dev)
|
||||
{
|
||||
return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
|
||||
@@ -138,8 +119,6 @@ static const struct watchdog_ops da9055_wdt_ops = {
|
||||
.stop = da9055_wdt_stop,
|
||||
.ping = da9055_wdt_ping,
|
||||
.set_timeout = da9055_wdt_set_timeout,
|
||||
.ref = da9055_wdt_ref,
|
||||
.unref = da9055_wdt_unref,
|
||||
};
|
||||
|
||||
static int da9055_wdt_probe(struct platform_device *pdev)
|
||||
@@ -165,8 +144,6 @@ static int da9055_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_set_nowayout(da9055_wdt, nowayout);
|
||||
watchdog_set_drvdata(da9055_wdt, driver_data);
|
||||
|
||||
kref_init(&driver_data->kref);
|
||||
|
||||
ret = da9055_wdt_stop(da9055_wdt);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
|
||||
@@ -189,7 +166,6 @@ static int da9055_wdt_remove(struct platform_device *pdev)
|
||||
struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
|
||||
|
||||
watchdog_unregister_device(&driver_data->wdt);
|
||||
kref_put(&driver_data->kref, da9055_wdt_release_resources);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/*
|
||||
@@ -39,7 +38,6 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
|
||||
struct da9063_watchdog {
|
||||
struct da9063 *da9063;
|
||||
struct watchdog_device wdtdev;
|
||||
struct notifier_block restart_handler;
|
||||
};
|
||||
|
||||
static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
|
||||
@@ -121,12 +119,9 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da9063_wdt_restart_handler(struct notifier_block *this,
|
||||
unsigned long mode, void *cmd)
|
||||
static int da9063_wdt_restart(struct watchdog_device *wdd)
|
||||
{
|
||||
struct da9063_watchdog *wdt = container_of(this,
|
||||
struct da9063_watchdog,
|
||||
restart_handler);
|
||||
struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd);
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,
|
||||
@@ -135,7 +130,7 @@ static int da9063_wdt_restart_handler(struct notifier_block *this,
|
||||
dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",
|
||||
ret);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct watchdog_info da9063_watchdog_info = {
|
||||
@@ -149,6 +144,7 @@ static const struct watchdog_ops da9063_watchdog_ops = {
|
||||
.stop = da9063_wdt_stop,
|
||||
.ping = da9063_wdt_ping,
|
||||
.set_timeout = da9063_wdt_set_timeout,
|
||||
.restart = da9063_wdt_restart,
|
||||
};
|
||||
|
||||
static int da9063_wdt_probe(struct platform_device *pdev)
|
||||
@@ -179,6 +175,8 @@ static int da9063_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS;
|
||||
|
||||
watchdog_set_restart_priority(&wdt->wdtdev, 128);
|
||||
|
||||
watchdog_set_drvdata(&wdt->wdtdev, wdt);
|
||||
dev_set_drvdata(&pdev->dev, wdt);
|
||||
|
||||
@@ -186,13 +184,6 @@ static int da9063_wdt_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
wdt->restart_handler.notifier_call = da9063_wdt_restart_handler;
|
||||
wdt->restart_handler.priority = 128;
|
||||
ret = register_restart_handler(&wdt->restart_handler);
|
||||
if (ret)
|
||||
dev_err(wdt->da9063->dev,
|
||||
"Failed to register restart handler (err = %d)\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,8 +191,6 @@ static int da9063_wdt_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
unregister_restart_handler(&wdt->restart_handler);
|
||||
|
||||
watchdog_unregister_device(&wdt->wdtdev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -106,6 +106,10 @@ static int __diag288_lpar(unsigned int func, unsigned int timeout,
|
||||
return __diag288(func, timeout, action, 0);
|
||||
}
|
||||
|
||||
static unsigned long wdt_status;
|
||||
|
||||
#define DIAG_WDOG_BUSY 0
|
||||
|
||||
static int wdt_start(struct watchdog_device *dev)
|
||||
{
|
||||
char *ebc_cmd;
|
||||
@@ -113,12 +117,17 @@ static int wdt_start(struct watchdog_device *dev)
|
||||
int ret;
|
||||
unsigned int func;
|
||||
|
||||
if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status))
|
||||
return -EBUSY;
|
||||
|
||||
ret = -ENODEV;
|
||||
|
||||
if (MACHINE_IS_VM) {
|
||||
ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
|
||||
if (!ebc_cmd)
|
||||
if (!ebc_cmd) {
|
||||
clear_bit(DIAG_WDOG_BUSY, &wdt_status);
|
||||
return -ENOMEM;
|
||||
}
|
||||
len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN);
|
||||
ASCEBC(ebc_cmd, MAX_CMDLEN);
|
||||
EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
|
||||
@@ -135,6 +144,7 @@ static int wdt_start(struct watchdog_device *dev)
|
||||
|
||||
if (ret) {
|
||||
pr_err("The watchdog cannot be activated\n");
|
||||
clear_bit(DIAG_WDOG_BUSY, &wdt_status);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
@@ -146,6 +156,9 @@ static int wdt_stop(struct watchdog_device *dev)
|
||||
|
||||
diag_stat_inc(DIAG_STAT_X288);
|
||||
ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0);
|
||||
|
||||
clear_bit(DIAG_WDOG_BUSY, &wdt_status);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -220,17 +233,10 @@ static struct watchdog_device wdt_dev = {
|
||||
* It makes no sense to go into suspend while the watchdog is running.
|
||||
* Depending on the memory size, the watchdog might trigger, while we
|
||||
* are still saving the memory.
|
||||
* We reuse the open flag to ensure that suspend and watchdog open are
|
||||
* exclusive operations
|
||||
*/
|
||||
static int wdt_suspend(void)
|
||||
{
|
||||
if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_dev.status)) {
|
||||
pr_err("Linux cannot be suspended while the watchdog is in use\n");
|
||||
return notifier_from_errno(-EBUSY);
|
||||
}
|
||||
if (test_bit(WDOG_ACTIVE, &wdt_dev.status)) {
|
||||
clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
|
||||
if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status)) {
|
||||
pr_err("Linux cannot be suspended while the watchdog is in use\n");
|
||||
return notifier_from_errno(-EBUSY);
|
||||
}
|
||||
@@ -239,7 +245,7 @@ static int wdt_suspend(void)
|
||||
|
||||
static int wdt_resume(void)
|
||||
{
|
||||
clear_bit(WDOG_DEV_OPEN, &wdt_dev.status);
|
||||
clear_bit(DIAG_WDOG_BUSY, &wdt_status);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
|
||||
Loaded 20 of 48 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user