^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Watchdog driver for IMX2 and later processors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <kernel@pengutronix.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2014 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * some parts adapted by similar drivers from Darius Augulis and Vladimir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Zapolskiy, additional improvements by Wim Van Sebroeck.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * NOTE: MX1 has a slightly different Watchdog than MX2 and later:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * MX1: MX2+:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * ---- -----
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Registers: 32-bit 16-bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Stopable timer: Yes No
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Need to enable clk: No Yes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Halt on suspend: Manual Can be automatic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define DRIVER_NAME "imx2-wdt"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define IMX2_WDT_WCR 0x00 /* Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define IMX2_WDT_WCR_WDE BIT(2) /* -> Watchdog Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define IMX2_WDT_WCR_WDZST BIT(0) /* -> Watchdog timer Suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define IMX2_WDT_WSR 0x02 /* Service Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define IMX2_WDT_SEQ2 0xAAAA /* -> service sequence 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define IMX2_WDT_WRSR 0x04 /* Reset Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define IMX2_WDT_WRSR_TOUT BIT(1) /* -> Reset due to Timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define IMX2_WDT_WICR 0x06 /* Interrupt Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define IMX2_WDT_WICR_WIE BIT(15) /* -> Interrupt Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define IMX2_WDT_WICR_WTIS BIT(14) /* -> Interrupt Status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define IMX2_WDT_WICR_WICT 0xFF /* -> Interrupt Count Timeout */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define IMX2_WDT_WMCR 0x08 /* Misc Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define IMX2_WDT_MAX_TIME 128U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define IMX2_WDT_DEFAULT_TIME 60 /* in seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct imx2_wdt_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct regmap *regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct watchdog_device wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) bool ext_reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) module_param(nowayout, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static unsigned timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) module_param(timeout, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) __MODULE_STRING(IMX2_WDT_DEFAULT_TIME) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static const struct watchdog_info imx2_wdt_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .identity = "imx2+ watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static const struct watchdog_info imx2_wdt_pretimeout_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .identity = "imx2+ watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) WDIOF_PRETIMEOUT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int imx2_wdt_restart(struct watchdog_device *wdog, unsigned long action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) unsigned int wcr_enable = IMX2_WDT_WCR_WDE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* Use internal reset or external - not both */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (wdev->ext_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) wcr_enable |= IMX2_WDT_WCR_SRS; /* do not assert int reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) wcr_enable |= IMX2_WDT_WCR_WDA; /* do not assert ext-reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Assert SRS signal */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * written twice), we add another two writes to ensure there must be at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * least two writes happen in the same one 32kHz clock period. We save
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * the target check here, since the writes shouldn't be a huge burden
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * for other platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) /* wait for reset to assert... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) mdelay(500);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static inline void imx2_wdt_setup(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /* Suspend timer in low power mode, write once-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) val |= IMX2_WDT_WCR_WDZST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /* Strip the old watchdog Time-Out value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) val &= ~IMX2_WDT_WCR_WT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) /* Generate internal chip-level reset if WDOG times out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (!wdev->ext_reset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) val &= ~IMX2_WDT_WCR_WRE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* Or if external-reset assert WDOG_B reset only on time-out */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) val |= IMX2_WDT_WCR_WRE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) /* Keep Watchdog Disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) val &= ~IMX2_WDT_WCR_WDE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) /* Set the watchdog's Time-Out value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) val |= WDOG_SEC_TO_COUNT(wdog->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /* enable the watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) val |= IMX2_WDT_WCR_WDE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return val & IMX2_WDT_WCR_WDE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int imx2_wdt_ping(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static void __imx2_wdt_set_timeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) unsigned int new_timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) WDOG_SEC_TO_COUNT(new_timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned int new_timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned int actual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) actual = min(new_timeout, IMX2_WDT_MAX_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) __imx2_wdt_set_timeout(wdog, actual);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) wdog->timeout = new_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static int imx2_wdt_set_pretimeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) unsigned int new_pretimeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) if (new_pretimeout >= IMX2_WDT_MAX_TIME)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) wdog->pretimeout = new_pretimeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) regmap_update_bits(wdev->regmap, IMX2_WDT_WICR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) IMX2_WDT_WICR_WIE | IMX2_WDT_WICR_WICT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) IMX2_WDT_WICR_WIE | (new_pretimeout << 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static irqreturn_t imx2_wdt_isr(int irq, void *wdog_arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) struct watchdog_device *wdog = wdog_arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) regmap_write_bits(wdev->regmap, IMX2_WDT_WICR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) IMX2_WDT_WICR_WTIS, IMX2_WDT_WICR_WTIS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) watchdog_notify_pretimeout(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static int imx2_wdt_start(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (imx2_wdt_is_running(wdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) imx2_wdt_set_timeout(wdog, wdog->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) imx2_wdt_setup(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) set_bit(WDOG_HW_RUNNING, &wdog->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return imx2_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) static const struct watchdog_ops imx2_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) .start = imx2_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .ping = imx2_wdt_ping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) .set_timeout = imx2_wdt_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) .set_pretimeout = imx2_wdt_set_pretimeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .restart = imx2_wdt_restart,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static const struct regmap_config imx2_wdt_regmap_config = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .reg_bits = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .reg_stride = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .val_bits = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .max_register = 0x8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void imx2_wdt_action(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) clk_disable_unprepare(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) static int __init imx2_wdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct imx2_wdt_device *wdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct watchdog_device *wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) wdev = devm_kzalloc(dev, sizeof(*wdev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (IS_ERR(base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return PTR_ERR(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) wdev->regmap = devm_regmap_init_mmio_clk(dev, NULL, base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) &imx2_wdt_regmap_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (IS_ERR(wdev->regmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) dev_err(dev, "regmap init failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return PTR_ERR(wdev->regmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) wdev->clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (IS_ERR(wdev->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) dev_err(dev, "can't get Watchdog clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return PTR_ERR(wdev->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) wdog = &wdev->wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) wdog->info = &imx2_wdt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) wdog->ops = &imx2_wdt_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) wdog->min_timeout = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) wdog->timeout = IMX2_WDT_DEFAULT_TIME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) wdog->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) ret = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (ret > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (!devm_request_irq(dev, ret, imx2_wdt_isr, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) dev_name(dev), wdog))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) wdog->info = &imx2_wdt_pretimeout_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) ret = clk_prepare_enable(wdev->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) ret = devm_add_action_or_reset(dev, imx2_wdt_action, wdev->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) wdev->ext_reset = of_property_read_bool(dev->of_node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) "fsl,ext-reset-output");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) platform_set_drvdata(pdev, wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) watchdog_set_drvdata(wdog, wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) watchdog_set_nowayout(wdog, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) watchdog_set_restart_priority(wdog, 128);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) watchdog_init_timeout(wdog, timeout, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (imx2_wdt_is_running(wdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) imx2_wdt_set_timeout(wdog, wdog->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) set_bit(WDOG_HW_RUNNING, &wdog->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) * Disable the watchdog power down counter at boot. Otherwise the power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) * down counter will pull down the #WDOG interrupt line for one clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) * cycle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return devm_watchdog_register_device(dev, wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) static void imx2_wdt_shutdown(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) struct watchdog_device *wdog = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (imx2_wdt_is_running(wdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) * We are running, configure max timeout before reboot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * will take place.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) imx2_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) /* Disable watchdog if it is active or non-active but still running */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int __maybe_unused imx2_wdt_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) struct watchdog_device *wdog = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) /* The watchdog IP block is running */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (imx2_wdt_is_running(wdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * Don't update wdog->timeout, we'll restore the current value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * during resume.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) __imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) imx2_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) clk_disable_unprepare(wdev->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /* Enable watchdog and configure it if necessary */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) static int __maybe_unused imx2_wdt_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct watchdog_device *wdog = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ret = clk_prepare_enable(wdev->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * If the watchdog is still active and resumes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) * from deep sleep state, need to restart the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * watchdog again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) imx2_wdt_setup(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (imx2_wdt_is_running(wdev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) imx2_wdt_set_timeout(wdog, wdog->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) imx2_wdt_ping(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) imx2_wdt_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static const struct of_device_id imx2_wdt_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) { .compatible = "fsl,imx21-wdt", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) static struct platform_driver imx2_wdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) .shutdown = imx2_wdt_shutdown,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) .name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) .pm = &imx2_wdt_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) .of_match_table = imx2_wdt_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) module_platform_driver_probe(imx2_wdt_driver, imx2_wdt_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) MODULE_AUTHOR("Wolfram Sang");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) MODULE_DESCRIPTION("Watchdog driver for IMX2 and later");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) MODULE_ALIAS("platform:" DRIVER_NAME);