watchdog: add new driver for STMP3xxx and i.MX23/28
authorWolfram Sang <w.sang@pengutronix.de>
Tue, 27 Sep 2011 20:35:40 +0000 (22:35 +0200)
committerWim Van Sebroeck <wim@iguana.be>
Fri, 1 Mar 2013 11:44:34 +0000 (12:44 +0100)
Replace the existing STMP3xxx driver because it has enough drawbacks
that a rewrite is apropriate. The new driver is designed to use the
watchdog framework which makes it a lot smaller and avoids open coding
the watchdog API again. It also uses now an explicitly exported function
from the RTC driver to set up its registers (the old driver silently
reused the hopefully(!) already remapped RTC registers). Also, this
driver is mach independent, while the old one depends on a mach replaced
by another one a year ago. Since the user interface is still the
standard watchdog API, users don't need to adapt.

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/stmp3xxx_rtc_wdt.c [new file with mode: 0644]

index 7f61687504b784a0285c8bb3e5d7312629335fba..879232186ca6cceb087d7b9d3666dac4d0ecfcb8 100644 (file)
@@ -326,6 +326,16 @@ config STMP3XXX_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called stmp3xxx_wdt.
 
+config STMP3XXX_RTC_WATCHDOG
+       tristate "Freescale STMP3XXX & i.MX23/28 watchdog"
+       depends on RTC_DRV_STMP
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the watchdog timer inside
+         the RTC for the STMP37XX/378X or i.MX23/28 SoC.
+         To compile this driver as a module, choose M here: the
+         module will be called stmp3xxx_rtc_wdt.
+
 config NUC900_WATCHDOG
        tristate "Nuvoton NUC900 watchdog"
        depends on ARCH_W90X900
index f7a612c0a5b40e29b2ac047d37fe2aa88c48f16e..f1fc6a1d92ca6f237d9ea24b72c3392cc15780ab 100644 (file)
@@ -49,6 +49,7 @@ obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
 obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
 obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
+obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
 obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
 obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
new file mode 100644 (file)
index 0000000..c97e98d
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Watchdog driver for the RTC based watchdog in STMP3xxx and i.MX23/28
+ *
+ * Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * Copyright (C) 2011-12 Wolfram Sang, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * 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/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/platform_device.h>
+#include <linux/stmp3xxx_rtc_wdt.h>
+
+#define WDOG_TICK_RATE 1000 /* 1 kHz clock */
+#define STMP3XXX_DEFAULT_TIMEOUT 19
+#define STMP3XXX_MAX_TIMEOUT (UINT_MAX / WDOG_TICK_RATE)
+
+static int heartbeat = STMP3XXX_DEFAULT_TIMEOUT;
+module_param(heartbeat, uint, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds from 1 to "
+                __MODULE_STRING(STMP3XXX_MAX_TIMEOUT) ", default "
+                __MODULE_STRING(STMP3XXX_DEFAULT_TIMEOUT));
+
+static int wdt_start(struct watchdog_device *wdd)
+{
+       struct device *dev = watchdog_get_drvdata(wdd);
+       struct stmp3xxx_wdt_pdata *pdata = dev->platform_data;
+
+       pdata->wdt_set_timeout(dev->parent, wdd->timeout * WDOG_TICK_RATE);
+       return 0;
+}
+
+static int wdt_stop(struct watchdog_device *wdd)
+{
+       struct device *dev = watchdog_get_drvdata(wdd);
+       struct stmp3xxx_wdt_pdata *pdata = dev->platform_data;
+
+       pdata->wdt_set_timeout(dev->parent, 0);
+       return 0;
+}
+
+static int wdt_set_timeout(struct watchdog_device *wdd, unsigned new_timeout)
+{
+       wdd->timeout = new_timeout;
+       return wdt_start(wdd);
+}
+
+static const struct watchdog_info stmp3xxx_wdt_ident = {
+       .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = "STMP3XXX RTC Watchdog",
+};
+
+static const struct watchdog_ops stmp3xxx_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = wdt_start,
+       .stop = wdt_stop,
+       .set_timeout = wdt_set_timeout,
+};
+
+static struct watchdog_device stmp3xxx_wdd = {
+       .info = &stmp3xxx_wdt_ident,
+       .ops = &stmp3xxx_wdt_ops,
+       .min_timeout = 1,
+       .max_timeout = STMP3XXX_MAX_TIMEOUT,
+       .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
+};
+
+static int stmp3xxx_wdt_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev);
+
+       stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT);
+
+       ret = watchdog_register_device(&stmp3xxx_wdd);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "cannot register watchdog device\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
+                       stmp3xxx_wdd.timeout);
+       return 0;
+}
+
+static int stmp3xxx_wdt_remove(struct platform_device *pdev)
+{
+       watchdog_unregister_device(&stmp3xxx_wdd);
+       return 0;
+}
+
+static struct platform_driver stmp3xxx_wdt_driver = {
+       .driver = {
+               .name = "stmp3xxx_rtc_wdt",
+       },
+       .probe = stmp3xxx_wdt_probe,
+       .remove = stmp3xxx_wdt_remove,
+};
+module_platform_driver(stmp3xxx_wdt_driver);
+
+MODULE_DESCRIPTION("STMP3XXX RTC Watchdog Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);