Re: [PATCH v2 2/2] watchdog: add support for Sigma Designs SMP86xx/SMP87xx

2015-11-19 Thread Måns Rullgård
Guenter Roeck  writes:

>> +writel(WD_CONFIG_XTAL_IN, dev->base + WD_CONFIG);
>
> What happens if the DISABLE bit was previously set (assuming
> that DISABLE means that the watchdog is disabled) ?
>
> Concern I guess would be the combination of DISABLE being set
> and WD_COUNTER at a value != 0 (say, 1). That might effectively
> auto-enable the watchdog or even reset the system.

There's no sane reason why it would be in that state, but then again
firmware authors are not sane.

How about checking the DISABLE bit, and if it's set turn off the
counter, otherwise leave it running?

-- 
Måns Rullgård
m...@mansr.com
--
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/


Re: [PATCH v2 2/2] watchdog: add support for Sigma Designs SMP86xx/SMP87xx

2015-11-19 Thread Guenter Roeck

On 11/18/2015 09:55 AM, Mans Rullgard wrote:

This adds support for the Sigma Designs SMP86xx/SMP87xx family built-in
watchdog.

Signed-off-by: Mans Rullgard 
---
Changes:
- combine start and ping functions
- use watchdog_init_timeout()
- calculate max timeout from clock rate
- add get_timeleft callback
- check if already running on startup
- add explanatory comments
- improve kconfig text
---
  drivers/watchdog/Kconfig  |  10 ++
  drivers/watchdog/Makefile |   1 +
  drivers/watchdog/tangox_wdt.c | 213 ++
  3 files changed, 224 insertions(+)
  create mode 100644 drivers/watchdog/tangox_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7a8a6c6..f43ff7a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -135,6 +135,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
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 53d4827..46cb387 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -187,6 +187,7 @@ 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
diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c
new file mode 100644
index 000..0b458ff
--- /dev/null
+++ b/drivers/watchdog/tangox_wdt.c
@@ -0,0 +1,213 @@
+/*
+ *  Copyright (C) 2015 Mans Rullgard 
+ *  SMP86xx/SMP87xx Watchdog driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+"Watchdog cannot be stopped once started (default="
+__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout");
+
+/*
+ * Counter counts down from programmed value.  Reset asserts when
+ * the counter reaches 1.
+ */
+#define WD_COUNTER 0
+
+#define WD_CONFIG  4
+#define WD_CONFIG_XTAL_IN  BIT(0)
+#define WD_CONFIG_DISABLE  BIT(31)
+


Please include linux/bitops.h when using BIT macros.


+struct tangox_wdt_device {
+   struct watchdog_device wdt;
+   void __iomem *base;
+   unsigned long clk_rate;
+   struct clk *clk;
+   struct notifier_block restart;
+};
+
+static int tangox_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int new_timeout)
+{
+   wdt->timeout = new_timeout;
+
+   return 0;
+}
+
+static int tangox_wdt_start(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+   u32 ticks;
+
+   ticks = 1 + wdt->timeout * dev->clk_rate;
+   writel(ticks, dev->base + WD_COUNTER);
+
+   return 0;
+}
+
+static int tangox_wdt_stop(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+
+   writel(0, dev->base + WD_COUNTER);
+
+   return 0;
+}
+
+static unsigned int tangox_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+   u32 count;
+
+   count = readl(dev->base + WD_COUNTER);
+
+   if (!count)
+   return 0;
+
+   return (count - 1) / dev->clk_rate;
+}
+
+static const struct watchdog_info tangox_wdt_info = {
+   .options  = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+   .identity = "tangox watchdog",
+};
+
+static const struct watchdog_ops tangox_wdt_ops = {
+   .start  = tangox_wdt_start,
+   .stop   = tangox_wdt_stop,
+   .set_timeout= tangox_wdt_set_timeout,
+   .get_timeleft   = tangox_wdt_get_timeleft,
+};
+
+static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action,
+   

[PATCH v2 2/2] watchdog: add support for Sigma Designs SMP86xx/SMP87xx

2015-11-18 Thread Mans Rullgard
This adds support for the Sigma Designs SMP86xx/SMP87xx family built-in
watchdog.

Signed-off-by: Mans Rullgard 
---
Changes:
- combine start and ping functions
- use watchdog_init_timeout()
- calculate max timeout from clock rate
- add get_timeleft callback
- check if already running on startup
- add explanatory comments
- improve kconfig text
---
 drivers/watchdog/Kconfig  |  10 ++
 drivers/watchdog/Makefile |   1 +
 drivers/watchdog/tangox_wdt.c | 213 ++
 3 files changed, 224 insertions(+)
 create mode 100644 drivers/watchdog/tangox_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7a8a6c6..f43ff7a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -135,6 +135,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
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 53d4827..46cb387 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -187,6 +187,7 @@ 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
diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c
new file mode 100644
index 000..0b458ff
--- /dev/null
+++ b/drivers/watchdog/tangox_wdt.c
@@ -0,0 +1,213 @@
+/*
+ *  Copyright (C) 2015 Mans Rullgard 
+ *  SMP86xx/SMP87xx Watchdog driver
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under  the terms of the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+"Watchdog cannot be stopped once started (default="
+__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout");
+
+/*
+ * Counter counts down from programmed value.  Reset asserts when
+ * the counter reaches 1.
+ */
+#define WD_COUNTER 0
+
+#define WD_CONFIG  4
+#define WD_CONFIG_XTAL_IN  BIT(0)
+#define WD_CONFIG_DISABLE  BIT(31)
+
+struct tangox_wdt_device {
+   struct watchdog_device wdt;
+   void __iomem *base;
+   unsigned long clk_rate;
+   struct clk *clk;
+   struct notifier_block restart;
+};
+
+static int tangox_wdt_set_timeout(struct watchdog_device *wdt,
+ unsigned int new_timeout)
+{
+   wdt->timeout = new_timeout;
+
+   return 0;
+}
+
+static int tangox_wdt_start(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+   u32 ticks;
+
+   ticks = 1 + wdt->timeout * dev->clk_rate;
+   writel(ticks, dev->base + WD_COUNTER);
+
+   return 0;
+}
+
+static int tangox_wdt_stop(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+
+   writel(0, dev->base + WD_COUNTER);
+
+   return 0;
+}
+
+static unsigned int tangox_wdt_get_timeleft(struct watchdog_device *wdt)
+{
+   struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+   u32 count;
+
+   count = readl(dev->base + WD_COUNTER);
+
+   if (!count)
+   return 0;
+
+   return (count - 1) / dev->clk_rate;
+}
+
+static const struct watchdog_info tangox_wdt_info = {
+   .options  = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+   .identity = "tangox watchdog",
+};
+
+static const struct watchdog_ops tangox_wdt_ops = {
+   .start  = tangox_wdt_start,
+   .stop   = tangox_wdt_stop,
+   .set_timeout= tangox_wdt_set_timeout,
+   .get_timeleft   = tangox_wdt_get_timeleft,
+};
+
+static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+   struct tangox_wdt_device *dev =
+   container_of(nb, stru