^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) * Cadence WDT driver - Used by Xilinx Zynq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2010 - 2014 Xilinx, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^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/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/watchdog.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define CDNS_WDT_DEFAULT_TIMEOUT 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) /* Supports 1 - 516 sec */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define CDNS_WDT_MIN_TIMEOUT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CDNS_WDT_MAX_TIMEOUT 516
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) /* Restart key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define CDNS_WDT_RESTART_KEY 0x00001999
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Counter register access key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /* Counter value divisor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* Clock prescaler value and selection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define CDNS_WDT_PRESCALE_64 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define CDNS_WDT_PRESCALE_512 512
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define CDNS_WDT_PRESCALE_4096 4096
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define CDNS_WDT_PRESCALE_SELECT_64 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define CDNS_WDT_PRESCALE_SELECT_512 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define CDNS_WDT_PRESCALE_SELECT_4096 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* Input clock frequency */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define CDNS_WDT_CLK_10MHZ 10000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define CDNS_WDT_CLK_75MHZ 75000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /* Counter maximum value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define CDNS_WDT_COUNTER_MAX 0xFFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static int wdt_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int nowayout = WATCHDOG_NOWAYOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) module_param(wdt_timeout, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) MODULE_PARM_DESC(wdt_timeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) "Watchdog time in seconds. (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) __MODULE_STRING(CDNS_WDT_DEFAULT_TIMEOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) module_param(nowayout, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) MODULE_PARM_DESC(nowayout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) "Watchdog cannot be stopped once started (default="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * struct cdns_wdt - Watchdog device structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * @regs: baseaddress of device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * @rst: reset flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * @clk: struct clk * of a clock source
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * @prescaler: for saving prescaler value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * @ctrl_clksel: counter clock prescaler selection
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * @io_lock: spinlock for IO register access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * @cdns_wdt_device: watchdog device structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * Structure containing parameters specific to cadence watchdog.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct cdns_wdt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void __iomem *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bool rst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct clk *clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) u32 prescaler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) u32 ctrl_clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) spinlock_t io_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct watchdog_device cdns_wdt_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* Write access to Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static inline void cdns_wdt_writereg(struct cdns_wdt *wdt, u32 offset, u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) writel_relaxed(val, wdt->regs + offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*************************Register Map**************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Register Offsets for the WDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define CDNS_WDT_ZMR_OFFSET 0x0 /* Zero Mode Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define CDNS_WDT_CCR_OFFSET 0x4 /* Counter Control Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define CDNS_WDT_RESTART_OFFSET 0x8 /* Restart Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define CDNS_WDT_SR_OFFSET 0xC /* Status Register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * Zero Mode Register - This register controls how the time out is indicated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * and also contains the access code to allow writes to the register (0xABC).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) #define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Counter Control register - This register controls how fast the timer runs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * and the reset value and also contains the access code to allow writes to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * the register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) * cdns_wdt_stop - Stop the watchdog.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * @wdd: watchdog device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * Read the contents of the ZMR register, clear the WDEN bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * in the register and set the access key for successful write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * Return: always 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static int cdns_wdt_stop(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) spin_lock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) spin_unlock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * cdns_wdt_reload - Reload the watchdog timer (i.e. pat the watchdog).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * @wdd: watchdog device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * Write the restart key value (0x00001999) to the restart register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * Return: always 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static int cdns_wdt_reload(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) spin_lock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) CDNS_WDT_RESTART_KEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) spin_unlock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) * cdns_wdt_start - Enable and start the watchdog.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) * @wdd: watchdog device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) * The counter value is calculated according to the formula:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) * calculated count = (timeout * clock) / prescaler + 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * The calculated count is divided by 0x1000 to obtain the field value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * to write to counter control register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * Clears the contents of prescaler and counter reset value. Sets the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) * prescaler to 4096 and the calculated count and access key
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) * to write to CCR Register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * or Interrupt signal(IRQEN) with a specified cycles and the access
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * key to write to ZMR Register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) * Return: always 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) static int cdns_wdt_start(struct watchdog_device *wdd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct cdns_wdt *wdt = watchdog_get_drvdata(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) unsigned int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) unsigned short count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) unsigned long clock_f = clk_get_rate(wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * Counter value divisor to obtain the value of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * counter reset to be written to control register.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) count = (wdd->timeout * (clock_f / wdt->prescaler)) /
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) CDNS_WDT_COUNTER_VALUE_DIVISOR + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) if (count > CDNS_WDT_COUNTER_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) count = CDNS_WDT_COUNTER_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) spin_lock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) CDNS_WDT_ZMR_ZKEY_VAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) count = (count << 2) & CDNS_WDT_CCR_CRV_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Write counter access key first to be able write to register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) data = count | CDNS_WDT_REGISTER_ACCESS_KEY | wdt->ctrl_clksel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) cdns_wdt_writereg(wdt, CDNS_WDT_CCR_OFFSET, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) CDNS_WDT_ZMR_ZKEY_VAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) /* Reset on timeout if specified in device tree. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (wdt->rst) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) data |= CDNS_WDT_ZMR_RSTEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) data &= ~CDNS_WDT_ZMR_IRQEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) data &= ~CDNS_WDT_ZMR_RSTEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) data |= CDNS_WDT_ZMR_IRQEN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) CDNS_WDT_RESTART_KEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) spin_unlock(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) * cdns_wdt_settimeout - Set a new timeout value for the watchdog device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * @wdd: watchdog device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * @new_time: new timeout value that needs to be set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * Return: 0 on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) * Update the watchdog_device timeout with new value which is used when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * cdns_wdt_start is called.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static int cdns_wdt_settimeout(struct watchdog_device *wdd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) unsigned int new_time)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) wdd->timeout = new_time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return cdns_wdt_start(wdd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) * cdns_wdt_irq_handler - Notifies of watchdog timeout.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) * @irq: interrupt number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * @dev_id: pointer to a platform device structure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) * Return: IRQ_HANDLED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * The handler is invoked when the watchdog times out and a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * reset on timeout has not been enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct platform_device *pdev = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) dev_info(&pdev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) "Watchdog timed out. Internal reset not enabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * Info structure used to indicate the features supported by the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * to the upper layers. This is defined in watchdog.h header file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) static const struct watchdog_info cdns_wdt_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) .identity = "cdns_wdt watchdog",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) WDIOF_MAGICCLOSE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) /* Watchdog Core Ops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static const struct watchdog_ops cdns_wdt_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) .start = cdns_wdt_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) .stop = cdns_wdt_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) .ping = cdns_wdt_reload,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) .set_timeout = cdns_wdt_settimeout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static void cdns_clk_disable_unprepare(void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) clk_disable_unprepare(data);
^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) /************************Platform Operations*****************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * cdns_wdt_probe - Probe call for the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * @pdev: handle to the platform device structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * Return: 0 on success, negative error otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) * It does all the memory allocation and registration for the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) static int cdns_wdt_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) int ret, irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) unsigned long clock_f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct cdns_wdt *wdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) struct watchdog_device *cdns_wdt_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (!wdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) cdns_wdt_device = &wdt->cdns_wdt_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) cdns_wdt_device->info = &cdns_wdt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) cdns_wdt_device->ops = &cdns_wdt_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) cdns_wdt_device->timeout = CDNS_WDT_DEFAULT_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) cdns_wdt_device->min_timeout = CDNS_WDT_MIN_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) cdns_wdt_device->max_timeout = CDNS_WDT_MAX_TIMEOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) wdt->regs = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (IS_ERR(wdt->regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return PTR_ERR(wdt->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) /* Register the interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) wdt->rst = of_property_read_bool(dev->of_node, "reset-on-timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) irq = platform_get_irq(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (!wdt->rst && irq >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ret = devm_request_irq(dev, irq, cdns_wdt_irq_handler, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) pdev->name, pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) dev_err(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) "cannot register interrupt handler err=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) /* Initialize the members of cdns_wdt structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) cdns_wdt_device->parent = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) watchdog_init_timeout(cdns_wdt_device, wdt_timeout, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) watchdog_set_nowayout(cdns_wdt_device, nowayout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) watchdog_stop_on_reboot(cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) watchdog_set_drvdata(cdns_wdt_device, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) wdt->clk = devm_clk_get(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if (IS_ERR(wdt->clk))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) return dev_err_probe(dev, PTR_ERR(wdt->clk),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) "input clock not found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) ret = clk_prepare_enable(wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) dev_err(dev, "unable to enable clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) ret = devm_add_action_or_reset(dev, cdns_clk_disable_unprepare,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) clock_f = clk_get_rate(wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (clock_f <= CDNS_WDT_CLK_75MHZ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) wdt->prescaler = CDNS_WDT_PRESCALE_512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) wdt->prescaler = CDNS_WDT_PRESCALE_4096;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) spin_lock_init(&wdt->io_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) watchdog_stop_on_reboot(cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) watchdog_stop_on_unregister(cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) ret = devm_watchdog_register_device(dev, cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) platform_set_drvdata(pdev, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) dev_info(dev, "Xilinx Watchdog Timer with timeout %ds%s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) cdns_wdt_device->timeout, nowayout ? ", nowayout" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * cdns_wdt_suspend - Stop the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * @dev: handle to the device structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * Return: 0 always.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static int __maybe_unused cdns_wdt_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) struct cdns_wdt *wdt = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (watchdog_active(&wdt->cdns_wdt_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) cdns_wdt_stop(&wdt->cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) clk_disable_unprepare(wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^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) * cdns_wdt_resume - Resume the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * @dev: handle to the device structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * Return: 0 on success, errno otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) static int __maybe_unused cdns_wdt_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct cdns_wdt *wdt = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (watchdog_active(&wdt->cdns_wdt_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) ret = clk_prepare_enable(wdt->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) dev_err(dev, "unable to enable clock\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) cdns_wdt_start(&wdt->cdns_wdt_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) static const struct of_device_id cdns_wdt_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) { .compatible = "cdns,wdt-r1p2", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) { /* end of table */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) MODULE_DEVICE_TABLE(of, cdns_wdt_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /* Driver Structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) static struct platform_driver cdns_wdt_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) .probe = cdns_wdt_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) .name = "cdns-wdt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) .of_match_table = cdns_wdt_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) .pm = &cdns_wdt_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) module_platform_driver(cdns_wdt_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) MODULE_AUTHOR("Xilinx, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) MODULE_DESCRIPTION("Watchdog driver for Cadence WDT");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) MODULE_LICENSE("GPL");