Skip to contentSkip to conversation

watchdog: gemini/ftwdt010: rename DT bindings

PATCH New Linus Walleij 2 participants 10 messages Oct 16, 2017 – Oct 22, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v2 1/5 watchdog: gemini/ftwdt010: rename DT bindings

The device tree bindings are in two copies and also should be consolidated into a single Faraday Technology FTWDT010 binding since we uncovered that this IP part is a standard IP from Faraday.

Cc devicetree at vger.kernel.org

---
ChangeLog v1->v2:
- Collect Rob's ACK.

---
 .../bindings/watchdog/cortina,gemini-watchdog.txt       | 17 -----------------
 ...{cortina,gemin-watchdog.txt => faraday,ftwdt010.txt} | 11 ++++++++---
 2 files changed, 8 insertions(+), 20 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt
 rename Documentation/devicetree/bindings/watchdog/{cortina,gemin-watchdog.txt => faraday,ftwdt010.txt} (55%)
Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt deleted +0 -17
deleted file mode 100644
index bc4b865d178b..000000000000
@@ -1,17 +0,0 @@
-Cortina Systems Gemini SoC Watchdog
-
-Required properties:
-- compatible : must be "cortina,gemini-watchdog"
-- reg : shall contain base register location and length
-- interrupts : shall contain the interrupt for the watchdog
-
-Optional properties:
-- timeout-sec : the default watchdog timeout in seconds.
-
-Example:
-
-watchdog at 41000000 {
-	compatible = "cortina,gemini-watchdog";
-	reg = <0x41000000 0x1000>;
-	interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
-};
Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt renamed from Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt +8 -3
similarity index 55%
rename from Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt
rename to Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt
index bc4b865d178b..9ecdb502e605 100644
@@ -1,7 +1,12 @@
-Cortina Systems Gemini SoC Watchdog
+Faraday Technology FTWDT010 watchdog
+
+This is an IP part from Faraday Technology found in the Gemini
+SoCs and others.
 
 Required properties:
-- compatible : must be "cortina,gemini-watchdog"
+- compatible : must be one of
+  "faraday,ftwdt010"
+  "cortina,gemini-watchdog", "faraday,ftwdt010"
 - reg : shall contain base register location and length
 - interrupts : shall contain the interrupt for the watchdog
 
@@ -11,7 +16,7 @@ Optional properties:
 Example:
 
 watchdog at 41000000 {
-	compatible = "cortina,gemini-watchdog";
+	compatible = "faraday,ftwdt010";
 	reg = <0x41000000 0x1000>;
 	interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
 };
Signature · 1 line
2.13.6
#1 lore raw

PATCH v2 2/5 watchdog: gemini/ftwdt010: rename driver and symbols

This renames all the driver files and symbols for the Gemini watchdog to FTWDT010 as it has been revealed that this IP block is a generic watchdog timer from Faraday Technology used in several SoC designs.

Select this driver by default for the Gemini, it is a sensible driver to always have enabled.

---
ChangeLog v1->v2:
- Fixed speling in commit message, rebased.

---
 drivers/watchdog/Kconfig                          |  14 +--
 drivers/watchdog/Makefile                         |   2 +-
 drivers/watchdog/{gemini_wdt.c => ftwdt010_wdt.c} | 117 +++++++++++-----------
 3 files changed, 68 insertions(+), 65 deletions(-)
 rename drivers/watchdog/{gemini_wdt.c => ftwdt010_wdt.c} (50%)
drivers/watchdog/Kconfig +8 -6
index c722cbfdc7e6..fd44a542036a 100644
@@ -321,16 +321,18 @@ config 977_WATCHDOG
 
 	  Not sure? It's safe to say N.
 
-config GEMINI_WATCHDOG
-	tristate "Gemini watchdog"
-	depends on ARCH_GEMINI
+config FTWDT010_WATCHDOG
+	tristate "Faraday Technology FTWDT010 watchdog"
+	depends on ARM || COMPILE_TEST
 	select WATCHDOG_CORE
+	default ARCH_GEMINI
 	help
-	  Say Y here if to include support for the watchdog timer
-	  embedded in the Cortina Systems Gemini family of devices.
+	  Say Y here if to include support for the Faraday Technology
+	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini
+	  family of devices.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called gemini_wdt.
+	  module will be called ftwdt010_wdt.
 
 config IXP4XX_WATCHDOG
 	tristate "IXP4xx Watchdog"
drivers/watchdog/Makefile +1 -1
index 56adf9fa67d0..df91d7db821c 100644
@@ -45,7 +45,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o
+obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
drivers/watchdog/ftwdt010_wdt.c renamed from drivers/watchdog/gemini_wdt.c +59 -58

245 lines not on this page · raw message

Signature · 1 line
2.13.6
maintainer
#2 lore raw

PATCH v2 2/5 watchdog: gemini/ftwdt010: rename driver and symbols

Quoted 9 lines · Linus Walleij

This renames all the driver files and symbols for the Gemini watchdog to FTWDT010 as it has been revealed that this IP block is a generic watchdog timer from Faraday Technology used in several SoC designs.

