Merge tag 'linux-watchdog-6.2-rc1' of git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 17 Dec 2022 14:34:01 +0000 (08:34 -0600)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 17 Dec 2022 14:34:01 +0000 (08:34 -0600)
Pull watchdog updates from Wim Van Sebroeck:

 - Add Advantech EC watchdog driver

 - Add support for MT6795 Helio X10 watchdog and toprgu

 - Add support for MT8188 watchdog device

 - Remove #ifdef guards for PM related functions

 - Other fixes and improvements

* tag 'linux-watchdog-6.2-rc1' of git://www.linux-watchdog.org/linux-watchdog:
  watchdog: aspeed: Enable pre-timeout interrupt
  watchdog: iTCO_wdt: Set NO_REBOOT if the watchdog is not already running
  watchdog: rn5t618: add support for read out bootstatus
  watchdog: kempld: Remove #ifdef guards for PM related functions
  watchdog: omap: Remove #ifdef guards for PM related functions
  watchdog: twl4030: Remove #ifdef guards for PM related functions
  watchdog: at91rm9200: Remove #ifdef guards for PM related functions
  watchdog: Add Advantech EC watchdog driver
  dt-bindings: watchdog: mediatek,mtk-wdt: Add compatible for MT8173
  dt-bindings: watchdog: mediatek,mtk-wdt: Add compatible for MT6795
  dt-bindings: watchdog: mediatek: Convert mtk-wdt to json-schema
  watchdog: mediatek: mt8188: add wdt support
  dt-bindings: reset: mt8188: add toprgu reset-controller header file
  dt-bindings: watchdog: Add compatible for MediaTek MT8188
  watchdog: mtk_wdt: Add support for MT6795 Helio X10 watchdog and toprgu

16 files changed:
Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/mtk-wdt.txt [deleted file]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/advantech_ec_wdt.c [new file with mode: 0644]
drivers/watchdog/aspeed_wdt.c
drivers/watchdog/at91rm9200_wdt.c
drivers/watchdog/db8500_wdt.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/kempld_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/rn5t618_wdt.c
drivers/watchdog/twl4030_wdt.c
include/dt-bindings/reset/mt8188-resets.h [new file with mode: 0644]
include/linux/mfd/rn5t618.h

