[v2 PATCH 2/8] watchdog/at91sam9_wdt: Convert to use the watchdog framework

Wenyou Yang wenyou.yang at atmel.com
Tue Dec 4 20:34:21 EST 2012


According to the kernel document: convert_drivers_to_kernel_api.txt,
remove the file_operations struct, miscdevice, and obsolete includes

Since the at91sam watchdog inherent characteristics, add the watchdog
operations: at91wdt_start, at91wdt_stop and at91wdt_ping.

Signed-off-by: Wenyou Yang <wenyou.yang at atmel.com>
Cc: wim at iguana.be
Cc: linux-watchdog at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
---
 drivers/watchdog/at91sam9_wdt.c |  203 +++++++++++++++------------------------
 1 file changed, 75 insertions(+), 128 deletions(-)

diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index f10a897..92467d4 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -13,16 +13,17 @@
  * The Watchdog Timer Mode Register can be only written to once. If the
  * timeout need to be set from Linux, be sure that the bootstrap or the
  * bootloader doesn't write to this register.
+ * The Watchdog Timer default is running with maximum counter value
+ * (WDV=0xfff) at reset, i.e., at power-up. It MUST be either disabled
+ * or be reprogrammed within the maxinum margin(16s).
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/errno.h>
-#include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
-#include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
@@ -31,7 +32,6 @@
 #include <linux/jiffies.h>
 #include <linux/timer.h>
 #include <linux/bitops.h>
-#include <linux/uaccess.h>
 #include <linux/of.h>
 
 #include "at91sam9_wdt.h"
@@ -65,8 +65,6 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 	"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static void at91_ping(unsigned long data);
-
 struct at91wdt_drvdata {
 	void __iomem	*phybase;
 	bool		is_enable;	/* indicate if the watchdog is eabled */
@@ -88,6 +86,11 @@ static inline void wdt_write(struct at91wdt_drvdata *driver_data,
 	writel_relaxed((val), driver_data->phybase + field);
 }
 
+static inline bool watchdog_is_open(struct watchdog_device *wddev)
+{
+	return test_bit(WDOG_DEV_OPEN, &wddev->status);
+}
+
 /*
  * Reload the watchdog timer.  (ie, pat the watchdog)
  */
@@ -99,7 +102,7 @@ static inline void at91_wdt_reset(struct at91wdt_drvdata *driver_data)
 /*
  * Timer tick
  */
-static void at91_ping(unsigned long data)
+static void at91wdt_timer_tick(unsigned long data)
 {
 	struct watchdog_device *wddev = (struct watchdog_device *)data;
 	struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
@@ -107,45 +110,30 @@ static void at91_ping(unsigned long data)
 	if (time_before(jiffies, driver_data->next_heartbeat)) {
 		at91_wdt_reset(driver_data);
 		mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
+
+		if (!watchdog_is_open(wddev))
+			driver_data->next_heartbeat = jiffies
+						+ wddev->timeout * HZ;
 	} else
 		pr_crit("I will reset your machine !\n");
 }
 
-/*
- * Watchdog device is opened, and watchdog starts running.
- */
-static int at91_wdt_open(struct inode *inode, struct file *file)
-{
-	driver_data->next_heartbeat = jiffies + heartbeat * HZ;
-	mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
-
-	return nonseekable_open(inode, file);
-}
-
-/*
- * Close the watchdog device.
- */
-static int at91_wdt_close(struct inode *inode, struct file *file)
-{
-	del_timer(&driver_data->timer);
-
-	return 0;
-}
-
-/*
- * Set the watchdog time interval in 1/256Hz (write-once)
- * Counter is 12 bit.
- */
-static int at91_wdt_settimeout(unsigned int timeout)
+static int at91wdt_enable(struct watchdog_device *wddev, unsigned int timeout)
 {
+	struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
 	unsigned int reg;
-	unsigned int mr;
 
-	/* Check if disabled */
-	mr = wdt_read(AT91_WDT_MR);
-	if (mr & AT91_WDT_WDDIS) {
-		pr_err("sorry, watchdog is disabled\n");
-		return -EIO;
+	/*
+	 * Check if the watchdog is disabled,
+	 * if disabled, the reason is the bootstrap or the bootloader has
+	 * written the Watchdog Timer Mode Register to disable the
+	 * watchdog timer
+	 */
+	reg = wdt_read(driver_data, AT91_WDT_MR);
+	if (reg & AT91_WDT_WDDIS) {
+		driver_data->is_enable = false;
+		pr_info("sorry, watchdog is disabled\n");
+		return -1;
 	}
 
 	/*
@@ -159,7 +147,9 @@ static int at91_wdt_settimeout(unsigned int timeout)
 		| AT91_WDT_WDDBGHLT	/* disabled in debug mode */
 		| AT91_WDT_WDD		/* restart at any time */
 		| (timeout & AT91_WDT_WDV);  /* timer value */
-	wdt_write(AT91_WDT_MR, reg);
+	wdt_write(driver_data, AT91_WDT_MR, reg);
+
+	driver_data->is_enable = true;
 
 	return 0;
 }
@@ -170,99 +160,61 @@ static const struct watchdog_info at91_wdt_info = {
 						WDIOF_MAGICCLOSE,
 };
 
-/*
- * Handle commands from user-space.
- */
-static long at91_wdt_ioctl(struct file *file,
-		unsigned int cmd, unsigned long arg)
+static int at91wdt_start(struct watchdog_device *wddev)
 {
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-	int new_value;
-
-	switch (cmd) {
-	case WDIOC_GETSUPPORT:
-		return copy_to_user(argp, &at91_wdt_info,
-				    sizeof(at91_wdt_info)) ? -EFAULT : 0;
-
-	case WDIOC_GETSTATUS:
-	case WDIOC_GETBOOTSTATUS:
-		return put_user(0, p);
+	struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
 
-	case WDIOC_KEEPALIVE:
-		driver_data->next_heartbeat = jiffies + heartbeat * HZ;
+	if (driver_data->is_enable) {
+		driver_data->next_heartbeat = jiffies + wddev->timeout * HZ;
+		mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
 		return 0;
-
-	case WDIOC_SETTIMEOUT:
-		if (get_user(new_value, p))
-			return -EFAULT;
-
-		heartbeat = new_value;
-		driver_data->next_heartbeat = jiffies + heartbeat * HZ;
-
-		return put_user(new_value, p);  /* return current value */
-
-	case WDIOC_GETTIMEOUT:
-		return put_user(heartbeat, p);
-	}
-	return -ENOTTY;
+	} else
+		return -EIO;
 }
 
-/*
- * Pat the watchdog whenever device is written to.
- */
-static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
-								loff_t *ppos)
+static int at91wdt_stop(struct watchdog_device *wddev)
 {
-	if (!len)
-		return 0;
-
-	/* Scan for magic character */
-	if (!nowayout) {
-		size_t i;
-
+	struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
 
-		for (i = 0; i < len; i++) {
-			char c;
-			if (get_user(c, data + i))
-				return -EFAULT;
-			}
-		}
-	}
+	if (driver_data->is_enable)
+		return -EIO;
+	else
+		return 0;
+}
 