Select this driver by default for the Gemini, it is a sensible driver to always have enabled.

Quoted 311 lines

---
ChangeLog v1->v2:
- Fixed speling in commit message, rebased.

---
 drivers/watchdog/Kconfig                          |  14 +--
 drivers/watchdog/Makefile                         |   2 +-
 drivers/watchdog/{gemini_wdt.c => ftwdt010_wdt.c} | 117 +++++++++++-----------
 3 files changed, 68 insertions(+), 65 deletions(-)
 rename drivers/watchdog/{gemini_wdt.c => ftwdt010_wdt.c} (50%)
drivers/watchdog/Kconfig +8 -6
index c722cbfdc7e6..fd44a542036a 100644
@@ -321,16 +321,18 @@ config 977_WATCHDOG
 
 	  Not sure? It's safe to say N.
 
-config GEMINI_WATCHDOG
-	tristate "Gemini watchdog"
-	depends on ARCH_GEMINI
+config FTWDT010_WATCHDOG
+	tristate "Faraday Technology FTWDT010 watchdog"
+	depends on ARM || COMPILE_TEST
 	select WATCHDOG_CORE
+	default ARCH_GEMINI
 	help
-	  Say Y here if to include support for the watchdog timer
-	  embedded in the Cortina Systems Gemini family of devices.
+	  Say Y here if to include support for the Faraday Technology
+	  FTWDT010 watchdog timer embedded in the Cortina Systems Gemini
+	  family of devices.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called gemini_wdt.
+	  module will be called ftwdt010_wdt.
 
 config IXP4XX_WATCHDOG
 	tristate "IXP4xx Watchdog"
drivers/watchdog/Makefile +1 -1
index 56adf9fa67d0..df91d7db821c 100644
@@ -45,7 +45,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o
+obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
drivers/watchdog/ftwdt010_wdt.c renamed from drivers/watchdog/gemini_wdt.c +59 -58
similarity index 50%
rename from drivers/watchdog/gemini_wdt.c
rename to drivers/watchdog/ftwdt010_wdt.c
index 8155aa619e4c..637ffd812f0b 100644
@@ -1,5 +1,5 @@
 /*
- * Watchdog driver for Cortina Systems Gemini SoC
+ * Watchdog driver for Faraday Technology FTWDT010
  *
  * Copyright (C) 2017 Linus Walleij <[email protected]>
  *
@@ -22,10 +22,10 @@
 #include <linux/slab.h>
 #include <linux/watchdog.h>
 
-#define GEMINI_WDCOUNTER	0x0
-#define GEMINI_WDLOAD		0x4
-#define GEMINI_WDRESTART	0x8
-#define GEMINI_WDCR		0xC
+#define FTWDT010_WDCOUNTER	0x0
+#define FTWDT010_WDLOAD		0x4
+#define FTWDT010_WDRESTART	0x8
+#define FTWDT010_WDCR		0xC
 
 #define WDRESTART_MAGIC		0x5AB9
 
@@ -35,79 +35,79 @@
 
 #define WDT_CLOCK		5000000		/* 5 MHz */
 
-struct gemini_wdt {
+struct ftwdt010_wdt {
 	struct watchdog_device	wdd;
 	struct device		*dev;
 	void __iomem		*base;
 };
 
 static inline
-struct gemini_wdt *to_gemini_wdt(struct watchdog_device *wdd)
+struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
 {
-	return container_of(wdd, struct gemini_wdt, wdd);
+	return container_of(wdd, struct ftwdt010_wdt, wdd);
 }
 
-static int gemini_wdt_start(struct watchdog_device *wdd)
+static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 {
-	struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
 
-	writel(wdd->timeout * WDT_CLOCK, gwdt->base + GEMINI_WDLOAD);
-	writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
+	writel(wdd->timeout * WDT_CLOCK, gwdt->base + FTWDT010_WDLOAD);
+	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
 	/* set clock before enabling */
 	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
-			gwdt->base + GEMINI_WDCR);
+			gwdt->base + FTWDT010_WDCR);
 	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
-			gwdt->base + GEMINI_WDCR);
+			gwdt->base + FTWDT010_WDCR);
 
 	return 0;
 }
 
-static int gemini_wdt_stop(struct watchdog_device *wdd)
+static int ftwdt010_wdt_stop(struct watchdog_device *wdd)
 {
-	struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
 
-	writel(0, gwdt->base + GEMINI_WDCR);
+	writel(0, gwdt->base + FTWDT010_WDCR);
 
 	return 0;
 }
 
-static int gemini_wdt_ping(struct watchdog_device *wdd)
+static int ftwdt010_wdt_ping(struct watchdog_device *wdd)
 {
-	struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
 
-	writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
+	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
 
 	return 0;
 }
 