diff --git a/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml b/Documentation/devicetree/bindings/watchdog/mediatek,mtk-wdt.yaml
new file mode 100644 (file)
index 0000000..b360560
--- /dev/null
@@ -0,0 +1,80 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/mediatek,mtk-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek SoCs Watchdog timer
+
+maintainers:
+  - Matthias Brugger <matthias.bgg@gmail.com>
+
+description:
+  The watchdog supports a pre-timeout interrupt that fires
+  timeout-sec/2 before the expiry.
+
+allOf:
+  - $ref: watchdog.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - enum:
+          - mediatek,mt2712-wdt
+          - mediatek,mt6589-wdt
+          - mediatek,mt6795-wdt
+          - mediatek,mt7986-wdt
+          - mediatek,mt8183-wdt
+          - mediatek,mt8186-wdt
+          - mediatek,mt8188-wdt
+          - mediatek,mt8192-wdt
+          - mediatek,mt8195-wdt
+      - items:
+          - enum:
+              - mediatek,mt2701-wdt
+              - mediatek,mt6582-wdt
+              - mediatek,mt6797-wdt
+              - mediatek,mt7622-wdt
+              - mediatek,mt7623-wdt
+              - mediatek,mt7629-wdt
+              - mediatek,mt8173-wdt
+              - mediatek,mt8516-wdt
+          - const: mediatek,mt6589-wdt
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    items:
+      - description: Watchdog pre-timeout (bark) interrupt
+
+  mediatek,disable-extrst:
+    description: Disable sending output reset signal
+    type: boolean
+
+  '#reset-cells':
+    const: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        watchdog: watchdog@10007000 {
+            compatible = "mediatek,mt8183-wdt";
+            reg = <0 0x10007000 0 0x100>;
+            interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_LOW>;
+            mediatek,disable-extrst;
+            timeout-sec = <10>;
+            #reset-cells = <1>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
deleted file mode 100644 (file)
index 762c62e..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-Mediatek SoCs Watchdog timer
-
-The watchdog supports a pre-timeout interrupt that fires timeout-sec/2
-before the expiry.
-
-Required properties:
-
-- compatible should contain:
-       "mediatek,mt2701-wdt", "mediatek,mt6589-wdt": for MT2701
-       "mediatek,mt2712-wdt": for MT2712
-       "mediatek,mt6582-wdt", "mediatek,mt6589-wdt": for MT6582
-       "mediatek,mt6589-wdt": for MT6589
-       "mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797
-       "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
-       "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
-       "mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
-       "mediatek,mt7986-wdt", "mediatek,mt6589-wdt": for MT7986
-       "mediatek,mt8183-wdt": for MT8183
-       "mediatek,mt8186-wdt", "mediatek,mt6589-wdt": for MT8186
-       "mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
-       "mediatek,mt8192-wdt": for MT8192
-       "mediatek,mt8195-wdt", "mediatek,mt6589-wdt": for MT8195
-
-- reg : Specifies base physical address and size of the registers.
-
-Optional properties:
-- mediatek,disable-extrst: disable send output reset signal
-- interrupts: Watchdog pre-timeout (bark) interrupt.
-- timeout-sec: contains the watchdog timeout in seconds.
-- #reset-cells: Should be 1.
-
-Example:
-
-watchdog: watchdog@10007000 {
-       compatible = "mediatek,mt8183-wdt",
-                    "mediatek,mt6589-wdt";
-       mediatek,disable-extrst;
-       reg = <0 0x10007000 0 0x100>;
-       interrupts = <GIC_SPI 139 IRQ_TYPE_NONE>;
-       timeout-sec = <10>;
-       #reset-cells = <1>;
-};
index b64bc49c7f30edda4e422519971430ffe2d7a0c7..0bc40b763b065210998eb886ec7192773016d535 100644 (file)
@@ -1055,6 +1055,13 @@ config ADVANTECH_WDT
          feature. More information can be found at
          <https://www.advantech.com.tw/products/>
 
+config ADVANTECH_EC_WDT
+       tristate "Advantech Embedded Controller Watchdog Timer"
+       depends on X86
+       help
+               This driver supports Advantech products with ITE based Embedded Controller.
+               It does not support Advantech products with other ECs or without EC.
+
 config ALIM1535_WDT
        tristate "ALi M1535 PMU Watchdog Timer"
        depends on X86 && PCI
index d41e5f830ae7f85060835ce790d24a8a0dea8789..9cbf6580f16c9fdf4bfca1b1c6778686624c1efc 100644 (file)
@@ -102,6 +102,7 @@ obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
+obj-$(CONFIG_ADVANTECH_EC_WDT) += advantech_ec_wdt.o
 obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
 obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
 obj-$(CONFIG_EBC_C384_WDT) += ebc-c384_wdt.o
diff --git a/drivers/watchdog/advantech_ec_wdt.c b/drivers/watchdog/advantech_ec_wdt.c
new file mode 100644 (file)
index 0000000..7c380f9
--- /dev/null
@@ -0,0 +1,205 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *     Advantech Embedded Controller Watchdog Driver
+ *
+ *     This driver supports Advantech products with ITE based Embedded Controller.
+ *     It does not support Advantech products with other ECs or without EC.
+ *
+ *     Copyright (C) 2022 Advantech Europe B.V.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/isa.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/watchdog.h>
+
+#define DRIVER_NAME            "advantech_ec_wdt"
+
+/* EC IO region */
+#define EC_BASE_ADDR           0x299
+#define EC_ADDR_EXTENT         2
+
+/* EC minimum IO access delay in ms */
+#define EC_MIN_DELAY           10
+
+/* EC interface definitions */
+#define EC_ADDR_CMD            (EC_BASE_ADDR + 1)
+#define EC_ADDR_DATA           EC_BASE_ADDR
+#define EC_CMD_EC_PROBE                0x30
+#define EC_CMD_COMM            0x89
+#define EC_CMD_WDT_START       0x28
+#define EC_CMD_WDT_STOP                0x29
+#define EC_CMD_WDT_RESET       0x2A
+#define EC_DAT_EN_DLY_H                0x58
+#define EC_DAT_EN_DLY_L                0x59
+#define EC_DAT_RST_DLY_H       0x5E
+#define EC_DAT_RST_DLY_L       0x5F
+#define EC_MAGIC               0x95
+
+/* module parameters */
+#define MIN_TIME               1
+#define MAX_TIME               6000 /* 100 minutes */
+#define DEFAULT_TIME           60
+
+static unsigned int timeout;
+static ktime_t ec_timestamp;
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+                "Default Watchdog timer setting (" __MODULE_STRING(DEFAULT_TIME) "s). The range is from " __MODULE_STRING(MIN_TIME) " to " __MODULE_STRING(MAX_TIME) ".");
+
+static void adv_ec_wdt_timing_gate(void)
+{
+       ktime_t time_cur, time_delta;
+
+       /* ensure minimum delay between IO accesses*/
+       time_cur = ktime_get();
+       time_delta = ktime_to_ms(ktime_sub(time_cur, ec_timestamp));
+       if (time_delta < EC_MIN_DELAY) {
+               time_delta = EC_MIN_DELAY - time_delta;
+               usleep_range(time_delta * 1000, (time_delta + 1) * 1000);
+       }
+       ec_timestamp = ktime_get();
+}
+
+static void adv_ec_wdt_outb(unsigned char value, unsigned short port)
+{
+       adv_ec_wdt_timing_gate();
+       outb(value, port);
+}
+
+static unsigned char adv_ec_wdt_inb(unsigned short port)
+{
+       adv_ec_wdt_timing_gate();
+       return inb(port);
+}
+
+static int adv_ec_wdt_ping(struct watchdog_device *wdd)
+{
+       adv_ec_wdt_outb(EC_CMD_WDT_RESET, EC_ADDR_CMD);
+       return 0;
+}
+
+static int adv_ec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
+{
+       unsigned int val;
+
+       /* scale time to EC 100 ms base */
+       val = t * 10;
+
+       /* reset enable delay, just in case it was set by BIOS etc. */
+       adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
+       adv_ec_wdt_outb(EC_DAT_EN_DLY_H, EC_ADDR_DATA);
+       adv_ec_wdt_outb(0, EC_ADDR_DATA);
+
+       adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
+       adv_ec_wdt_outb(EC_DAT_EN_DLY_L, EC_ADDR_DATA);
+       adv_ec_wdt_outb(0, EC_ADDR_DATA);
+
+       /* set reset delay */
+       adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
+       adv_ec_wdt_outb(EC_DAT_RST_DLY_H, EC_ADDR_DATA);
+       adv_ec_wdt_outb(val >> 8, EC_ADDR_DATA);
+
+       adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
+       adv_ec_wdt_outb(EC_DAT_RST_DLY_L, EC_ADDR_DATA);
+       adv_ec_wdt_outb(val & 0xFF, EC_ADDR_DATA);
+
+       wdd->timeout = t;
+       return 0;
+}
+
+static int adv_ec_wdt_start(struct watchdog_device *wdd)
+{
+       adv_ec_wdt_set_timeout(wdd, wdd->timeout);
+       adv_ec_wdt_outb(EC_CMD_WDT_START, EC_ADDR_CMD);
+
+       return 0;
+}
+
+static int adv_ec_wdt_stop(struct watchdog_device *wdd)
+{
+       adv_ec_wdt_outb(EC_CMD_WDT_STOP, EC_ADDR_CMD);
+
+       return 0;
+}
+
+static const struct watchdog_info adv_ec_wdt_info = {
+       .identity =     DRIVER_NAME,
+       .options =      WDIOF_SETTIMEOUT |
+                       WDIOF_MAGICCLOSE |
+                       WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops adv_ec_wdt_ops = {
+       .owner =        THIS_MODULE,
+       .start =        adv_ec_wdt_start,
+       .stop =         adv_ec_wdt_stop,
+       .ping =         adv_ec_wdt_ping,
+       .set_timeout =  adv_ec_wdt_set_timeout,
+};
+
+static struct watchdog_device adv_ec_wdt_dev = {
+       .info =         &adv_ec_wdt_info,
+       .ops =          &adv_ec_wdt_ops,
+       .min_timeout =  MIN_TIME,
+       .max_timeout =  MAX_TIME,
+       .timeout =      DEFAULT_TIME,
+};
+
+static int adv_ec_wdt_probe(struct device *dev, unsigned int id)
+{
+       if (!devm_request_region(dev, EC_BASE_ADDR, EC_ADDR_EXTENT, dev_name(dev))) {
+               dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
+                       EC_BASE_ADDR, EC_BASE_ADDR + EC_ADDR_EXTENT);
+               return -EBUSY;
+       }
+
+       watchdog_init_timeout(&adv_ec_wdt_dev, timeout, dev);
+       watchdog_stop_on_reboot(&adv_ec_wdt_dev);
+       watchdog_stop_on_unregister(&adv_ec_wdt_dev);
+
+       return devm_watchdog_register_device(dev, &adv_ec_wdt_dev);
+}
+
+static struct isa_driver adv_ec_wdt_driver = {
+       .probe          = adv_ec_wdt_probe,
+       .driver         = {
+       .name           = DRIVER_NAME,
+       },
+};
+
+static int __init adv_ec_wdt_init(void)
+{
+       unsigned int val;
+
+       /* quick probe for EC */
+       if (!request_region(EC_BASE_ADDR, EC_ADDR_EXTENT, DRIVER_NAME))
+               return -EBUSY;
+
+       adv_ec_wdt_outb(EC_CMD_EC_PROBE, EC_ADDR_CMD);
+       val = adv_ec_wdt_inb(EC_ADDR_DATA);
+       release_region(EC_BASE_ADDR, EC_ADDR_EXTENT);
+
+       if (val != EC_MAGIC)
+               return -ENODEV;
+
+       return isa_register_driver(&adv_ec_wdt_driver, 1);
+}
+
+static void __exit adv_ec_wdt_exit(void)
+{
+       isa_unregister_driver(&adv_ec_wdt_driver);
+}
+
+module_init(adv_ec_wdt_init);
+module_exit(adv_ec_wdt_exit);
+
+MODULE_AUTHOR("Thomas Kastner <thomas.kastner@advantech.com>");
+MODULE_DESCRIPTION("Advantech Embedded Controller Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("20221019");
+MODULE_ALIAS("isa:" DRIVER_NAME);
index 0cff2adfbfc966355630cb3bb7e97f476b1eaa39..86b5331bc491166bd1eedc89796cecae624b0e7c 100644 (file)
@@ -5,11 +5,14 @@
  * Joel Stanley <joel@jms.id.au>
  */
 
+#include <linux/bits.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 
@@ -18,28 +21,41 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+struct aspeed_wdt_config {
+       u32 ext_pulse_width_mask;
+       u32 irq_shift;
+       u32 irq_mask;
+};
+
 struct aspeed_wdt {
        struct watchdog_device  wdd;
        void __iomem            *base;
        u32                     ctrl;
-};
-
-struct aspeed_wdt_config {
-       u32 ext_pulse_width_mask;
+       const struct aspeed_wdt_config *cfg;
 };
 
 static const struct aspeed_wdt_config ast2400_config = {
        .ext_pulse_width_mask = 0xff,
+       .irq_shift = 0,
+       .irq_mask = 0,
 };
 
 static const struct aspeed_wdt_config ast2500_config = {
        .ext_pulse_width_mask = 0xfffff,
+       .irq_shift = 12,
+       .irq_mask = GENMASK(31, 12),
+};
+
+static const struct aspeed_wdt_config ast2600_config = {
+       .ext_pulse_width_mask = 0xfffff,
+       .irq_shift = 0,
+       .irq_mask = GENMASK(31, 10),
 };
 
 static const struct of_device_id aspeed_wdt_of_table[] = {
        { .compatible = "aspeed,ast2400-wdt", .data = &ast2400_config },
        { .compatible = "aspeed,ast2500-wdt", .data = &ast2500_config },
-       { .compatible = "aspeed,ast2600-wdt", .data = &ast2500_config },
+       { .compatible = "aspeed,ast2600-wdt", .data = &ast2600_config },
        { },
 };
 MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
@@ -58,6 +74,7 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table);
 #define   WDT_CTRL_RESET_SYSTEM                BIT(1)
 #define   WDT_CTRL_ENABLE              BIT(0)
 #define WDT_TIMEOUT_STATUS     0x10
