watchdog: core: dt: add support for the timeout-sec dt property

Add support for watchdog drivers to initialize/set the timeout field
of the watchdog_device structure. The timeout field is initialised
either with the module timeout parameter value (if valid) or with the
timeout-sec dt property (if valid). If both are invalid the initial
value is unchanged.

Signed-off-by: Fabio Porcedda <fabio.porcedda@gmail.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
This commit is contained in:
Fabio Porcedda 2013-01-08 11:04:10 +01:00 committed by Wim Van Sebroeck
parent e3e83d0001
commit 3048253ed9
4 changed files with 80 additions and 12 deletions

View File

@ -1,6 +1,6 @@
The Linux WatchDog Timer Driver Core kernel API.
===============================================
Last reviewed: 22-May-2012
Last reviewed: 12-Feb-2013
Wim Van Sebroeck <wim@iguana.be>
@ -212,3 +212,15 @@ driver specific data to and a pointer to the data itself.
The watchdog_get_drvdata function allows you to retrieve driver specific data.
The argument of this function is the watchdog device where you want to retrieve
data from. The function returns the pointer to the driver specific data.
To initialize the timeout field, the following function can be used:
extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);
The watchdog_init_timeout function allows you to initialize the timeout field
using the module timeout parameter or by retrieving the timeout-sec property from
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.

View File

@ -36,12 +36,68 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/idr.h> /* For ida_* macros */
#include <linux/err.h> /* For IS_ERR macros */
#include <linux/of.h> /* For of_get_timeout_sec */
#include "watchdog_core.h" /* For watchdog_dev_register/... */
static DEFINE_IDA(watchdog_ida);
static struct class *watchdog_class;
static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
{
/*
* Check that we have valid min and max timeout values, if
* not reset them both to 0 (=not used or unknown)
*/
if (wdd->min_timeout > wdd->max_timeout) {
pr_info("Invalid min and max timeout values, resetting to 0!\n");
wdd->min_timeout = 0;
wdd->max_timeout = 0;
}
}
/**
* watchdog_init_timeout() - initialize the timeout field
* @timeout_parm: timeout module parameter
* @dev: Device that stores the timeout-sec property
*
* Initialize the timeout field of the watchdog_device struct with either the
* timeout module parameter (if it is valid value) or the timeout-sec property
* (only if it is a valid value and the timeout_parm is out of bounds).
* If none of them are valid then we keep the old value (which should normally
* be the default timeout value.
*
* A zero is returned on success and -EINVAL for failure.
*/
int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev)
{
unsigned int t = 0;
int ret = 0;
watchdog_check_min_max_timeout(wdd);
/* try to get the tiemout module parameter first */
if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
wdd->timeout = timeout_parm;
return ret;
}
if (timeout_parm)
ret = -EINVAL;
/* try to get the timeout_sec property */
if (dev == NULL || dev->of_node == NULL)
return ret;
of_property_read_u32(dev->of_node, "timeout-sec", &t);
if (!watchdog_timeout_invalid(wdd, t))
wdd->timeout = t;
else
ret = -EINVAL;
return ret;
}
EXPORT_SYMBOL_GPL(watchdog_init_timeout);
/**
* watchdog_register_device() - register a watchdog device
* @wdd: watchdog device
@ -63,15 +119,7 @@ int watchdog_register_device(struct watchdog_device *wdd)
if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
return -EINVAL;
/*
* Check that we have valid min and max timeout values, if
* not reset them both to 0 (=not used or unknown)
*/
if (wdd->min_timeout > wdd->max_timeout) {
pr_info("Invalid min and max timeout values, resetting to 0!\n");
wdd->min_timeout = 0;
wdd->max_timeout = 0;
}
watchdog_check_min_max_timeout(wdd);
/*
* Note: now that all watchdog_device data has been verified, we

View File

@ -200,8 +200,7 @@ static int watchdog_set_timeout(struct watchdog_device *wddev,
!(wddev->info->options & WDIOF_SETTIMEOUT))
return -EOPNOTSUPP;
if ((wddev->max_timeout != 0) &&
(timeout < wddev->min_timeout || timeout > wddev->max_timeout))
if (watchdog_timeout_invalid(wddev, timeout))
return -EINVAL;
mutex_lock(&wddev->lock);

View File

@ -118,6 +118,13 @@ static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool noway
set_bit(WDOG_NO_WAY_OUT, &wdd->status);
}
/* Use the following function to check if a timeout value is invalid */
static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
{
return ((wdd->max_timeout != 0) &&
(t < wdd->min_timeout || t > wdd->max_timeout));
}
/* Use the following functions to manipulate watchdog driver specific data */
static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
{
@ -130,6 +137,8 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
}
/* drivers/watchdog/watchdog_core.c */
extern int watchdog_init_timeout(struct watchdog_device *wdd,
unsigned int timeout_parm, struct device *dev);
extern int watchdog_register_device(struct watchdog_device *);
extern void watchdog_unregister_device(struct watchdog_device *);