^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) * Copyright 2018-2019 NXP.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/arm-smccc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/firmware/imx/sci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define DEFAULT_TIMEOUT 60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Software timer tick implemented in scfw side, support 10ms to 0xffffffff ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * in theory, but for normal case, 1s~128s is enough, you can change this max
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * value in case it's not enough.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MAX_TIMEOUT 128
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define IMX_SIP_TIMER 0xC2000002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define IMX_SIP_TIMER_START_WDOG 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define IMX_SIP_TIMER_STOP_WDOG 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define IMX_SIP_TIMER_SET_WDOG_ACT 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define IMX_SIP_TIMER_PING_WDOG 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define IMX_SIP_TIMER_SET_TIMEOUT_WDOG 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define IMX_SIP_TIMER_GET_WDOG_STAT 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define IMX_SIP_TIMER_SET_PRETIME_WDOG 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define SC_TIMER_WDOG_ACTION_PARTITION 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define SC_IRQ_WDOG 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define SC_IRQ_GROUP_WDOG 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) module_param(nowayout, bool, 0000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct imx_sc_wdt_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) struct watchdog_device wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) struct notifier_block wdt_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int imx_sc_wdt_ping(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_PING_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) 0, 0, 0, 0, 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int imx_sc_wdt_start(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_START_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) 0, 0, 0, 0, 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (res.a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_WDOG_ACT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) SC_TIMER_WDOG_ACTION_PARTITION,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) 0, 0, 0, 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return res.a0 ? -EACCES : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int imx_sc_wdt_stop(struct watchdog_device *wdog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_STOP_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) 0, 0, 0, 0, 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return res.a0 ? -EACCES : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int imx_sc_wdt_set_timeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) unsigned int timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) wdog->timeout = timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_TIMEOUT_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) timeout * 1000, 0, 0, 0, 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return res.a0 ? -EACCES : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static int imx_sc_wdt_set_pretimeout(struct watchdog_device *wdog,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) unsigned int pretimeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) struct arm_smccc_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * SCU firmware calculates pretimeout based on current time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * stamp instead of watchdog timeout stamp, need to convert
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * the pretimeout to SCU firmware's timeout value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) arm_smccc_smc(IMX_SIP_TIMER, IMX_SIP_TIMER_SET_PRETIME_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) (wdog->timeout - pretimeout) * 1000, 0, 0, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 0, 0, &res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (res.a0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EACCES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) wdog->pretimeout = pretimeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) static int imx_sc_wdt_notify(struct notifier_block *nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned long event, void *group)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct imx_sc_wdt_device *imx_sc_wdd =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) container_of(nb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct imx_sc_wdt_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (event & SC_IRQ_WDOG &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) *(u8 *)group == SC_IRQ_GROUP_WDOG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) watchdog_notify_pretimeout(&imx_sc_wdd->wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) static void imx_sc_wdt_action(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct notifier_block *wdt_notifier = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) imx_scu_irq_unregister_notifier(wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) SC_IRQ_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) static const struct watchdog_ops imx_sc_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .start = imx_sc_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .stop = imx_sc_wdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .ping = imx_sc_wdt_ping,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .set_timeout = imx_sc_wdt_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .set_pretimeout = imx_sc_wdt_set_pretimeout,
^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 struct watchdog_info imx_sc_wdt_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .identity = "i.MX SC watchdog timer",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) WDIOF_MAGICCLOSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) static int imx_sc_wdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) struct imx_sc_wdt_device *imx_sc_wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct watchdog_device *wdog;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) imx_sc_wdd = devm_kzalloc(dev, sizeof(*imx_sc_wdd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!imx_sc_wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) platform_set_drvdata(pdev, imx_sc_wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) wdog = &imx_sc_wdd->wdd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) wdog->info = &imx_sc_wdt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) wdog->ops = &imx_sc_wdt_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) wdog->min_timeout = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) wdog->max_timeout = MAX_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) wdog->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) wdog->timeout = DEFAULT_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) watchdog_init_timeout(wdog, 0, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ret = imx_sc_wdt_set_timeout(wdog, wdog->timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) watchdog_stop_on_reboot(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) watchdog_stop_on_unregister(wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) ret = imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) SC_IRQ_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dev_warn(dev, "Enable irq failed, pretimeout NOT supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) goto register_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) imx_sc_wdd->wdt_notifier.notifier_call = imx_sc_wdt_notify;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) ret = imx_scu_irq_register_notifier(&imx_sc_wdd->wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) imx_scu_irq_group_enable(SC_IRQ_GROUP_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) SC_IRQ_WDOG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) dev_warn(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) "Register irq notifier failed, pretimeout NOT supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) goto register_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) ret = devm_add_action_or_reset(dev, imx_sc_wdt_action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) &imx_sc_wdd->wdt_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) imx_sc_wdt_info.options |= WDIOF_PRETIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) dev_warn(dev, "Add action failed, pretimeout NOT supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) register_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return devm_watchdog_register_device(dev, wdog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static int __maybe_unused imx_sc_wdt_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (watchdog_active(&imx_sc_wdd->wdd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) imx_sc_wdt_stop(&imx_sc_wdd->wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) static int __maybe_unused imx_sc_wdt_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct imx_sc_wdt_device *imx_sc_wdd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (watchdog_active(&imx_sc_wdd->wdd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) imx_sc_wdt_start(&imx_sc_wdd->wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static SIMPLE_DEV_PM_OPS(imx_sc_wdt_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) imx_sc_wdt_suspend, imx_sc_wdt_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) static const struct of_device_id imx_sc_wdt_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) { .compatible = "fsl,imx-sc-wdt", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) MODULE_DEVICE_TABLE(of, imx_sc_wdt_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static struct platform_driver imx_sc_wdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) .probe = imx_sc_wdt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) .name = "imx-sc-wdt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .of_match_table = imx_sc_wdt_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .pm = &imx_sc_wdt_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) module_platform_driver(imx_sc_wdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) MODULE_AUTHOR("Robin Gong <yibin.gong@nxp.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) MODULE_DESCRIPTION("NXP i.MX system controller watchdog driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) MODULE_LICENSE("GPL v2");