From nobody Fri Feb 13 17:30:46 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6D5B4E7D0BC for ; Fri, 22 Sep 2023 01:36:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230153AbjIVBgJ (ORCPT ); Thu, 21 Sep 2023 21:36:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54302 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229497AbjIVBgH (ORCPT ); Thu, 21 Sep 2023 21:36:07 -0400 Received: from thorn.bewilderbeest.net (thorn.bewilderbeest.net [71.19.156.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C6629F1 for ; Thu, 21 Sep 2023 18:35:59 -0700 (PDT) Received: from hatter.bewilderbeest.net (unknown [IPv6:2602:61:7e5d:5300::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: zev) by thorn.bewilderbeest.net (Postfix) with ESMTPSA id 18CBA71B; Thu, 21 Sep 2023 18:35:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bewilderbeest.net; s=thorn; t=1695346556; bh=wBmZ94Tjue/srt7oHjURk9wPTPStY6npfsmnvm1vRrg=; h=From:To:Cc:Subject:Date:From; b=JwK9H8L3pTZzthIZF5yJDbd8CFYusMgoiOavw+cq7rWiRO76WaeE/3XHL83eY6QlA L4RjLv1F83B498BuxajIw/Cq8KYVN88dBBk1yyAXnEKKHcYVfRM3fli/Ayt/iZMlNb vHKXOd1jWrfJwY943xdTeXelZNs9o0AZfyL3eSUQ= From: Zev Weiss To: Wim Van Sebroeck , Guenter Roeck , Joel Stanley , Andrew Jeffery Cc: Zev Weiss , linux-watchdog@vger.kernel.org, linux-aspeed@lists.ozlabs.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, openbmc@lists.ozlabs.org, =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Eddie James , Ivan Mikhaylov Subject: [PATCH] watchdog: aspeed: Add sysfs attributes for reset mask bits Date: Thu, 21 Sep 2023 18:35:43 -0700 Message-ID: <20230922013542.29136-2-zev@bewilderbeest.net> X-Mailer: git-send-email 2.42.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The AST2500 and AST2600 watchdog timers provide the ability to control which devices are reset by the watchdog timer via a reset mask resgister. Previously the driver ignored that register, leaving whatever configuration it found at boot and offering no way of altering its settings. Add a 'reset_ctrl' sysfs subdirectory with a file per bit so that userspace can determine which devices the reset is applied to. Note that not all bits in the hardware register are exposed -- in particular, the ARM CPU and SOC/misc reset bits are left hidden since clearing them can render the system unable to reboot. Signed-off-by: Zev Weiss --- I'm porting OpenBMC to a platform that requires that the LPC controller rem= ain un-reset by a BMC reboot. With this patch userspace can control the reset mask of the Aspeed watchdog timer, with a few bits remaining unexposed so as to prevent some almost-certainly undesirable situations. If there are other bits that people feel shouldn't be exposed (or conversely if someone feels strongly that the "dangerous" bits _should_ be exposed) I can adjust accordingly. Also, I was a little unsure about appropriately-concise names for some of t= he bits, and am not hugely attached to the ones currently in this patch, so suggestions on better alternatives there would also be welcome. I've tested this on ast2500 hardware and a qemu ast2600 model (since I don't have any ast2600 hardware) and it appears to be working as intended, but if anyone can verify on actual ast2600 hardware that would of course be nice to confirm. .../ABI/testing/sysfs-class-watchdog | 10 + drivers/watchdog/aspeed_wdt.c | 290 ++++++++++++++++-- 2 files changed, 272 insertions(+), 28 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-watchdog b/Documentation= /ABI/testing/sysfs-class-watchdog index 94fb74615951..a2f4bb6a4263 100644 --- a/Documentation/ABI/testing/sysfs-class-watchdog +++ b/Documentation/ABI/testing/sysfs-class-watchdog @@ -127,3 +127,13 @@ Description: shown. When written with any non-zero value, it clears the boot code selection and the timeout counter, which results in chipselect reset for AST2400/AST2500. + +What: /sys/class/watchdog/watchdogn/reset_ctrl/* +Date: September 2023 +Contact: Zev Weiss +Description: + The read/write files in this subdirectory (present on Aspeed + AST2500 and AST2600 only) control which devices and SoC + components are reset when the watchdog timer expires. When set + to '1', the device indicated by the name of the file will be + reset; when set to '0' it will not. diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index b72a858bbac7..a05dcf1b5d34 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -26,6 +26,7 @@ struct aspeed_wdt_config { u32 ext_pulse_width_mask; u32 irq_shift; u32 irq_mask; + const struct attribute_group *reset_ctrl_group; }; =20 struct aspeed_wdt { @@ -33,34 +34,10 @@ struct aspeed_wdt { void __iomem *base; u32 ctrl; const struct aspeed_wdt_config *cfg; + const struct attribute_group *groups[3]; /* bswitch_group, reset ctrl, NU= LL terminator */ + spinlock_t lock; }; =20 -static const struct aspeed_wdt_config ast2400_config =3D { - .ext_pulse_width_mask =3D 0xff, - .irq_shift =3D 0, - .irq_mask =3D 0, -}; - -static const struct aspeed_wdt_config ast2500_config =3D { - .ext_pulse_width_mask =3D 0xfffff, - .irq_shift =3D 12, - .irq_mask =3D GENMASK(31, 12), -}; - -static const struct aspeed_wdt_config ast2600_config =3D { - .ext_pulse_width_mask =3D 0xfffff, - .irq_shift =3D 0, - .irq_mask =3D GENMASK(31, 10), -}; - -static const struct of_device_id aspeed_wdt_of_table[] =3D { - { .compatible =3D "aspeed,ast2400-wdt", .data =3D &ast2400_config }, - { .compatible =3D "aspeed,ast2500-wdt", .data =3D &ast2500_config }, - { .compatible =3D "aspeed,ast2600-wdt", .data =3D &ast2600_config }, - { }, -}; -MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); - #define WDT_STATUS 0x00 #define WDT_RELOAD_VALUE 0x04 #define WDT_RESTART 0x08 @@ -79,6 +56,8 @@ MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); #define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1) #define WDT_CLEAR_TIMEOUT_STATUS 0x14 #define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0) +#define WDT_RESET_MASK1 0x1c +#define WDT_RESET_MASK2 0x20 =20 /* * WDT_RESET_WIDTH controls the characteristics of the external pulse (if @@ -263,7 +242,227 @@ static struct attribute *bswitch_attrs[] =3D { &dev_attr_access_cs0.attr, NULL }; -ATTRIBUTE_GROUPS(bswitch); + +static const struct attribute_group bswitch_group =3D { + .attrs =3D bswitch_attrs, +}; + +struct aspeed_wdt_rstctrl_bit { + struct device_attribute dev_attr; + u8 reg, bit; +}; + +static ssize_t aspeed_wdt_reset_ctrl_show(struct device *dev, struct devic= e_attribute *attr, + char *buf) +{ + struct aspeed_wdt *wdt =3D dev_get_drvdata(dev); + struct aspeed_wdt_rstctrl_bit *bit =3D container_of(attr, struct aspeed_w= dt_rstctrl_bit, + dev_attr); + u32 mask =3D readl(wdt->base + bit->reg); + + return sysfs_emit(buf, "%u\n", !!(mask & BIT(bit->bit))); +} + +static ssize_t aspeed_wdt_reset_ctrl_store(struct device *dev, struct devi= ce_attribute *attr, + const char *buf, size_t size) +{ + struct aspeed_wdt *wdt =3D dev_get_drvdata(dev); + struct aspeed_wdt_rstctrl_bit *bit =3D container_of(attr, struct aspeed_w= dt_rstctrl_bit, + dev_attr); + u32 mask; + bool val; + + if (kstrtobool(buf, &val)) + return -EINVAL; + + spin_lock(&wdt->lock); + mask =3D readl(wdt->base + bit->reg); + if (val) + mask |=3D BIT(bit->bit); + else + mask &=3D ~BIT(bit->bit); + writel(mask, wdt->base + bit->reg); + spin_unlock(&wdt->lock); + + return size; +} + +#define ASPEED_WDT_RSTCTRL_BIT(chip, name, regnum, bitnum) \ + static struct aspeed_wdt_rstctrl_bit chip##_##name##_reset_ctrl =3D { \ + .dev_attr =3D __ATTR(name, 0644, aspeed_wdt_reset_ctrl_show, \ + aspeed_wdt_reset_ctrl_store), \ + .reg =3D regnum, \ + .bit =3D bitnum, \ + } + +#define AST2500_WDT_RESET_CTRL(name, bit) \ + ASPEED_WDT_RSTCTRL_BIT(ast2500, name, WDT_RESET_MASK1, bit) + +AST2500_WDT_RESET_CTRL(spi, 24); +AST2500_WDT_RESET_CTRL(xdma, 23); +AST2500_WDT_RESET_CTRL(mctp, 22); +AST2500_WDT_RESET_CTRL(gpio, 21); +AST2500_WDT_RESET_CTRL(adc, 20); +AST2500_WDT_RESET_CTRL(jtag, 19); +AST2500_WDT_RESET_CTRL(peci, 18); +AST2500_WDT_RESET_CTRL(pwm, 17); +AST2500_WDT_RESET_CTRL(crt, 16); +AST2500_WDT_RESET_CTRL(mic, 15); +AST2500_WDT_RESET_CTRL(sdio, 14); +AST2500_WDT_RESET_CTRL(lpc, 13); +AST2500_WDT_RESET_CTRL(hac, 12); +AST2500_WDT_RESET_CTRL(video, 11); +AST2500_WDT_RESET_CTRL(hid_ehci, 10); +AST2500_WDT_RESET_CTRL(usb_host, 9); +AST2500_WDT_RESET_CTRL(usb2_host_hub, 8); +AST2500_WDT_RESET_CTRL(graphics, 7); +AST2500_WDT_RESET_CTRL(mac1, 6); +AST2500_WDT_RESET_CTRL(mac0, 5); +AST2500_WDT_RESET_CTRL(i2c, 4); +AST2500_WDT_RESET_CTRL(ahb, 3); +AST2500_WDT_RESET_CTRL(sdram, 2); +AST2500_WDT_RESET_CTRL(coproc, 1); + +static struct attribute *ast2500_reset_ctrl_attrs[] =3D { + &ast2500_spi_reset_ctrl.dev_attr.attr, + &ast2500_xdma_reset_ctrl.dev_attr.attr, + &ast2500_mctp_reset_ctrl.dev_attr.attr, + &ast2500_gpio_reset_ctrl.dev_attr.attr, + &ast2500_adc_reset_ctrl.dev_attr.attr, + &ast2500_jtag_reset_ctrl.dev_attr.attr, + &ast2500_peci_reset_ctrl.dev_attr.attr, + &ast2500_pwm_reset_ctrl.dev_attr.attr, + &ast2500_crt_reset_ctrl.dev_attr.attr, + &ast2500_mic_reset_ctrl.dev_attr.attr, + &ast2500_sdio_reset_ctrl.dev_attr.attr, + &ast2500_lpc_reset_ctrl.dev_attr.attr, + &ast2500_hac_reset_ctrl.dev_attr.attr, + &ast2500_video_reset_ctrl.dev_attr.attr, + &ast2500_hid_ehci_reset_ctrl.dev_attr.attr, + &ast2500_usb_host_reset_ctrl.dev_attr.attr, + &ast2500_usb2_host_hub_reset_ctrl.dev_attr.attr, + &ast2500_graphics_reset_ctrl.dev_attr.attr, + &ast2500_mac1_reset_ctrl.dev_attr.attr, + &ast2500_mac0_reset_ctrl.dev_attr.attr, + &ast2500_i2c_reset_ctrl.dev_attr.attr, + &ast2500_ahb_reset_ctrl.dev_attr.attr, + &ast2500_sdram_reset_ctrl.dev_attr.attr, + &ast2500_coproc_reset_ctrl.dev_attr.attr, + NULL +}; + +static const struct attribute_group ast2500_reset_ctrl_group =3D { + .name =3D "reset_ctrl", + .attrs =3D ast2500_reset_ctrl_attrs, +}; + +#define AST2600_WDT_RESET_CTRL(name, reg, bit) \ + ASPEED_WDT_RSTCTRL_BIT(ast2600, name, reg, bit) + +AST2600_WDT_RESET_CTRL(rvas, WDT_RESET_MASK1, 25); +AST2600_WDT_RESET_CTRL(gpio0, WDT_RESET_MASK1, 24); +AST2600_WDT_RESET_CTRL(xdma1, WDT_RESET_MASK1, 23); +AST2600_WDT_RESET_CTRL(xdma0, WDT_RESET_MASK1, 22); +AST2600_WDT_RESET_CTRL(mctp1, WDT_RESET_MASK1, 21); +AST2600_WDT_RESET_CTRL(mctp0, WDT_RESET_MASK1, 20); +AST2600_WDT_RESET_CTRL(jtag0, WDT_RESET_MASK1, 19); +AST2600_WDT_RESET_CTRL(sdio0, WDT_RESET_MASK1, 18); +AST2600_WDT_RESET_CTRL(mac1, WDT_RESET_MASK1, 17); +AST2600_WDT_RESET_CTRL(mac0, WDT_RESET_MASK1, 16); +AST2600_WDT_RESET_CTRL(gp_mcu, WDT_RESET_MASK1, 15); +AST2600_WDT_RESET_CTRL(dp_mcu, WDT_RESET_MASK1, 14); +AST2600_WDT_RESET_CTRL(dp, WDT_RESET_MASK1, 13); +AST2600_WDT_RESET_CTRL(hac, WDT_RESET_MASK1, 12); +AST2600_WDT_RESET_CTRL(video, WDT_RESET_MASK1, 11); +AST2600_WDT_RESET_CTRL(crt, WDT_RESET_MASK1, 10); +AST2600_WDT_RESET_CTRL(graphics, WDT_RESET_MASK1, 9); +AST2600_WDT_RESET_CTRL(uhci, WDT_RESET_MASK1, 8); +AST2600_WDT_RESET_CTRL(usb_b, WDT_RESET_MASK1, 7); +AST2600_WDT_RESET_CTRL(usb_a, WDT_RESET_MASK1, 6); +AST2600_WDT_RESET_CTRL(coproc, WDT_RESET_MASK1, 5); +AST2600_WDT_RESET_CTRL(sli, WDT_RESET_MASK1, 3); +AST2600_WDT_RESET_CTRL(ahb, WDT_RESET_MASK1, 2); +AST2600_WDT_RESET_CTRL(sdram, WDT_RESET_MASK1, 1); + +AST2600_WDT_RESET_CTRL(espi, WDT_RESET_MASK2, 26); +AST2600_WDT_RESET_CTRL(i3c5, WDT_RESET_MASK2, 23); +AST2600_WDT_RESET_CTRL(i3c4, WDT_RESET_MASK2, 22); +AST2600_WDT_RESET_CTRL(i3c3, WDT_RESET_MASK2, 21); +AST2600_WDT_RESET_CTRL(i3c2, WDT_RESET_MASK2, 20); +AST2600_WDT_RESET_CTRL(i3c1, WDT_RESET_MASK2, 19); +AST2600_WDT_RESET_CTRL(i3c0, WDT_RESET_MASK2, 18); +AST2600_WDT_RESET_CTRL(i3c_global, WDT_RESET_MASK2, 17); +AST2600_WDT_RESET_CTRL(i2c, WDT_RESET_MASK2, 16); +AST2600_WDT_RESET_CTRL(fsi, WDT_RESET_MASK2, 15); +AST2600_WDT_RESET_CTRL(adc, WDT_RESET_MASK2, 14); +AST2600_WDT_RESET_CTRL(pwm, WDT_RESET_MASK2, 13); +AST2600_WDT_RESET_CTRL(peci, WDT_RESET_MASK2, 12); +AST2600_WDT_RESET_CTRL(lpc, WDT_RESET_MASK2, 11); +AST2600_WDT_RESET_CTRL(mdio, WDT_RESET_MASK2, 10); +AST2600_WDT_RESET_CTRL(gpio1, WDT_RESET_MASK2, 9); +AST2600_WDT_RESET_CTRL(jtag1, WDT_RESET_MASK2, 8); +AST2600_WDT_RESET_CTRL(sdio1, WDT_RESET_MASK2, 7); +AST2600_WDT_RESET_CTRL(mac3, WDT_RESET_MASK2, 6); +AST2600_WDT_RESET_CTRL(mac2, WDT_RESET_MASK2, 5); +AST2600_WDT_RESET_CTRL(sli2, WDT_RESET_MASK2, 3); +AST2600_WDT_RESET_CTRL(ahb2, WDT_RESET_MASK2, 2); +AST2600_WDT_RESET_CTRL(spi, WDT_RESET_MASK2, 1); + +static struct attribute *ast2600_reset_ctrl_attrs[] =3D { + &ast2600_rvas_reset_ctrl.dev_attr.attr, + &ast2600_gpio0_reset_ctrl.dev_attr.attr, + &ast2600_xdma1_reset_ctrl.dev_attr.attr, + &ast2600_xdma0_reset_ctrl.dev_attr.attr, + &ast2600_mctp1_reset_ctrl.dev_attr.attr, + &ast2600_mctp0_reset_ctrl.dev_attr.attr, + &ast2600_jtag0_reset_ctrl.dev_attr.attr, + &ast2600_sdio0_reset_ctrl.dev_attr.attr, + &ast2600_mac1_reset_ctrl.dev_attr.attr, + &ast2600_mac0_reset_ctrl.dev_attr.attr, + &ast2600_gp_mcu_reset_ctrl.dev_attr.attr, + &ast2600_dp_mcu_reset_ctrl.dev_attr.attr, + &ast2600_dp_reset_ctrl.dev_attr.attr, + &ast2600_hac_reset_ctrl.dev_attr.attr, + &ast2600_video_reset_ctrl.dev_attr.attr, + &ast2600_crt_reset_ctrl.dev_attr.attr, + &ast2600_graphics_reset_ctrl.dev_attr.attr, + &ast2600_uhci_reset_ctrl.dev_attr.attr, + &ast2600_usb_b_reset_ctrl.dev_attr.attr, + &ast2600_usb_a_reset_ctrl.dev_attr.attr, + &ast2600_coproc_reset_ctrl.dev_attr.attr, + &ast2600_sli_reset_ctrl.dev_attr.attr, + &ast2600_ahb_reset_ctrl.dev_attr.attr, + &ast2600_sdram_reset_ctrl.dev_attr.attr, + &ast2600_espi_reset_ctrl.dev_attr.attr, + &ast2600_i3c5_reset_ctrl.dev_attr.attr, + &ast2600_i3c4_reset_ctrl.dev_attr.attr, + &ast2600_i3c3_reset_ctrl.dev_attr.attr, + &ast2600_i3c2_reset_ctrl.dev_attr.attr, + &ast2600_i3c1_reset_ctrl.dev_attr.attr, + &ast2600_i3c0_reset_ctrl.dev_attr.attr, + &ast2600_i3c_global_reset_ctrl.dev_attr.attr, + &ast2600_i2c_reset_ctrl.dev_attr.attr, + &ast2600_fsi_reset_ctrl.dev_attr.attr, + &ast2600_adc_reset_ctrl.dev_attr.attr, + &ast2600_pwm_reset_ctrl.dev_attr.attr, + &ast2600_peci_reset_ctrl.dev_attr.attr, + &ast2600_lpc_reset_ctrl.dev_attr.attr, + &ast2600_mdio_reset_ctrl.dev_attr.attr, + &ast2600_gpio1_reset_ctrl.dev_attr.attr, + &ast2600_jtag1_reset_ctrl.dev_attr.attr, + &ast2600_sdio1_reset_ctrl.dev_attr.attr, + &ast2600_mac3_reset_ctrl.dev_attr.attr, + &ast2600_mac2_reset_ctrl.dev_attr.attr, + &ast2600_sli2_reset_ctrl.dev_attr.attr, + &ast2600_ahb2_reset_ctrl.dev_attr.attr, + &ast2600_spi_reset_ctrl.dev_attr.attr, + NULL +}; + +static const struct attribute_group ast2600_reset_ctrl_group =3D { + .name =3D "reset_ctrl", + .attrs =3D ast2600_reset_ctrl_attrs, +}; =20 static const struct watchdog_ops aspeed_wdt_ops =3D { .start =3D aspeed_wdt_start, @@ -302,6 +501,34 @@ static irqreturn_t aspeed_wdt_irq(int irq, void *arg) return IRQ_HANDLED; } =20 +static const struct aspeed_wdt_config ast2400_config =3D { + .ext_pulse_width_mask =3D 0xff, + .irq_shift =3D 0, + .irq_mask =3D 0, +}; + +static const struct aspeed_wdt_config ast2500_config =3D { + .ext_pulse_width_mask =3D 0xfffff, + .irq_shift =3D 12, + .irq_mask =3D GENMASK(31, 12), + .reset_ctrl_group =3D &ast2500_reset_ctrl_group, +}; + +static const struct aspeed_wdt_config ast2600_config =3D { + .ext_pulse_width_mask =3D 0xfffff, + .irq_shift =3D 0, + .irq_mask =3D GENMASK(31, 10), + .reset_ctrl_group =3D &ast2600_reset_ctrl_group, +}; + +static const struct of_device_id aspeed_wdt_of_table[] =3D { + { .compatible =3D "aspeed,ast2400-wdt", .data =3D &ast2400_config }, + { .compatible =3D "aspeed,ast2500-wdt", .data =3D &ast2500_config }, + { .compatible =3D "aspeed,ast2600-wdt", .data =3D &ast2600_config }, + { }, +}; +MODULE_DEVICE_TABLE(of, aspeed_wdt_of_table); + static int aspeed_wdt_probe(struct platform_device *pdev) { struct device *dev =3D &pdev->dev; @@ -312,6 +539,7 @@ static int aspeed_wdt_probe(struct platform_device *pde= v) u32 duration; u32 status; int ret; + int ngroups =3D 0; =20 wdt =3D devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); if (!wdt) @@ -328,6 +556,8 @@ static int aspeed_wdt_probe(struct platform_device *pde= v) if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); =20 + spin_lock_init(&wdt->lock); + wdt->wdd.info =3D &aspeed_wdt_info; =20 if (wdt->cfg->irq_mask) { @@ -347,6 +577,7 @@ static int aspeed_wdt_probe(struct platform_device *pde= v) wdt->wdd.ops =3D &aspeed_wdt_ops; wdt->wdd.max_hw_heartbeat_ms =3D WDT_MAX_TIMEOUT_MS; wdt->wdd.parent =3D dev; + wdt->wdd.groups =3D wdt->groups; =20 wdt->wdd.timeout =3D WDT_DEFAULT_TIMEOUT; watchdog_init_timeout(&wdt->wdd, 0, dev); @@ -453,9 +684,12 @@ static int aspeed_wdt_probe(struct platform_device *pd= ev) =20 if (of_device_is_compatible(np, "aspeed,ast2400-wdt") || of_device_is_compatible(np, "aspeed,ast2500-wdt")) - wdt->wdd.groups =3D bswitch_groups; + wdt->groups[ngroups++] =3D &bswitch_group; } =20 + if (wdt->cfg->reset_ctrl_group) + wdt->groups[ngroups++] =3D wdt->cfg->reset_ctrl_group; + dev_set_drvdata(dev, wdt); =20 return devm_watchdog_register_device(dev, &wdt->wdd); --=20 2.42.0