-static int gemini_wdt_set_timeout(struct watchdog_device *wdd,
+static int ftwdt010_wdt_set_timeout(struct watchdog_device *wdd,
 				  unsigned int timeout)
 {
 	wdd->timeout = timeout;
 	if (watchdog_active(wdd))
-		gemini_wdt_start(wdd);
+		ftwdt010_wdt_start(wdd);
 
 	return 0;
 }
 
-static irqreturn_t gemini_wdt_interrupt(int irq, void *data)
+static irqreturn_t ftwdt010_wdt_interrupt(int irq, void *data)
 {
-	struct gemini_wdt *gwdt = data;
+	struct ftwdt010_wdt *gwdt = data;
 
 	watchdog_notify_pretimeout(&gwdt->wdd);
 
 	return IRQ_HANDLED;
 }
 
-static const struct watchdog_ops gemini_wdt_ops = {
-	.start		= gemini_wdt_start,
-	.stop		= gemini_wdt_stop,
-	.ping		= gemini_wdt_ping,
-	.set_timeout	= gemini_wdt_set_timeout,
+static const struct watchdog_ops ftwdt010_wdt_ops = {
+	.start		= ftwdt010_wdt_start,
+	.stop		= ftwdt010_wdt_stop,
+	.ping		= ftwdt010_wdt_ping,
+	.set_timeout	= ftwdt010_wdt_set_timeout,
 	.owner		= THIS_MODULE,
 };
 
-static const struct watchdog_info gemini_wdt_info = {
+static const struct watchdog_info ftwdt010_wdt_info = {
 	.options	= WDIOF_KEEPALIVEPING
 			| WDIOF_MAGICCLOSE
 			| WDIOF_SETTIMEOUT,
@@ -115,11 +115,11 @@ static const struct watchdog_info gemini_wdt_info = {
 };
 
 
-static int gemini_wdt_probe(struct platform_device *pdev)
+static int ftwdt010_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
-	struct gemini_wdt *gwdt;
+	struct ftwdt010_wdt *gwdt;
 	unsigned int reg;
 	int irq;
 	int ret;
@@ -138,8 +138,8 @@ static int gemini_wdt_probe(struct platform_device *pdev)
 		return -EINVAL;
 
 	gwdt->dev = dev;
-	gwdt->wdd.info = &gemini_wdt_info;
-	gwdt->wdd.ops = &gemini_wdt_ops;
+	gwdt->wdd.info = &ftwdt010_wdt_info;
+	gwdt->wdd.ops = &ftwdt010_wdt_ops;
 	gwdt->wdd.min_timeout = 1;
 	gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK;
 	gwdt->wdd.parent = dev;
@@ -151,14 +151,14 @@ static int gemini_wdt_probe(struct platform_device *pdev)
 	gwdt->wdd.timeout = 13U;
 	watchdog_init_timeout(&gwdt->wdd, 0, dev);
 
-	reg = readw(gwdt->base + GEMINI_WDCR);
+	reg = readw(gwdt->base + FTWDT010_WDCR);
 	if (reg & WDCR_ENABLE) {
 		/* Watchdog was enabled by the bootloader, disable it. */
 		reg &= ~WDCR_ENABLE;
-		writel(reg, gwdt->base + GEMINI_WDCR);
+		writel(reg, gwdt->base + FTWDT010_WDCR);
 	}
 
-	ret = devm_request_irq(dev, irq, gemini_wdt_interrupt, 0,
+	ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
 			       "watchdog bark", gwdt);
 	if (ret)
 		return ret;
@@ -171,59 +171,60 @@ static int gemini_wdt_probe(struct platform_device *pdev)
 
 	/* Set up platform driver data */
 	platform_set_drvdata(pdev, gwdt);
-	dev_info(dev, "Gemini watchdog driver enabled\n");
+	dev_info(dev, "FTWDT010 watchdog driver enabled\n");
 
 	return 0;
 }
 
-static int __maybe_unused gemini_wdt_suspend(struct device *dev)
+static int __maybe_unused ftwdt010_wdt_suspend(struct device *dev)
 {
-	struct gemini_wdt *gwdt = dev_get_drvdata(dev);
+	struct ftwdt010_wdt *gwdt = dev_get_drvdata(dev);
 	unsigned int reg;
 
-	reg = readw(gwdt->base + GEMINI_WDCR);
+	reg = readw(gwdt->base + FTWDT010_WDCR);
 	reg &= ~WDCR_ENABLE;
-	writel(reg, gwdt->base + GEMINI_WDCR);
+	writel(reg, gwdt->base + FTWDT010_WDCR);
 
 	return 0;
 }
 
-static int __maybe_unused gemini_wdt_resume(struct device *dev)
+static int __maybe_unused ftwdt010_wdt_resume(struct device *dev)
 {
-	struct gemini_wdt *gwdt = dev_get_drvdata(dev);
+	struct ftwdt010_wdt *gwdt = dev_get_drvdata(dev);
 	unsigned int reg;
 
 	if (watchdog_active(&gwdt->wdd)) {
-		reg = readw(gwdt->base + GEMINI_WDCR);
+		reg = readw(gwdt->base + FTWDT010_WDCR);
 		reg |= WDCR_ENABLE;
-		writel(reg, gwdt->base + GEMINI_WDCR);
+		writel(reg, gwdt->base + FTWDT010_WDCR);
 	}
 
 	return 0;
 }
 
-static const struct dev_pm_ops gemini_wdt_dev_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(gemini_wdt_suspend,
-				gemini_wdt_resume)
+static const struct dev_pm_ops ftwdt010_wdt_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(ftwdt010_wdt_suspend,
+				ftwdt010_wdt_resume)
 };
 
 #ifdef CONFIG_OF
-static const struct of_device_id gemini_wdt_match[] = {
+static const struct of_device_id ftwdt010_wdt_match[] = {
+	{ .compatible = "faraday,ftwdt010" },
 	{ .compatible = "cortina,gemini-watchdog" },
 	{},
 };
-MODULE_DEVICE_TABLE(of, gemini_wdt_match);
+MODULE_DEVICE_TABLE(of, ftwdt010_wdt_match);
 #endif
 
-static struct platform_driver gemini_wdt_driver = {
-	.probe		= gemini_wdt_probe,
+static struct platform_driver ftwdt010_wdt_driver = {
+	.probe		= ftwdt010_wdt_probe,
 	.driver		= {
-		.name	= "gemini-wdt",
-		.of_match_table = of_match_ptr(gemini_wdt_match),
-		.pm = &gemini_wdt_dev_pm_ops,
+		.name	= "ftwdt010-wdt",
+		.of_match_table = of_match_ptr(ftwdt010_wdt_match),
+		.pm = &ftwdt010_wdt_dev_pm_ops,
 	},
 };
-module_platform_driver(gemini_wdt_driver);
+module_platform_driver(ftwdt010_wdt_driver);
 MODULE_AUTHOR("Linus Walleij");
-MODULE_DESCRIPTION("Watchdog driver for Gemini");
+MODULE_DESCRIPTION("Watchdog driver for Faraday Technology FTWDT010");
 MODULE_LICENSE("GPL");
#3 lore raw

PATCH v2 3/5 watchdog: ftwdt010: Make interrupt optional

In reply to Linus Walleij

The Moxart does not appear to be using the interrupt from the watchdog timer, maybe it's not even routed, so as to support more architectures with this driver, make the interrupt optional.

While we are at it: actually enable the use of the interrupt if present by setting the right bit in the control register and define the missing control register bits.

---
ChangeLog v1->v2:
- Fix surplus flag assignment of enable |= WDCR_CLOCK_5MHZ

---
 drivers/watchdog/ftwdt010_wdt.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)
drivers/watchdog/ftwdt010_wdt.c +18 -12
index 637ffd812f0b..a9c2912ee280 100644
@@ -30,6 +30,8 @@
 #define WDRESTART_MAGIC		0x5AB9
 
 #define WDCR_CLOCK_5MHZ		BIT(4)
+#define WDCR_WDEXT		BIT(3)
+#define WDCR_WDINTR		BIT(2)
 #define WDCR_SYS_RST		BIT(1)
 #define WDCR_ENABLE		BIT(0)
 
@@ -39,6 +41,7 @@ struct ftwdt010_wdt {
 	struct watchdog_device	wdd;
 	struct device		*dev;
 	void __iomem		*base;
+	bool			has_irq;
 };
 
 static inline
@@ -50,14 +53,17 @@ struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
 static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 {
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
+	u32 enable;
 
 	writel(wdd->timeout * WDT_CLOCK, gwdt->base + FTWDT010_WDLOAD);
 	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
 	/* set clock before enabling */
-	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
-			gwdt->base + FTWDT010_WDCR);
-	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
-			gwdt->base + FTWDT010_WDCR);
+	enable = WDCR_CLOCK_5MHZ | WDCR_SYS_RST;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
+	if (gwdt->has_irq)
+		enable |= WDCR_WDINTR;
+	enable |= WDCR_ENABLE;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
 
 	return 0;
 }
@@ -133,10 +139,6 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	if (IS_ERR(gwdt->base))
 		return PTR_ERR(gwdt->base);
 
-	irq = platform_get_irq(pdev, 0);
-	if (!irq)
-		return -EINVAL;
-
 	gwdt->dev = dev;
 	gwdt->wdd.info = &ftwdt010_wdt_info;
 	gwdt->wdd.ops = &ftwdt010_wdt_ops;
@@ -158,10 +160,14 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 		writel(reg, gwdt->base + FTWDT010_WDCR);
 	}
 
