^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 Renesas WDT watchdog
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015-17 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2015-17 Renesas Electronics Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/sys_soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define RWTCNT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define RWTCSRA 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define RWTCSRA_WOVF BIT(4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define RWTCSRA_WRFLG BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define RWTCSRA_TME BIT(7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define RWTCSRB 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define RWDT_DEFAULT_TIMEOUT 60U
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * In probe, clk_rate is checked to be not more than 16 bit * biggest clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * divider (12 bits). d is only a factor to fully utilize the WDT counter and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * will not exceed its 16 bits. Thus, no overflow, we stay below 32 bits.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MUL_BY_CLKS_PER_SEC(p, d) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) DIV_ROUND_UP((d) * (p)->clk_rate, clk_divs[(p)->cks])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* d is 16 bit, clk_divs 12 bit -> no 32 bit overflow */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define DIV_BY_CLKS_PER_SEC(p, d) ((d) * clk_divs[(p)->cks] / (p)->clk_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const unsigned int clk_divs[] = { 1, 4, 16, 32, 64, 128, 1024, 4096 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) module_param(nowayout, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct rwdt_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct watchdog_device wdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) unsigned long clk_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) u8 cks;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void rwdt_write(struct rwdt_priv *priv, u32 val, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (reg == RWTCNT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) val |= 0x5a5a0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) val |= 0xa5a5a500;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) writel_relaxed(val, priv->base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int rwdt_init_timeout(struct watchdog_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) rwdt_write(priv, 65536 - MUL_BY_CLKS_PER_SEC(priv, wdev->timeout), RWTCNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) static void rwdt_wait_cycles(struct rwdt_priv *priv, unsigned int cycles)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned int delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) delay = DIV_ROUND_UP(cycles * 1000000, priv->clk_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) usleep_range(delay, 2 * delay);
^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 rwdt_start(struct watchdog_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) u8 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) pm_runtime_get_sync(wdev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* Stop the timer before we modify any register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) val = readb_relaxed(priv->base + RWTCSRA) & ~RWTCSRA_TME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) rwdt_write(priv, val, RWTCSRA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /* Delay 2 cycles before setting watchdog counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) rwdt_wait_cycles(priv, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) rwdt_init_timeout(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) rwdt_write(priv, priv->cks, RWTCSRA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) rwdt_write(priv, 0, RWTCSRB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) rwdt_write(priv, priv->cks | RWTCSRA_TME, RWTCSRA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int rwdt_stop(struct watchdog_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) rwdt_write(priv, priv->cks, RWTCSRA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Delay 3 cycles before disabling module clock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) rwdt_wait_cycles(priv, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) pm_runtime_put(wdev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static unsigned int rwdt_get_timeleft(struct watchdog_device *wdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) u16 val = readw_relaxed(priv->base + RWTCNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return DIV_BY_CLKS_PER_SEC(priv, 65536 - val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static int rwdt_restart(struct watchdog_device *wdev, unsigned long action,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct rwdt_priv *priv = watchdog_get_drvdata(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) rwdt_start(wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) rwdt_write(priv, 0xffff, RWTCNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static const struct watchdog_info rwdt_ident = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) WDIOF_CARDRESET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .identity = "Renesas WDT Watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static const struct watchdog_ops rwdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .start = rwdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .stop = rwdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .ping = rwdt_init_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .get_timeleft = rwdt_get_timeleft,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .restart = rwdt_restart,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #if defined(CONFIG_ARCH_RCAR_GEN2) && defined(CONFIG_SMP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * Watchdog-reset integration is broken on early revisions of R-Car Gen2 SoCs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static const struct soc_device_attribute rwdt_quirks_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .soc_id = "r8a7790",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .revision = "ES1.*",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .data = (void *)1, /* needs single CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .soc_id = "r8a7791",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .revision = "ES1.*",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .data = (void *)1, /* needs single CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .soc_id = "r8a7792",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .data = (void *)0, /* needs SMP disabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static bool rwdt_blacklisted(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) const struct soc_device_attribute *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) attr = soc_device_match(rwdt_quirks_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (attr && setup_max_cpus > (uintptr_t)attr->data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) dev_info(dev, "Watchdog blacklisted on %s %s\n", attr->soc_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) attr->revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #else /* !CONFIG_ARCH_RCAR_GEN2 || !CONFIG_SMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static inline bool rwdt_blacklisted(struct device *dev) { return false; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) #endif /* !CONFIG_ARCH_RCAR_GEN2 || !CONFIG_SMP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) static int rwdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct rwdt_priv *priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) unsigned long clks_per_sec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u8 csra;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (rwdt_blacklisted(dev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (!priv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) priv->base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (IS_ERR(priv->base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return PTR_ERR(priv->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (IS_ERR(clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return PTR_ERR(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) pm_runtime_enable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) pm_runtime_get_sync(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) priv->clk_rate = clk_get_rate(clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) csra = readb_relaxed(priv->base + RWTCSRA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) priv->wdev.bootstatus = csra & RWTCSRA_WOVF ? WDIOF_CARDRESET : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) pm_runtime_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (!priv->clk_rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto out_pm_disable;
^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) for (i = ARRAY_SIZE(clk_divs) - 1; i >= 0; i--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) clks_per_sec = priv->clk_rate / clk_divs[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (clks_per_sec && clks_per_sec < 65536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) priv->cks = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (i < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dev_err(dev, "Can't find suitable clock divider\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ret = -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) goto out_pm_disable;
^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) priv->wdev.info = &rwdt_ident;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) priv->wdev.ops = &rwdt_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) priv->wdev.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) priv->wdev.min_timeout = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) priv->wdev.timeout = min(priv->wdev.max_timeout, RWDT_DEFAULT_TIMEOUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) platform_set_drvdata(pdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) watchdog_set_drvdata(&priv->wdev, priv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) watchdog_set_nowayout(&priv->wdev, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) watchdog_set_restart_priority(&priv->wdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) watchdog_stop_on_unregister(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) /* This overrides the default timeout only if DT configuration was found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) watchdog_init_timeout(&priv->wdev, 0, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /* Check if FW enabled the watchdog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (csra & RWTCSRA_TME) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* Ensure properly initialized dividers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) rwdt_start(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) ret = watchdog_register_device(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) goto out_pm_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) out_pm_disable:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) pm_runtime_disable(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static int rwdt_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) struct rwdt_priv *priv = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) watchdog_unregister_device(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) pm_runtime_disable(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static int __maybe_unused rwdt_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) struct rwdt_priv *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (watchdog_active(&priv->wdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) rwdt_stop(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int __maybe_unused rwdt_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct rwdt_priv *priv = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (watchdog_active(&priv->wdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) rwdt_start(&priv->wdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static SIMPLE_DEV_PM_OPS(rwdt_pm_ops, rwdt_suspend, rwdt_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static const struct of_device_id rwdt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) { .compatible = "renesas,rcar-gen2-wdt", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) { .compatible = "renesas,rcar-gen3-wdt", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) MODULE_DEVICE_TABLE(of, rwdt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static struct platform_driver rwdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .name = "renesas_wdt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .of_match_table = rwdt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .pm = &rwdt_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) .probe = rwdt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) .remove = rwdt_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) module_platform_driver(rwdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) MODULE_DESCRIPTION("Renesas WDT Watchdog Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");