+#define   WDT_TIMEOUT_STATUS_IRQ               BIT(2)
 #define   WDT_TIMEOUT_STATUS_BOOT_SECONDARY    BIT(1)
 #define WDT_CLEAR_TIMEOUT_STATUS       0x14
 #define   WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION    BIT(0)
@@ -160,6 +177,26 @@ static int aspeed_wdt_set_timeout(struct watchdog_device *wdd,
        return 0;
 }
 
+static int aspeed_wdt_set_pretimeout(struct watchdog_device *wdd,
+                                    unsigned int pretimeout)
+{
+       struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
+       u32 actual = pretimeout * WDT_RATE_1MHZ;
+       u32 s = wdt->cfg->irq_shift;
+       u32 m = wdt->cfg->irq_mask;
+
+       wdd->pretimeout = pretimeout;
+       wdt->ctrl &= ~m;
+       if (pretimeout)
+               wdt->ctrl |= ((actual << s) & m) | WDT_CTRL_WDT_INTR;
+       else
+               wdt->ctrl &= ~WDT_CTRL_WDT_INTR;
+
+       writel(wdt->ctrl, wdt->base + WDT_CTRL);
+
+       return 0;
+}
+
 static int aspeed_wdt_restart(struct watchdog_device *wdd,
                              unsigned long action, void *data)
 {
@@ -232,6 +269,7 @@ static const struct watchdog_ops aspeed_wdt_ops = {
        .stop           = aspeed_wdt_stop,
        .ping           = aspeed_wdt_ping,
        .set_timeout    = aspeed_wdt_set_timeout,
+       .set_pretimeout = aspeed_wdt_set_pretimeout,
        .restart        = aspeed_wdt_restart,
        .owner          = THIS_MODULE,
 };
@@ -243,10 +281,29 @@ static const struct watchdog_info aspeed_wdt_info = {
        .identity       = KBUILD_MODNAME,
 };
 
+static const struct watchdog_info aspeed_wdt_pretimeout_info = {
+       .options        = WDIOF_KEEPALIVEPING
+                       | WDIOF_PRETIMEOUT
+                       | WDIOF_MAGICCLOSE
+                       | WDIOF_SETTIMEOUT,
+       .identity       = KBUILD_MODNAME,
+};
+
+static irqreturn_t aspeed_wdt_irq(int irq, void *arg)
+{
+       struct watchdog_device *wdd = arg;
+       struct aspeed_wdt *wdt = to_aspeed_wdt(wdd);
+       u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS);
+
+       if (status & WDT_TIMEOUT_STATUS_IRQ)
+               watchdog_notify_pretimeout(wdd);
+
+       return IRQ_HANDLED;
+}
+
 static int aspeed_wdt_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       const struct aspeed_wdt_config *config;
        const struct of_device_id *ofdid;
        struct aspeed_wdt *wdt;
        struct device_node *np;
