^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) * drivers/char/watchdog/pnx4008_wdt.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Watchdog driver for PNX4008 board
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Authors: Dmitry Chigirev <source@mvista.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Vitaly Wool <vitalywool@gmail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Based on sa1100 driver,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * 2005-2006 (c) MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * (C) 2012 Wolfram Sang, Pengutronix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* WatchDog Timer - Chapter 23 Page 207 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define DEFAULT_HEARTBEAT 19
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MAX_HEARTBEAT 60
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Watchdog timer register set definition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define WDTIM_INT(p) ((p) + 0x0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define WDTIM_CTRL(p) ((p) + 0x4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define WDTIM_COUNTER(p) ((p) + 0x8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define WDTIM_MCTRL(p) ((p) + 0xC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define WDTIM_MATCH0(p) ((p) + 0x10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define WDTIM_EMR(p) ((p) + 0x14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define WDTIM_PULSE(p) ((p) + 0x18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define WDTIM_RES(p) ((p) + 0x1C)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* WDTIM_INT bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define MATCH_INT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* WDTIM_CTRL bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define COUNT_ENAB 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define RESET_COUNT (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define DEBUG_EN (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /* WDTIM_MCTRL bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define MR0_INT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #undef RESET_COUNT0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define RESET_COUNT0 (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define STOP_COUNT0 (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define M_RES1 (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define M_RES2 (1 << 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define RESFRC1 (1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define RESFRC2 (1 << 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) /* WDTIM_EMR bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define EXT_MATCH0 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define MATCH_OUTPUT_HIGH (2 << 4) /*a MATCH_CTRL setting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) /* WDTIM_RES bit definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define WDOG_RESET 1 /* read only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static bool nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static unsigned int heartbeat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static DEFINE_SPINLOCK(io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void __iomem *wdt_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static struct clk *wdt_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int pnx4008_wdt_start(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) spin_lock(&io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* stop counter, initiate counter reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /*wait for reset to complete. 100% guarantee event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) while (readl(WDTIM_COUNTER(wdt_base)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) cpu_relax();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* internal and external reset, stop after that */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0, WDTIM_MCTRL(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* configure match output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /* clear interrupt, just in case */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) writel(MATCH_INT, WDTIM_INT(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) writel(0xFFFF, WDTIM_PULSE(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) writel(wdd->timeout * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /*enable counter, stop when debugger active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) spin_unlock(&io_lock);
^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 pnx4008_wdt_stop(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) spin_lock(&io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) spin_unlock(&io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static int pnx4008_wdt_set_timeout(struct watchdog_device *wdd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) unsigned int new_timeout)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) wdd->timeout = new_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int pnx4008_restart_handler(struct watchdog_device *wdd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned long mode, void *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) const char *boot_cmd = cmd;
^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) * Verify if a "cmd" passed from the userspace program rebooting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * the system; if available, handle it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * - For details, see the 'reboot' syscall in kernel/reboot.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * - If the received "cmd" is not supported, use the default mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (boot_cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (boot_cmd[0] == 'h')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) mode = REBOOT_HARD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) else if (boot_cmd[0] == 's')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) mode = REBOOT_SOFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (mode == REBOOT_SOFT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* Force match output active */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) writel(EXT_MATCH0, WDTIM_EMR(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* Internal reset on match output (RESOUT_N not asserted) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) writel(M_RES1, WDTIM_MCTRL(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* Instant assert of RESETOUT_N with pulse length 1mS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) writel(13000, WDTIM_PULSE(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) writel(M_RES2 | RESFRC1 | RESFRC2, WDTIM_MCTRL(wdt_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Wait for watchdog to reset system */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) mdelay(1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static const struct watchdog_info pnx4008_wdt_ident = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .identity = "PNX4008 Watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static const struct watchdog_ops pnx4008_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .start = pnx4008_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .stop = pnx4008_wdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) .set_timeout = pnx4008_wdt_set_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .restart = pnx4008_restart_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct watchdog_device pnx4008_wdd = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .info = &pnx4008_wdt_ident,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .ops = &pnx4008_wdt_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .timeout = DEFAULT_HEARTBEAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .min_timeout = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .max_timeout = MAX_HEARTBEAT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void pnx4008_clk_disable_unprepare(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) clk_disable_unprepare(data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int pnx4008_wdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) watchdog_init_timeout(&pnx4008_wdd, heartbeat, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) wdt_base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (IS_ERR(wdt_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return PTR_ERR(wdt_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) wdt_clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (IS_ERR(wdt_clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return PTR_ERR(wdt_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) ret = clk_prepare_enable(wdt_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) ret = devm_add_action_or_reset(dev, pnx4008_clk_disable_unprepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) wdt_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) WDIOF_CARDRESET : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) pnx4008_wdd.parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) watchdog_set_nowayout(&pnx4008_wdd, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) watchdog_set_restart_priority(&pnx4008_wdd, 128);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) if (readl(WDTIM_CTRL(wdt_base)) & COUNT_ENAB)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) set_bit(WDOG_HW_RUNNING, &pnx4008_wdd.status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) ret = devm_watchdog_register_device(dev, &pnx4008_wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) dev_info(dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static const struct of_device_id pnx4008_wdt_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) { .compatible = "nxp,pnx4008-wdt" },
^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) MODULE_DEVICE_TABLE(of, pnx4008_wdt_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static struct platform_driver platform_wdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .name = "pnx4008-watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .of_match_table = of_match_ptr(pnx4008_wdt_match),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .probe = pnx4008_wdt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) module_platform_driver(platform_wdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) module_param(heartbeat, uint, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) MODULE_PARM_DESC(heartbeat,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) "Watchdog heartbeat period in seconds from 1 to "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) __MODULE_STRING(MAX_HEARTBEAT) ", default "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) __MODULE_STRING(DEFAULT_HEARTBEAT));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) module_param(nowayout, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) MODULE_PARM_DESC(nowayout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) "Set to 1 to keep watchdog running after device release");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) MODULE_ALIAS("platform:pnx4008-watchdog");