For the Watchdog Timer Mode Register can be only written only once,
so struct watchdog_info options only support WDIOF_KEEPALIVEPING,
not support WDIOF_SETTIMEOUT and WDIOF_MAGICCLOSE.

Signed-off-by: Wenyou Yang <wenyou.y...@atmel.com>
---
 drivers/watchdog/Kconfig        |    1 +
 drivers/watchdog/at91sam9_wdt.c |   90 ++++++++++++++++++++++++++++++++-------
 2 files changed, 76 insertions(+), 15 deletions(-)

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ad1bb93..dda695f 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -114,6 +114,7 @@ config AT91RM9200_WATCHDOG
 config AT91SAM9X_WATCHDOG
        tristate "AT91SAM9X / AT91CAP9 watchdog"
        depends on ARCH_AT91 && !ARCH_AT91RM9200
+       select WATCHDOG_CORE
        help
          Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will
          reboot your system when the timeout is reached.
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index e2d6111..84c2aa7 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -85,6 +85,11 @@ static inline void wdt_write(struct at91wdt_drvdata 
*driver_data,
        __raw_writel((val), driver_data->base + 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)
  */
@@ -101,9 +106,12 @@ static void at91_ping(unsigned long data)
        struct watchdog_device *wddev = (struct watchdog_device *)data;
        struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
 
-       if (time_before(jiffies, driver_data->next_heartbeat))
-               at91_wdt_reset();
+       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 + heartbeat * HZ;
        } else
                pr_crit("I will reset your machine !\n");
 }
@@ -144,17 +152,62 @@ static int at91wdt_enable(struct watchdog_device *wddev, 
unsigned int timeout)
        return 0;
 }
 
-static const struct watchdog_info at91_wdt_info = {
+static int at91wdt_start(struct watchdog_device *wddev)
+{
+       struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
+
+       if (driver_data->enabled)
+               return 0;
+       else
+               return -EIO;
+}
+
+static int at91wdt_stop(struct watchdog_device *wddev)
+{
+       struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
+
+       if (driver_data->enabled)
+               return -EIO;
+       else
+               return 0;
+}
+
+static int at91wdt_keepalive(struct watchdog_device *wddev)
+{
+       struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev);
+
+       if (driver_data->enabled) {
+               driver_data->next_heartbeat = jiffies + heartbeat * HZ;
+               return 0;
+       } else
+               return -EIO;
+}
+
+/* ......................................................................... */
+
+static const struct watchdog_info at91wdt_info = {
        .identity       = DRV_NAME,
-       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
-                                               WDIOF_MAGICCLOSE,
+       .options        = WDIOF_KEEPALIVEPING,
+       .firmware_version       = 0,
+};
+
+static struct watchdog_ops at91wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = at91wdt_start,
+       .stop = at91wdt_stop,
+       .ping = at91wdt_keepalive,
+};
+
+static struct watchdog_device at91_wddev = {
+       .info = &at91wdt_info,
+       .ops = &at91wdt_ops,
 };
 
 static int __init at91wdt_probe(struct platform_device *pdev)
 {
        struct at91wdt_drvdata *driver_data;
-       struct resource *r;
-       int res;
+       struct resource *res;
+       int ret;
 
        driver_data = devm_kzalloc(&pdev->dev,
                                sizeof(*driver_data), GFP_KERNEL);
@@ -163,10 +216,10 @@ static int __init at91wdt_probe(struct platform_device 
*pdev)
                return -ENOMEM;
        }
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
                return -ENODEV;
-       driver_data->base = ioremap(r->start, resource_size(r));
+       driver_data->base = ioremap(res->start, resource_size(res));
        if (!driver_data->base) {
                dev_err(&pdev->dev, "failed to map registers, aborting.\n");
                return -ENOMEM;
@@ -174,14 +227,21 @@ static int __init at91wdt_probe(struct platform_device 
*pdev)
 
        watchdog_set_drvdata(&at91_wddev, driver_data);
 
-       res = at91wdt_enable(&at91_wddev);
-       if (res) {
+       ret = at91wdt_enable(&at91_wddev, ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+       if (ret) {
                dev_err(&pdev->dev, "cannot enable watchdog (%d)\n", ret);
                return ret;
        }
 
+       ret = watchdog_register_device(&at91_wddev);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register watchdog (%d)\n", ret);
+               return ret;
+       }
+
        driver_data->next_heartbeat = jiffies + heartbeat * HZ;
-       setup_timer(&driver_data->timer, at91_ping, 0);
+       setup_timer(&driver_data->timer, at91_ping,
+                                       (unsigned long)&at91_wddev);
        mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT);
 
        pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
@@ -192,9 +252,9 @@ static int __init at91wdt_probe(struct platform_device 
*pdev)
 
 static int __exit at91wdt_remove(struct platform_device *pdev)
 {
-       int res;
+       watchdog_unregister_device(&at91_wddev);
 
-       return res;
+       return 0;
 }
 
 static struct platform_driver at91wdt_driver = {
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to