@@ -259,11 +316,33 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        if (!wdt)
                return -ENOMEM;
 
+       np = dev->of_node;
+
+       ofdid = of_match_node(aspeed_wdt_of_table, np);
+       if (!ofdid)
+               return -EINVAL;
+       wdt->cfg = ofdid->data;
+
        wdt->base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(wdt->base))
                return PTR_ERR(wdt->base);
 
        wdt->wdd.info = &aspeed_wdt_info;
+
+       if (wdt->cfg->irq_mask) {
+               int irq = platform_get_irq_optional(pdev, 0);
+
+               if (irq > 0) {
+                       ret = devm_request_irq(dev, irq, aspeed_wdt_irq,
+                                              IRQF_SHARED, dev_name(dev),
+                                              wdt);
+                       if (ret)
+                               return ret;
+
+                       wdt->wdd.info = &aspeed_wdt_pretimeout_info;
+               }
+       }
+
        wdt->wdd.ops = &aspeed_wdt_ops;
        wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
        wdt->wdd.parent = dev;
@@ -273,13 +352,6 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_nowayout(&wdt->wdd, nowayout);
 
-       np = dev->of_node;
-
-       ofdid = of_match_node(aspeed_wdt_of_table, np);
-       if (!ofdid)
-               return -EINVAL;
-       config = ofdid->data;
-
        /*
         * On clock rates:
         *  - ast2400 wdt can run at PCLK, or 1MHz
@@ -331,7 +403,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
                (of_device_is_compatible(np, "aspeed,ast2600-wdt"))) {
                u32 reg = readl(wdt->base + WDT_RESET_WIDTH);
 
-               reg &= config->ext_pulse_width_mask;
+               reg &= wdt->cfg->ext_pulse_width_mask;
                if (of_property_read_bool(np, "aspeed,ext-active-high"))
                        reg |= WDT_ACTIVE_HIGH_MAGIC;
                else
@@ -339,7 +411,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
 
                writel(reg, wdt->base + WDT_RESET_WIDTH);
 
-               reg &= config->ext_pulse_width_mask;
+               reg &= wdt->cfg->ext_pulse_width_mask;
                if (of_property_read_bool(np, "aspeed,ext-push-pull"))
                        reg |= WDT_PUSH_PULL_MAGIC;
                else
@@ -349,7 +421,7 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
        }
 
        if (!of_property_read_u32(np, "aspeed,ext-pulse-duration", &duration)) {
-               u32 max_duration = config->ext_pulse_width_mask + 1;
+               u32 max_duration = wdt->cfg->ext_pulse_width_mask + 1;
 
                if (duration == 0 || duration > max_duration) {
                        dev_err(dev, "Invalid pulse duration: %uus\n",
index 6d751eb8191d6c8f3d2e398a5364432bc4d0e1b4..5126454bb86138116f976bd69c1ba94df24b5bcd 100644 (file)
@@ -278,8 +278,6 @@ static void at91wdt_shutdown(struct platform_device *pdev)
        at91_wdt_stop();
 }
 
-#ifdef CONFIG_PM
-
 static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
 {
        at91_wdt_stop();
@@ -293,11 +291,6 @@ static int at91wdt_resume(struct platform_device *pdev)
        return 0;
 }
 
-#else
-#define at91wdt_suspend NULL
-#define at91wdt_resume NULL
-#endif
-
 static const struct of_device_id at91_wdt_dt_ids[] = {
        { .compatible = "atmel,at91rm9200-wdt" },
        { /* sentinel */ }