-	ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
-			       "watchdog bark", gwdt);
-	if (ret)
-		return ret;
+	irq = platform_get_irq(pdev, 0);
+	if (irq) {
+		ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
+				       "watchdog bark", gwdt);
+		if (ret)
+			return ret;
+		gwdt->has_irq = true;
+	}
 
 	ret = devm_watchdog_register_device(dev, &gwdt->wdd);
 	if (ret) {
Signature · 1 line
2.13.6
maintainer
#4 lore raw

PATCH v2 3/5 watchdog: ftwdt010: Make interrupt optional

Quoted 10 lines · Linus Walleij

The Moxart does not appear to be using the interrupt from the watchdog timer, maybe it's not even routed, so as to support more architectures with this driver, make the interrupt optional.

While we are at it: actually enable the use of the interrupt if present by setting the right bit in the control register and define the missing control register bits.

Quoted 80 lines

---
ChangeLog v1->v2:
- Fix surplus flag assignment of enable |= WDCR_CLOCK_5MHZ

---
 drivers/watchdog/ftwdt010_wdt.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)
drivers/watchdog/ftwdt010_wdt.c +18 -12
index 637ffd812f0b..a9c2912ee280 100644
@@ -30,6 +30,8 @@
 #define WDRESTART_MAGIC		0x5AB9
 
 #define WDCR_CLOCK_5MHZ		BIT(4)