-	driver_data->next_heartbeat = jiffies + heartbeat * HZ;
+static int at91wdt_ping(struct watchdog_device *wddev)
+{
+	struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
 
-	return len;
+	if (driver_data->is_enable) {
+		driver_data->next_heartbeat = jiffies + wddev->timeout * HZ;
+		 mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
+		return 0;
+	} else
+		return -EIO;
 }
-
 /* ......................................................................... */
 
-static const struct file_operations at91wdt_fops = {
-	.owner			= THIS_MODULE,
-	.llseek			= no_llseek,
-	.unlocked_ioctl	= at91_wdt_ioctl,
-	.open			= at91_wdt_open,
-	.release		= at91_wdt_close,
-	.write			= at91_wdt_write,
-};
-
-static struct miscdevice at91wdt_miscdev = {
-	.minor		= WATCHDOG_MINOR,
-	.name		= "watchdog",
-	.fops		= &at91wdt_fops,
+static struct watchdog_ops at91wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = at91wdt_start,
+	.stop = at91wdt_stop,
+	.ping = at91wdt_ping,
 };
 
 static struct watchdog_device at91wdt_wdd __initdata = {
 	.timeout = WDT_HEARTBEAT,
 	.min_timeout = MIN_HEARTBEAT,
 	.max_timeout = MAX_HEARTBEAT,
+	.info = &at91_wdt_info,
+	.ops = &at91wdt_ops,
 };
 
 static int __init at91wdt_probe(struct platform_device *pdev)
 {
 	struct at91wdt_drvdata *driver_data;
 	struct resource	*r;
-	int res;
+	int ret;
 
 	driver_data = devm_kzalloc(&pdev->dev,
 				sizeof(*driver_data), GFP_KERNEL);
@@ -273,32 +225,32 @@ static int __init at91wdt_probe(struct platform_device *pdev)
 
 	watchdog_set_drvdata(&at91wdt_wdd, driver_data);
 
-	if (at91wdt_miscdev.parent)
-		return -EBUSY;
-	at91wdt_miscdev.parent = &pdev->dev;
-
 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!r)
 		return -ENODEV;
+
 	driver_data->phybase = ioremap(r->start, resource_size(r));
 	if (!driver_data->phybase) {
 		dev_err(&pdev->dev, "failed to map registers, aborting.\n");
 		return -ENOMEM;
 	}
 
-	watchdog_init_timeout(&at91wdt_wdd, heartbeat, pdev->dev.of_node);
+	ret = watchdog_register_device(&at91wdt_wdd);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot register watchdog (%d)\n", ret);
+		return ret;
+	}
 
-	/* Set watchdog */
-	res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
-	if (res)
-		return res;
+	watchdog_init_timeout(&at91wdt_wdd, heartbeat, pdev->dev.of_node);
 
-	res = misc_register(&at91wdt_miscdev);
-	if (res)
-		return res;
+	ret = at91wdt_enable(&at91wdt_wdd, ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+	if (ret) {
+		pr_info("the watchdog has been disabled\n");
+		return 0;
+	}
 
 	driver_data->next_heartbeat = jiffies + at91wdt_wdd.timeout * HZ;
-	setup_timer(&driver_data->timer, at91_ping,
+	setup_timer(&driver_data->timer, at91wdt_timer_tick,
 					(unsigned long)&at91wdt_wdd);
 	mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
 
@@ -310,13 +262,9 @@ static int __init at91wdt_probe(struct platform_device *pdev)
 
 static int __exit at91wdt_remove(struct platform_device *pdev)
 {
-	int res;
+	watchdog_unregister_device(&at91wdt_wdd);
 
-	res = misc_deregister(&at91wdt_miscdev);
-	if (!res)
-		at91wdt_miscdev.parent = NULL;
-
-	return res;
+	return 0;
 }
 
 #if defined(CONFIG_OF)
@@ -353,4 +301,3 @@ module_exit(at91sam_wdt_exit);
 MODULE_AUTHOR("Renaud CERRATO <r.cerrato at til-technologies.fr>");
 MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-- 
1.7.9.5




More information about the linux-arm-kernel mailing list