@@ -308,8 +301,8 @@ static struct platform_driver at91wdt_driver = {
        .probe          = at91wdt_probe,
        .remove         = at91wdt_remove,
        .shutdown       = at91wdt_shutdown,
-       .suspend        = at91wdt_suspend,
-       .resume         = at91wdt_resume,
+       .suspend        = pm_ptr(at91wdt_suspend),
+       .resume         = pm_ptr(at91wdt_resume),
        .driver         = {
                .name   = "atmel_st_watchdog",
                .of_match_table = at91_wdt_dt_ids,
index 6ed8b63d310d12ead0fa9ef91b75fe983e6093b8..97148ac0aa54a861f8a39a210f70afc0c1ce37fd 100644 (file)
@@ -105,7 +105,6 @@ static int db8500_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
 static int db8500_wdt_suspend(struct platform_device *pdev,
                             pm_message_t state)
 {
@@ -130,15 +129,11 @@ static int db8500_wdt_resume(struct platform_device *pdev)
        }
        return 0;
 }
-#else
-#define db8500_wdt_suspend NULL
-#define db8500_wdt_resume NULL
-#endif
 
 static struct platform_driver db8500_wdt_driver = {
        .probe          = db8500_wdt_probe,
-       .suspend        = db8500_wdt_suspend,
-       .resume         = db8500_wdt_resume,
+       .suspend        = pm_ptr(db8500_wdt_suspend),
+       .resume         = pm_ptr(db8500_wdt_resume),
        .driver         = {
                .name   = "db8500_wdt",
        },
index 34693f11385f6c64178b548ef580d12f74b76dca..e937b4dd28be7542564b4e602053652bd81ed70a 100644 (file)
@@ -423,14 +423,18 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
        return time_left;
 }
 
-static void iTCO_wdt_set_running(struct iTCO_wdt_private *p)
+/* Returns true if the watchdog was running */
+static bool iTCO_wdt_set_running(struct iTCO_wdt_private *p)
 {
        u16 val;
 
-       /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled */
+       /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled */
        val = inw(TCO1_CNT(p));
-       if (!(val & BIT(11)))
+       if (!(val & BIT(11))) {
                set_bit(WDOG_HW_RUNNING, &p->wddev.status);
+               return true;
+       }
+       return false;
 }
 
 /*
@@ -518,9 +522,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
                return -ENODEV; /* Cannot reset NO_REBOOT bit */
        }
 