+#define WDCR_WDEXT		BIT(3)
+#define WDCR_WDINTR		BIT(2)
 #define WDCR_SYS_RST		BIT(1)
 #define WDCR_ENABLE		BIT(0)
 
@@ -39,6 +41,7 @@ struct ftwdt010_wdt {
 	struct watchdog_device	wdd;
 	struct device		*dev;
 	void __iomem		*base;
+	bool			has_irq;
 };
 
 static inline
@@ -50,14 +53,17 @@ struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
 static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 {
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
+	u32 enable;
 
 	writel(wdd->timeout * WDT_CLOCK, gwdt->base + FTWDT010_WDLOAD);
 	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
 	/* set clock before enabling */
-	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
-			gwdt->base + FTWDT010_WDCR);
-	writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
-			gwdt->base + FTWDT010_WDCR);
+	enable = WDCR_CLOCK_5MHZ | WDCR_SYS_RST;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
+	if (gwdt->has_irq)
+		enable |= WDCR_WDINTR;
+	enable |= WDCR_ENABLE;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
 
 	return 0;
 }
@@ -133,10 +139,6 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	if (IS_ERR(gwdt->base))
 		return PTR_ERR(gwdt->base);
 
-	irq = platform_get_irq(pdev, 0);
-	if (!irq)
-		return -EINVAL;
-
 	gwdt->dev = dev;
 	gwdt->wdd.info = &ftwdt010_wdt_info;
 	gwdt->wdd.ops = &ftwdt010_wdt_ops;
@@ -158,10 +160,14 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 		writel(reg, gwdt->base + FTWDT010_WDCR);
 	}
 