-       /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-       p->update_no_reboot_bit(p->no_reboot_priv, true);
-
        if (turn_SMI_watchdog_clear_off >= p->iTCO_version) {
                /*
                 * Bit 13: TCO_EN -> 0
@@ -572,7 +573,13 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        watchdog_set_drvdata(&p->wddev, p);
        platform_set_drvdata(pdev, p);
 
-       iTCO_wdt_set_running(p);
+       if (!iTCO_wdt_set_running(p)) {
+               /*
+                * If the watchdog was not running set NO_REBOOT now to
+                * prevent later reboots.
+                */
+               p->update_no_reboot_bit(p->no_reboot_priv, true);
+       }
 
        /* Check that the heartbeat value is within it's range;
           if not reset to the default */
index 40bd518ed87387a2f28b2d3e2ab3fd8002565df7..e6c7a2906680436912d809619600fc2a9919efa6 100644 (file)
@@ -75,9 +75,7 @@ struct kempld_wdt_data {
        struct watchdog_device          wdd;
        unsigned int                    pretimeout;
        struct kempld_wdt_stage         stage[KEMPLD_WDT_MAX_STAGES];
-#ifdef CONFIG_PM
        u8                              pm_status_store;
-#endif
 };
 
 #define DEFAULT_TIMEOUT                30 /* seconds */
@@ -495,7 +493,6 @@ static int kempld_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
 /* Disable watchdog if it is active during suspend */
 static int kempld_wdt_suspend(struct platform_device *pdev,
                                pm_message_t message)
@@ -531,18 +528,14 @@ static int kempld_wdt_resume(struct platform_device *pdev)
        else
                return kempld_wdt_stop(wdd);
 }
-#else
-#define kempld_wdt_suspend     NULL
-#define kempld_wdt_resume      NULL
-#endif
 
 static struct platform_driver kempld_wdt_driver = {
        .driver         = {
                .name   = "kempld-wdt",
        },
        .probe          = kempld_wdt_probe,
-       .suspend        = kempld_wdt_suspend,
-       .resume         = kempld_wdt_resume,
+       .suspend        = pm_ptr(kempld_wdt_suspend),
+       .resume         = pm_ptr(kempld_wdt_resume),
 };
 
 module_platform_driver(kempld_wdt_driver);
index e977875367926e6168391eec44050b208cf71f1a..3e6212591e697b8e7f4f5c88a6b7395ec2701d95 100644 (file)
  */
 
 #include <dt-bindings/reset/mt2712-resets.h>
+#include <dt-bindings/reset/mediatek,mt6795-resets.h>
 #include <dt-bindings/reset/mt7986-resets.h>
 #include <dt-bindings/reset/mt8183-resets.h>
 #include <dt-bindings/reset/mt8186-resets.h>
+#include <dt-bindings/reset/mt8188-resets.h>
 #include <dt-bindings/reset/mt8192-resets.h>
 #include <dt-bindings/reset/mt8195-resets.h>
 #include <linux/delay.h>
@@ -78,6 +80,10 @@ static const struct mtk_wdt_data mt2712_data = {
        .toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM,
 };
 
+static const struct mtk_wdt_data mt6795_data = {
+       .toprgu_sw_rst_num = MT6795_TOPRGU_SW_RST_NUM,
+};
+
 static const struct mtk_wdt_data mt7986_data = {
        .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
 };
@@ -90,6 +96,10 @@ static const struct mtk_wdt_data mt8186_data = {
        .toprgu_sw_rst_num = MT8186_TOPRGU_SW_RST_NUM,
 };
 
+static const struct mtk_wdt_data mt8188_data = {
+       .toprgu_sw_rst_num = MT8188_TOPRGU_SW_RST_NUM,
+};
+
 static const struct mtk_wdt_data mt8192_data = {
        .toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM,
 };