-	ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
-			       "watchdog bark", gwdt);
-	if (ret)
-		return ret;
+	irq = platform_get_irq(pdev, 0);
+	if (irq) {
+		ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
+				       "watchdog bark", gwdt);
+		if (ret)
+			return ret;
+		gwdt->has_irq = true;
+	}
 
 	ret = devm_watchdog_register_device(dev, &gwdt->wdd);
 	if (ret) {
#5 lore raw

PATCH v2 4/5 watchdog: ftwdt010: Add clock support

In reply to Linus Walleij

The Gemini platform now provides a proper clock look-up for this and other IPs, so add clock support to the driver. This also aids in using the same driver with other platforms such as MOXA ART.

The IP has two clock inputs: PCLK (the IP peripheral clock) and EXTCLK (an external clock). We are a bit elaborate around this:
on Gemini the EXTCLK is used by default today and it's 5MHz, and on MOXA ART the PCLK is used. On Aspeed the EXTCLK is used and it's 1MHz. So add some clever code to fall back to platform defaults if PCLK or EXTCLK is not provided by the device tree.

Take this opportunity to implement .remove() for the driver that stops the watchdog and disables the clocks.

Add credits that this code is inspired by MOXA ART.

---
ChangeLog v1->v2:
- Strictly require the clock framework
- Sort header files in alphabetic order
- Fix the error path to properly disable the clocks
- Fix spelling in commit message
- Be minimalist with informational messages and cut down on error messages

---
 drivers/watchdog/Kconfig        |  1 +
 drivers/watchdog/ftwdt010_wdt.c | 79 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 71 insertions(+), 9 deletions(-)
drivers/watchdog/Kconfig +1 -0
index fd44a542036a..245cff03c992 100644
@@ -324,6 +324,7 @@ config 977_WATCHDOG
 config FTWDT010_WATCHDOG
 	tristate "Faraday Technology FTWDT010 watchdog"
 	depends on ARM || COMPILE_TEST
+	depends on COMMON_CLK
 	select WATCHDOG_CORE
 	default ARCH_GEMINI
 	help
drivers/watchdog/ftwdt010_wdt.c +70 -9

159 lines not on this page · raw message

Signature · 1 line
2.13.6
maintainer
#6 lore raw

PATCH v2 4/5 watchdog: ftwdt010: Add clock support

Quoted 11 lines · Linus Walleij

The Gemini platform now provides a proper clock look-up for this and other IPs, so add clock support to the driver. This also aids in using the same driver with other platforms such as MOXA ART.

The IP has two clock inputs: PCLK (the IP peripheral clock) and EXTCLK (an external clock). We are a bit elaborate around this:
on Gemini the EXTCLK is used by default today and it's 5MHz, and on MOXA ART the PCLK is used. On Aspeed the EXTCLK is used and it's 1MHz. So add some clever code to fall back to platform defaults if PCLK or EXTCLK is not provided by the device tree.

Am I missing something ? The code suggests that PCLK is mandatory.

+ gwdt->pclk = devm_clk_get(dev, "PCLK");
+ if (IS_ERR(gwdt->pclk))
+ return PTR_ERR(gwdt->pclk);

Quoted 108 lines

Take this opportunity to implement .remove() for the driver that stops the watchdog and disables the clocks.

Add credits that this code is inspired by MOXA ART.

---
ChangeLog v1->v2:
- Strictly require the clock framework
- Sort header files in alphabetic order
- Fix the error path to properly disable the clocks
- Fix spelling in commit message
- Be minimalist with informational messages and cut down on error messages

---
 drivers/watchdog/Kconfig        |  1 +
 drivers/watchdog/ftwdt010_wdt.c | 79 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 71 insertions(+), 9 deletions(-)
drivers/watchdog/Kconfig +1 -0
index fd44a542036a..245cff03c992 100644
@@ -324,6 +324,7 @@ config 977_WATCHDOG
 config FTWDT010_WATCHDOG
 	tristate "Faraday Technology FTWDT010 watchdog"
 	depends on ARM || COMPILE_TEST
+	depends on COMMON_CLK
 	select WATCHDOG_CORE
 	default ARCH_GEMINI
 	help
drivers/watchdog/ftwdt010_wdt.c +14 -5
index a9c2912ee280..21c3ac7f557a 100644
@@ -5,6 +5,8 @@
  *
  * Inspired by the out-of-tree drivers from OpenWRT:
  * Copyright (C) 2009 Paulius Zaleckas <[email protected]>
+ * Inspired by the MOXA ART driver from Jonas Jensen:
+ * Copyright (C) 2013 Jonas Jensen <[email protected]>
  *
  * 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
@@ -12,12 +14,14 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/clk.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/watchdog.h>
@@ -29,19 +33,21 @@
 
 #define WDRESTART_MAGIC		0x5AB9
 
-#define WDCR_CLOCK_5MHZ		BIT(4)
+#define WDCR_EXTCLK		BIT(4)
 #define WDCR_WDEXT		BIT(3)
 #define WDCR_WDINTR		BIT(2)
 #define WDCR_SYS_RST		BIT(1)
 #define WDCR_ENABLE		BIT(0)
 
-#define WDT_CLOCK		5000000		/* 5 MHz */
-
 struct ftwdt010_wdt {
 	struct watchdog_device	wdd;
 	struct device		*dev;
 	void __iomem		*base;
 	bool			has_irq;
+	struct clk		*pclk;
+	struct clk		*extclk;
+	unsigned int		clk_freq;
+	bool			use_extclk;
 };
 
 static inline
@@ -55,10 +61,12 @@ static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
 	u32 enable;
 
-	writel(wdd->timeout * WDT_CLOCK, gwdt->base + FTWDT010_WDLOAD);
+	writel(wdd->timeout * gwdt->clk_freq, gwdt->base + FTWDT010_WDLOAD);
 	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
 	/* set clock before enabling */
-	enable = WDCR_CLOCK_5MHZ | WDCR_SYS_RST;
+	enable = WDCR_SYS_RST;
+	if (gwdt->use_extclk)
+		enable |= WDCR_EXTCLK;
 	writel(enable, gwdt->base + FTWDT010_WDCR);
 	if (gwdt->has_irq)
 		enable |= WDCR_WDINTR;
@@ -124,6 +132,7 @@ static const struct watchdog_info ftwdt010_wdt_info = {
 static int ftwdt010_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
 	struct resource *res;
 	struct ftwdt010_wdt *gwdt;
 	unsigned int reg;

drivers/watchdog/ftwdt010_wdt.c static int ftwdt010_wdt_probe(struct platform_device *pdev) · line 151

Quoted 4 lines
drivers/watchdog/ftwdt010_wdt.c +1 -0
@@ -139,11 +148,40 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	if (IS_ERR(gwdt->base))
 		return PTR_ERR(gwdt->base);
 
+	gwdt->use_extclk = of_property_read_bool(np, "faraday,use-extclk");

Documentation and Ack from Rob required.

drivers/watchdog/ftwdt010_wdt.c static int ftwdt010_wdt_probe(struct platform_device *pdev) · line 160

Quoted 9 lines
drivers/watchdog/ftwdt010_wdt.c +9 -0
+
+	gwdt->pclk = devm_clk_get(dev, "PCLK");
+	if (IS_ERR(gwdt->pclk))
+		return PTR_ERR(gwdt->pclk);
+	ret = clk_prepare_enable(gwdt->pclk);
+	if (ret)
+		return ret;
+	if (!gwdt->use_extclk)
+		gwdt->clk_freq = clk_get_rate(gwdt->pclk);

else case to the is statement below ?

drivers/watchdog/ftwdt010_wdt.c static int ftwdt010_wdt_probe(struct platform_device *pdev) · line 163

Quoted 3 lines
drivers/watchdog/ftwdt010_wdt.c +3 -0
+
+	/* Only enable and get frequency from EXTCLK if it's in use */
+	if (gwdt->use_extclk) {

Does this use case still require pclk ?

Quoted 4 lines
drivers/watchdog/ftwdt010_wdt.c +4 -0
+		gwdt->extclk = devm_clk_get(dev, "EXTCLK");
+		if (IS_ERR(gwdt->extclk)) {
+			ret = PTR_ERR(gwdt->extclk);
+			goto out_disable_pclk;

drivers/watchdog/ftwdt010_wdt.c static int ftwdt010_wdt_probe(struct platform_device *pdev) · line 177

Quoted 10 lines
drivers/watchdog/ftwdt010_wdt.c +10 -0
+		}
+		ret = clk_prepare_enable(gwdt->extclk);
+		if (ret)
+			goto out_disable_pclk;
+		gwdt->clk_freq = clk_get_rate(gwdt->extclk);
+	}
+
+	if (gwdt->clk_freq == 0) {
+		ret = -EINVAL;
+		goto out_disable_extclk;

Yet another use case of the rejected devm_clk_prepare_enable() :-(.

Quoted 64 lines
drivers/watchdog/ftwdt010_wdt.c +29 -4
+	}
+
 	gwdt->dev = dev;
 	gwdt->wdd.info = &ftwdt010_wdt_info;
 	gwdt->wdd.ops = &ftwdt010_wdt_ops;
 	gwdt->wdd.min_timeout = 1;
-	gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK;
+	gwdt->wdd.max_timeout = UINT_MAX / gwdt->clk_freq;
 	gwdt->wdd.parent = dev;
 
 	/*
@@ -165,19 +203,41 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 		ret = devm_request_irq(dev, irq, ftwdt010_wdt_interrupt, 0,
 				       "watchdog bark", gwdt);
 		if (ret)
-			return ret;
+			goto out_disable_extclk;
 		gwdt->has_irq = true;
 	}
 
 	ret = devm_watchdog_register_device(dev, &gwdt->wdd);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register watchdog\n");
-		return ret;
+		goto out_disable_extclk;
 	}
 
 	/* Set up platform driver data */
 	platform_set_drvdata(pdev, gwdt);
-	dev_info(dev, "FTWDT010 watchdog driver enabled\n");
+	dev_info(dev, "FTWDT010 watchdog driver @%uHz\n",
+		 gwdt->clk_freq);
+
+	return 0;
+
+out_disable_extclk:
+	if (gwdt->use_extclk)
+		clk_disable_unprepare(gwdt->extclk);
+out_disable_pclk:
+	if (!IS_ERR(gwdt->pclk))
+		clk_disable_unprepare(gwdt->pclk);
+
+	return ret;
+}
+
+static int ftwdt010_wdt_remove(struct platform_device *pdev)
+{
+	struct ftwdt010_wdt *gwdt = platform_get_drvdata(pdev);
+
+	writel(0, gwdt->base + FTWDT010_WDCR);
+	clk_disable_unprepare(gwdt->pclk);
+	if (gwdt->use_extclk)
+		clk_disable_unprepare(gwdt->extclk);
 
 	return 0;
 }
@@ -224,6 +284,7 @@ MODULE_DEVICE_TABLE(of, ftwdt010_wdt_match);
 
 static struct platform_driver ftwdt010_wdt_driver = {
 	.probe		= ftwdt010_wdt_probe,
+	.remove		= ftwdt010_wdt_remove,
 	.driver		= {
 		.name	= "ftwdt010-wdt",
 		.of_match_table = of_match_ptr(ftwdt010_wdt_match),
#7 lore raw

PATCH v2 5/5 watchdog: ftwdt010: Add restart support

In reply to Linus Walleij

This enables the Faraday FTWDT010 to restart the system, if need be. Set the restart priority for the watchdog to 128.

---
ChangeLog v1->v2:
- Rebased, no changes.

---
 drivers/watchdog/ftwdt010_wdt.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/watchdog/ftwdt010_wdt.c +18 -0
index 21c3ac7f557a..0be7c2db642d 100644
@@ -56,6 +56,22 @@ struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
 	return container_of(wdd, struct ftwdt010_wdt, wdd);
 }
 
+static int ftwdt010_wdt_restart(struct watchdog_device *wdd,
+				unsigned long action, void *data)
+{
+	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
+	u32 enable;
+
+	writel(1, gwdt->base + FTWDT010_WDLOAD);
+	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
+	enable = WDCR_SYS_RST | WDCR_ENABLE;
+	if (gwdt->use_extclk)
+		enable |= WDCR_EXTCLK;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
+
+	return 0;
+}
+
 static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 {
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
@@ -118,6 +134,7 @@ static const struct watchdog_ops ftwdt010_wdt_ops = {
 	.stop		= ftwdt010_wdt_stop,
 	.ping		= ftwdt010_wdt_ping,
 	.set_timeout	= ftwdt010_wdt_set_timeout,
+	.restart	= ftwdt010_wdt_restart,
 	.owner		= THIS_MODULE,
 };
 
@@ -190,6 +207,7 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	 */
 	gwdt->wdd.timeout = 13U;
 	watchdog_init_timeout(&gwdt->wdd, 0, dev);
+	watchdog_set_restart_priority(&gwdt->wdd, 128);
 
 	reg = readw(gwdt->base + FTWDT010_WDCR);
 	if (reg & WDCR_ENABLE) {
Signature · 1 line
2.13.6
maintainer
#8 lore raw

PATCH v2 5/5 watchdog: ftwdt010: Add restart support

Quoted 5 lines · Linus Walleij

This enables the Faraday FTWDT010 to restart the system, if need be. Set the restart priority for the watchdog to 128.

Quoted 50 lines

---
ChangeLog v1->v2:
- Rebased, no changes.

---
 drivers/watchdog/ftwdt010_wdt.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/watchdog/ftwdt010_wdt.c +18 -0
index 21c3ac7f557a..0be7c2db642d 100644
@@ -56,6 +56,22 @@ struct ftwdt010_wdt *to_ftwdt010_wdt(struct watchdog_device *wdd)
 	return container_of(wdd, struct ftwdt010_wdt, wdd);
 }
 
+static int ftwdt010_wdt_restart(struct watchdog_device *wdd,
+				unsigned long action, void *data)
+{
+	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
+	u32 enable;
+
+	writel(1, gwdt->base + FTWDT010_WDLOAD);
+	writel(WDRESTART_MAGIC, gwdt->base + FTWDT010_WDRESTART);
+	enable = WDCR_SYS_RST | WDCR_ENABLE;
+	if (gwdt->use_extclk)
+		enable |= WDCR_EXTCLK;
+	writel(enable, gwdt->base + FTWDT010_WDCR);
+
+	return 0;
+}
+
 static int ftwdt010_wdt_start(struct watchdog_device *wdd)
 {
 	struct ftwdt010_wdt *gwdt = to_ftwdt010_wdt(wdd);
@@ -118,6 +134,7 @@ static const struct watchdog_ops ftwdt010_wdt_ops = {
 	.stop		= ftwdt010_wdt_stop,
 	.ping		= ftwdt010_wdt_ping,
 	.set_timeout	= ftwdt010_wdt_set_timeout,
+	.restart	= ftwdt010_wdt_restart,
 	.owner		= THIS_MODULE,
 };
 
@@ -190,6 +207,7 @@ static int ftwdt010_wdt_probe(struct platform_device *pdev)
 	 */
 	gwdt->wdd.timeout = 13U;
 	watchdog_init_timeout(&gwdt->wdd, 0, dev);
+	watchdog_set_restart_priority(&gwdt->wdd, 128);
 
 	reg = readw(gwdt->base + FTWDT010_WDCR);
 	if (reg & WDCR_ENABLE) {
maintainer
#9 lore raw

PATCH v2 1/5 watchdog: gemini/ftwdt010: rename DT bindings

In reply to Linus Walleij
Quoted 8 lines · Linus Walleij

The device tree bindings are in two copies and also should be consolidated into a single Faraday Technology FTWDT010 binding since we uncovered that this IP part is a standard IP from Faraday.

Cc devicetree at vger.kernel.org
Quoted 64 lines

---
ChangeLog v1->v2:
- Collect Rob's ACK.

---
 .../bindings/watchdog/cortina,gemini-watchdog.txt       | 17 -----------------
 ...{cortina,gemin-watchdog.txt => faraday,ftwdt010.txt} | 11 ++++++++---
 2 files changed, 8 insertions(+), 20 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt
 rename Documentation/devicetree/bindings/watchdog/{cortina,gemin-watchdog.txt => faraday,ftwdt010.txt} (55%)
Documentation/devicetree/bindings/watchdog/cortina,gemini-watchdog.txt deleted +0 -17
deleted file mode 100644
index bc4b865d178b..000000000000
@@ -1,17 +0,0 @@
-Cortina Systems Gemini SoC Watchdog
-
-Required properties:
-- compatible : must be "cortina,gemini-watchdog"
-- reg : shall contain base register location and length
-- interrupts : shall contain the interrupt for the watchdog
-
-Optional properties:
-- timeout-sec : the default watchdog timeout in seconds.
-
-Example:
-
-watchdog at 41000000 {
-	compatible = "cortina,gemini-watchdog";
-	reg = <0x41000000 0x1000>;
-	interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
-};
Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt renamed from Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt +8 -3
similarity index 55%
rename from Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt
rename to Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt
index bc4b865d178b..9ecdb502e605 100644
@@ -1,7 +1,12 @@
-Cortina Systems Gemini SoC Watchdog
+Faraday Technology FTWDT010 watchdog
+
+This is an IP part from Faraday Technology found in the Gemini
+SoCs and others.
 
 Required properties:
-- compatible : must be "cortina,gemini-watchdog"
+- compatible : must be one of
+  "faraday,ftwdt010"
+  "cortina,gemini-watchdog", "faraday,ftwdt010"
 - reg : shall contain base register location and length
 - interrupts : shall contain the interrupt for the watchdog
 
@@ -11,7 +16,7 @@ Optional properties:
 Example:
 
 watchdog at 41000000 {
-	compatible = "cortina,gemini-watchdog";
+	compatible = "faraday,ftwdt010";
 	reg = <0x41000000 0x1000>;
 	interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
 };