@@ -426,9 +436,11 @@ static int mtk_wdt_resume(struct device *dev)
 static const struct of_device_id mtk_wdt_dt_ids[] = {
        { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
        { .compatible = "mediatek,mt6589-wdt" },
+       { .compatible = "mediatek,mt6795-wdt", .data = &mt6795_data },
        { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
        { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
        { .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data },
+       { .compatible = "mediatek,mt8188-wdt", .data = &mt8188_data },
        { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },
        { .compatible = "mediatek,mt8195-wdt", .data = &mt8195_data },
        { /* sentinel */ }
index 74d785b2b478f4719c78eae1425f826e7368b526..e75aa86f63cbb437ee15738f495fc69c0fa2cac3 100644 (file)
@@ -316,8 +316,6 @@ static int omap_wdt_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
-
 /* REVISIT ... not clear this is the best way to handle system suspend; and
  * it's very inappropriate for selective device suspend (e.g. suspending this
  * through sysfs rather than by stopping the watchdog daemon).  Also, this
@@ -353,11 +351,6 @@ static int omap_wdt_resume(struct platform_device *pdev)
        return 0;
 }
 
-#else
-#define        omap_wdt_suspend        NULL
-#define        omap_wdt_resume         NULL
-#endif
-
 static const struct of_device_id omap_wdt_of_match[] = {
        { .compatible = "ti,omap3-wdt", },
        {},
@@ -368,8 +361,8 @@ static struct platform_driver omap_wdt_driver = {
        .probe          = omap_wdt_probe,
        .remove         = omap_wdt_remove,
        .shutdown       = omap_wdt_shutdown,
-       .suspend        = omap_wdt_suspend,
-       .resume         = omap_wdt_resume,
+       .suspend        = pm_ptr(omap_wdt_suspend),
+       .resume         = pm_ptr(omap_wdt_resume),
        .driver         = {
                .name   = "omap_wdt",
                .of_match_table = omap_wdt_of_match,
index 6e524c8e26a8f06a39ac0bf18aa2019c03c88fb2..40d8ebd8c0acd505d4c146432c448f3bebd8caaa 100644 (file)
@@ -144,6 +144,8 @@ static int rn5t618_wdt_probe(struct platform_device *pdev)
        struct rn5t618 *rn5t618 = dev_get_drvdata(dev->parent);
        struct rn5t618_wdt *wdt;
        int min_timeout, max_timeout;
+       int ret;
+       unsigned int val;
 
        wdt = devm_kzalloc(dev, sizeof(struct rn5t618_wdt), GFP_KERNEL);
        if (!wdt)
@@ -160,6 +162,16 @@ static int rn5t618_wdt_probe(struct platform_device *pdev)
        wdt->wdt_dev.timeout = max_timeout;
        wdt->wdt_dev.parent = dev;
 
+       /* Read out previous power-off factor */
+       ret = regmap_read(wdt->rn5t618->regmap, RN5T618_POFFHIS, &val);
+       if (ret)
+               return ret;
+
+       if (val & RN5T618_POFFHIS_VINDET)
+               wdt->wdt_dev.bootstatus = WDIOF_POWERUNDER;
+       else if (val & RN5T618_POFFHIS_WDG)
+               wdt->wdt_dev.bootstatus = WDIOF_CARDRESET;
+
        watchdog_set_drvdata(&wdt->wdt_dev, wdt);
        watchdog_init_timeout(&wdt->wdt_dev, timeout, dev);
        watchdog_set_nowayout(&wdt->wdt_dev, nowayout);
index 36b4a660928d3ddee4356f8f079d0d9e2347afbe..09d17e20f4a76aadb4de63b03c9198db09d9785c 100644 (file)
@@ -81,7 +81,6 @@ static int twl4030_wdt_probe(struct platform_device *pdev)
        return devm_watchdog_register_device(dev, wdt);
 }
 
-#ifdef CONFIG_PM
 static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct watchdog_device *wdt = platform_get_drvdata(pdev);
@@ -99,10 +98,6 @@ static int twl4030_wdt_resume(struct platform_device *pdev)
 
        return 0;
 }
-#else
-#define twl4030_wdt_suspend        NULL
-#define twl4030_wdt_resume         NULL
-#endif
 
 static const struct of_device_id twl_wdt_of_match[] = {
        { .compatible = "ti,twl4030-wdt", },
@@ -112,8 +107,8 @@ MODULE_DEVICE_TABLE(of, twl_wdt_of_match);
 
 static struct platform_driver twl4030_wdt_driver = {
        .probe          = twl4030_wdt_probe,
-       .suspend        = twl4030_wdt_suspend,
-       .resume         = twl4030_wdt_resume,
+       .suspend        = pm_ptr(twl4030_wdt_suspend),
+       .resume         = pm_ptr(twl4030_wdt_resume),
        .driver         = {
                .name           = "twl4030_wdt",
                .of_match_table = twl_wdt_of_match,
diff --git a/include/dt-bindings/reset/mt8188-resets.h b/include/dt-bindings/reset/mt8188-resets.h
new file mode 100644 (file)
index 0000000..377cdfd
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)*/
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Runyang Chen <runyang.chen@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8188
+#define _DT_BINDINGS_RESET_CONTROLLER_MT8188
+
+#define MT8188_TOPRGU_CONN_MCU_SW_RST          0
+#define MT8188_TOPRGU_INFRA_GRST_SW_RST        1
+#define MT8188_TOPRGU_IPU0_SW_RST              2
+#define MT8188_TOPRGU_IPU1_SW_RST              3
+#define MT8188_TOPRGU_IPU2_SW_RST              4
+#define MT8188_TOPRGU_AUD_ASRC_SW_RST          5
+#define MT8188_TOPRGU_INFRA_SW_RST             6
+#define MT8188_TOPRGU_MMSYS_SW_RST             7
+#define MT8188_TOPRGU_MFG_SW_RST               8
+#define MT8188_TOPRGU_VENC_SW_RST              9
+#define MT8188_TOPRGU_VDEC_SW_RST              10
+#define MT8188_TOPRGU_CAM_VCORE_SW_RST         11
+#define MT8188_TOPRGU_SCP_SW_RST               12
+#define MT8188_TOPRGU_APMIXEDSYS_SW_RST        13
+#define MT8188_TOPRGU_AUDIO_SW_RST             14
+#define MT8188_TOPRGU_CAMSYS_SW_RST            15
+#define MT8188_TOPRGU_MJC_SW_RST               16
+#define MT8188_TOPRGU_PERI_SW_RST              17
+#define MT8188_TOPRGU_PERI_AO_SW_RST           18
+#define MT8188_TOPRGU_PCIE_SW_RST              19
+#define MT8188_TOPRGU_ADSPSYS_SW_RST           21
+#define MT8188_TOPRGU_DPTX_SW_RST              22
+#define MT8188_TOPRGU_SPMI_MST_SW_RST          23
+
+#define MT8188_TOPRGU_SW_RST_NUM               24
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT8188 */
index 8aa0bda1af4fa2a043bb329db45de06c23c5c20f..aacb6d51e99cba04ce1711751aa1d5ac6385d6f8 100644 (file)
 #define RN5T618_WATCHDOG_WDOGTIM_S     0
 #define RN5T618_PWRIRQ_IR_WDOG         BIT(6)
 
+#define RN5T618_POFFHIS_PWRON          BIT(0)
+#define RN5T618_POFFHIS_TSHUT          BIT(1)
+#define RN5T618_POFFHIS_VINDET         BIT(2)
+#define RN5T618_POFFHIS_IODET          BIT(3)
+#define RN5T618_POFFHIS_CPU            BIT(4)
+#define RN5T618_POFFHIS_WDG            BIT(5)
+#define RN5T618_POFFHIS_DCLIM          BIT(6)
+#define RN5T618_POFFHIS_N_OE           BIT(7)
+
 enum {
        RN5T618_DCDC1,
        RN5T618_DCDC2,