Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:
- new Cadence WDT driver
- new Ricoh RN5T618 watchdog
- new DA9063 PMIC watchdog driver
- new Meson WDT driver
- add restart handling code
- fixes and improvements

* git://www.linux-watchdog.org/linux-watchdog: (25 commits)
watchdog: meson: remove magic value for reboot
watchdog: Let XILINX_WATCHDOG and TEGRA_WATCHDOG depend on HAS_IOMEM
watchdog: sunxi: Add A31 watchdog support
watchdog: sunxi: support parameterized compatible strings
watchdog: imx2_wdt: add restart handler support
watchdog: qcom: register a restart notifier
watchdog: s3c2410: add restart handler
watchdog: dw_wdt: add restart handler support
ARM: defconfig: update multi_v7_defconfig
ARM: meson: add watchdog driver
ARM: docs: add documentation binding for meson watchdog
stmp3xxx_rtc_wdt: Add suspend/resume PM support
watchdog: Add DA9063 PMIC watchdog driver.
watchdog: add driver for Ricoh RN5T618 watchdog
watchdog: s3c2410_wdt: Add support for Watchdog device on Exynos7
watchdog: qcom: document device tree bindings
watchdog: qcom: add support for KPSS WDT
watchdog: dw_wdt: initialise TOP_INIT in dw_wdt_set_top()
devicetree: Add Cadence WDT devicetree bindings documentation
watchdog: Add Cadence WDT driver
...

+1725 -70
+24
Documentation/devicetree/bindings/watchdog/cadence-wdt.txt
··· 1 + Zynq Watchdog Device Tree Bindings 2 + ------------------------------------------- 3 + 4 + Required properties: 5 + - compatible : Should be "cdns,wdt-r1p2". 6 + - clocks : This is pclk (APB clock). 7 + - interrupts : This is wd_irq - watchdog timeout interrupt. 8 + - interrupt-parent : Must be core interrupt controller. 9 + 10 + Optional properties 11 + - reset-on-timeout : If this property exists, then a reset is done 12 + when watchdog times out. 13 + - timeout-sec : Watchdog timeout value (in seconds). 14 + 15 + Example: 16 + watchdog@f8005000 { 17 + compatible = "cdns,wdt-r1p2"; 18 + clocks = <&clkc 45>; 19 + interrupt-parent = <&intc>; 20 + interrupts = <0 9 1>; 21 + reg = <0xf8005000 0x1000>; 22 + reset-on-timeout; 23 + timeout-sec = <10>; 24 + };
+2 -1
Documentation/devicetree/bindings/watchdog/fsl-imx-wdt.txt
··· 7 7 8 8 Optional property: 9 9 - big-endian: If present the watchdog device's registers are implemented 10 - in big endian mode, otherwise in little mode. 10 + in big endian mode, otherwise in native mode(same with CPU), for more 11 + detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. 11 12 12 13 Examples: 13 14
+13
Documentation/devicetree/bindings/watchdog/meson6-wdt.txt
··· 1 + Meson SoCs Watchdog timer 2 + 3 + Required properties: 4 + 5 + - compatible : should be "amlogic,meson6-wdt" 6 + - reg : Specifies base physical address and size of the registers. 7 + 8 + Example: 9 + 10 + wdt: watchdog@c1109900 { 11 + compatible = "amlogic,meson6-wdt"; 12 + reg = <0xc1109900 0x8>; 13 + };
+24
Documentation/devicetree/bindings/watchdog/qcom-wdt.txt
··· 1 + Qualcomm Krait Processor Sub-system (KPSS) Watchdog 2 + --------------------------------------------------- 3 + 4 + Required properties : 5 + - compatible : shall contain only one of the following: 6 + 7 + "qcom,kpss-wdt-msm8960" 8 + "qcom,kpss-wdt-apq8064" 9 + "qcom,kpss-wdt-ipq8064" 10 + 11 + - reg : shall contain base register location and length 12 + - clocks : shall contain the input clock 13 + 14 + Optional properties : 15 + - timeout-sec : shall contain the default watchdog timeout in seconds, 16 + if unset, the default timeout is 30 seconds 17 + 18 + Example: 19 + watchdog@208a038 { 20 + compatible = "qcom,kpss-wdt-ipq8064"; 21 + reg = <0x0208a038 0x40>; 22 + clocks = <&sleep_clk>; 23 + timeout-sec = <10>; 24 + };
+1
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
··· 9 9 (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs 10 10 (b) "samsung,exynos5250-wdt" for Exynos5250 11 11 (c) "samsung,exynos5420-wdt" for Exynos5420 12 + (c) "samsung,exynos7-wdt" for Exynos7 12 13 13 14 - reg : base physical address of the controller and length of memory mapped 14 15 region.
+1
arch/arm/configs/multi_v7_defconfig
··· 261 261 CONFIG_XILINX_WATCHDOG=y 262 262 CONFIG_ORION_WATCHDOG=y 263 263 CONFIG_SUNXI_WATCHDOG=y 264 + CONFIG_MESON_WATCHDOG=y 264 265 CONFIG_MFD_AS3722=y 265 266 CONFIG_MFD_BCM590XX=y 266 267 CONFIG_MFD_CROS_EC=y
+53 -1
drivers/watchdog/Kconfig
··· 87 87 This driver can also be built as a module. If so, the module 88 88 will be called da9055_wdt. 89 89 90 + config DA9063_WATCHDOG 91 + tristate "Dialog DA9063 Watchdog" 92 + depends on MFD_DA9063 93 + select WATCHDOG_CORE 94 + help 95 + Support for the watchdog in the DA9063 PMIC. 96 + 97 + This driver can be built as a module. The module name is da9063_wdt. 98 + 90 99 config GPIO_WATCHDOG 91 100 tristate "Watchdog device controlled through GPIO-line" 92 101 depends on OF_GPIO ··· 132 123 133 124 config XILINX_WATCHDOG 134 125 tristate "Xilinx Watchdog timer" 126 + depends on HAS_IOMEM 135 127 select WATCHDOG_CORE 136 128 help 137 129 Watchdog driver for the xps_timebase_wdt ip core. ··· 166 156 help 167 157 Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will 168 158 reboot your system when the timeout is reached. 159 + 160 + config CADENCE_WATCHDOG 161 + tristate "Cadence Watchdog Timer" 162 + depends on ARM 163 + select WATCHDOG_CORE 164 + help 165 + Say Y here if you want to include support for the watchdog 166 + timer in the Xilinx Zynq. 169 167 170 168 config 21285_WATCHDOG 171 169 tristate "DC21285 watchdog" ··· 337 319 To compile this driver as a module, choose M here: the 338 320 module will be called orion_wdt. 339 321 322 + config RN5T618_WATCHDOG 323 + tristate "Ricoh RN5T618 watchdog" 324 + depends on MFD_RN5T618 325 + select WATCHDOG_CORE 326 + help 327 + If you say yes here you get support for watchdog on the Ricoh 328 + RN5T618 PMIC. 329 + 330 + This driver can also be built as a module. If so, the module 331 + will be called rn5t618_wdt. 332 + 340 333 config SUNXI_WATCHDOG 341 334 tristate "Allwinner SoCs watchdog support" 342 335 depends on ARCH_SUNXI ··· 473 444 474 445 config TEGRA_WATCHDOG 475 446 tristate "Tegra watchdog" 476 - depends on ARCH_TEGRA || COMPILE_TEST 447 + depends on (ARCH_TEGRA || COMPILE_TEST) && HAS_IOMEM 477 448 select WATCHDOG_CORE 478 449 help 479 450 Say Y here to include support for the watchdog timer ··· 481 452 482 453 To compile this driver as a module, choose M here: the 483 454 module will be called tegra_wdt. 455 + 456 + config QCOM_WDT 457 + tristate "QCOM watchdog" 458 + depends on HAS_IOMEM 459 + depends on ARCH_QCOM 460 + select WATCHDOG_CORE 461 + help 462 + Say Y here to include Watchdog timer support for the watchdog found 463 + on QCOM chipsets. Currently supported targets are the MSM8960, 464 + APQ8064, and IPQ8064. 465 + 466 + To compile this driver as a module, choose M here: the 467 + module will be called qcom_wdt. 468 + 469 + config MESON_WATCHDOG 470 + tristate "Amlogic Meson SoCs watchdog support" 471 + depends on ARCH_MESON 472 + select WATCHDOG_CORE 473 + help 474 + Say Y here to include support for the watchdog timer 475 + in Amlogic Meson SoCs. 476 + To compile this driver as a module, choose M here: the 477 + module will be called meson_wdt. 484 478 485 479 # AVR32 Architecture 486 480
+5
drivers/watchdog/Makefile
··· 32 32 obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o 33 33 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o 34 34 obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o 35 + obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o 35 36 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o 36 37 obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o 37 38 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o ··· 48 47 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o 49 48 obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o 50 49 obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o 50 + obj-$(CONFIG_RN5T618_WATCHDOG) += rn5t618_wdt.o 51 51 obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o 52 52 obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o 53 53 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o ··· 59 57 obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o 60 58 obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o 61 59 obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o 60 + obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o 62 61 obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o 63 62 obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o 63 + obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o 64 64 65 65 # AVR32 Architecture 66 66 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o ··· 177 173 # Architecture Independent 178 174 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o 179 175 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o 176 + obj-$(CONFIG_DA9063_WATCHDOG) += da9063_wdt.o 180 177 obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o 181 178 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o 182 179 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
+5 -23
drivers/watchdog/booke_wdt.c
··· 30 30 * occur, and the final time the board will reset. 31 31 */ 32 32 33 - u32 booke_wdt_enabled; 34 - u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT; 35 33 36 34 #ifdef CONFIG_PPC_FSL_BOOK3E 37 35 #define WDTP(x) ((((x)&0x3)<<30)|(((x)&0x3c)<<15)) ··· 39 41 #define WDTP_MASK (TCR_WP_MASK) 40 42 #endif 41 43 42 - /* Checks wdt=x and wdt_period=xx command-line option */ 43 - notrace int __init early_parse_wdt(char *p) 44 - { 45 - if (p && strncmp(p, "0", 1) != 0) 46 - booke_wdt_enabled = 1; 47 - 48 - return 0; 49 - } 50 - early_param("wdt", early_parse_wdt); 51 - 52 - int __init early_parse_wdt_period(char *p) 53 - { 54 - unsigned long ret; 55 - if (p) { 56 - if (!kstrtol(p, 0, &ret)) 57 - booke_wdt_period = ret; 58 - } 59 - 60 - return 0; 61 - } 62 - early_param("wdt_period", early_parse_wdt_period); 44 + static bool booke_wdt_enabled; 45 + module_param(booke_wdt_enabled, bool, 0); 46 + static int booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT; 47 + module_param(booke_wdt_period, int, 0); 63 48 64 49 #ifdef CONFIG_PPC_FSL_BOOK3E 65 50 ··· 240 259 module_init(booke_wdt_init); 241 260 module_exit(booke_wdt_exit); 242 261 262 + MODULE_ALIAS("booke_wdt"); 243 263 MODULE_DESCRIPTION("PowerPC Book-E watchdog driver"); 244 264 MODULE_LICENSE("GPL");
+516
drivers/watchdog/cadence_wdt.c
··· 1 + /* 2 + * Cadence WDT driver - Used by Xilinx Zynq 3 + * 4 + * Copyright (C) 2010 - 2014 Xilinx, Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/init.h> 14 + #include <linux/interrupt.h> 15 + #include <linux/io.h> 16 + #include <linux/irq.h> 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/of.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/reboot.h> 22 + #include <linux/watchdog.h> 23 + 24 + #define CDNS_WDT_DEFAULT_TIMEOUT 10 25 + /* Supports 1 - 516 sec */ 26 + #define CDNS_WDT_MIN_TIMEOUT 1 27 + #define CDNS_WDT_MAX_TIMEOUT 516 28 + 29 + /* Restart key */ 30 + #define CDNS_WDT_RESTART_KEY 0x00001999 31 + 32 + /* Counter register access key */ 33 + #define CDNS_WDT_REGISTER_ACCESS_KEY 0x00920000 34 + 35 + /* Counter value divisor */ 36 + #define CDNS_WDT_COUNTER_VALUE_DIVISOR 0x1000 37 + 38 + /* Clock prescaler value and selection */ 39 + #define CDNS_WDT_PRESCALE_64 64 40 + #define CDNS_WDT_PRESCALE_512 512 41 + #define CDNS_WDT_PRESCALE_4096 4096 42 + #define CDNS_WDT_PRESCALE_SELECT_64 1 43 + #define CDNS_WDT_PRESCALE_SELECT_512 2 44 + #define CDNS_WDT_PRESCALE_SELECT_4096 3 45 + 46 + /* Input clock frequency */ 47 + #define CDNS_WDT_CLK_10MHZ 10000000 48 + #define CDNS_WDT_CLK_75MHZ 75000000 49 + 50 + /* Counter maximum value */ 51 + #define CDNS_WDT_COUNTER_MAX 0xFFF 52 + 53 + static int wdt_timeout = CDNS_WDT_DEFAULT_TIMEOUT; 54 + static int nowayout = WATCHDOG_NOWAYOUT; 55 + 56 + module_param(wdt_timeout, int, 0); 57 + MODULE_PARM_DESC(wdt_timeout, 58 + "Watchdog time in seconds. (default=" 59 + __MODULE_STRING(CDNS_WDT_DEFAULT_TIMEOUT) ")"); 60 + 61 + module_param(nowayout, int, 0); 62 + MODULE_PARM_DESC(nowayout, 63 + "Watchdog cannot be stopped once started (default=" 64 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 65 + 66 + /** 67 + * struct cdns_wdt - Watchdog device structure 68 + * @regs: baseaddress of device 69 + * @rst: reset flag 70 + * @clk: struct clk * of a clock source 71 + * @prescaler: for saving prescaler value 72 + * @ctrl_clksel: counter clock prescaler selection 73 + * @io_lock: spinlock for IO register access 74 + * @cdns_wdt_device: watchdog device structure 75 + * @cdns_wdt_notifier: notifier structure 76 + * 77 + * Structure containing parameters specific to cadence watchdog. 78 + */ 79 + struct cdns_wdt { 80 + void __iomem *regs; 81 + bool rst; 82 + struct clk *clk; 83 + u32 prescaler; 84 + u32 ctrl_clksel; 85 + spinlock_t io_lock; 86 + struct watchdog_device cdns_wdt_device; 87 + struct notifier_block cdns_wdt_notifier; 88 + }; 89 + 90 + /* Write access to Registers */ 91 + static inline void cdns_wdt_writereg(struct cdns_wdt *wdt, u32 offset, u32 val) 92 + { 93 + writel_relaxed(val, wdt->regs + offset); 94 + } 95 + 96 + /*************************Register Map**************************************/ 97 + 98 + /* Register Offsets for the WDT */ 99 + #define CDNS_WDT_ZMR_OFFSET 0x0 /* Zero Mode Register */ 100 + #define CDNS_WDT_CCR_OFFSET 0x4 /* Counter Control Register */ 101 + #define CDNS_WDT_RESTART_OFFSET 0x8 /* Restart Register */ 102 + #define CDNS_WDT_SR_OFFSET 0xC /* Status Register */ 103 + 104 + /* 105 + * Zero Mode Register - This register controls how the time out is indicated 106 + * and also contains the access code to allow writes to the register (0xABC). 107 + */ 108 + #define CDNS_WDT_ZMR_WDEN_MASK 0x00000001 /* Enable the WDT */ 109 + #define CDNS_WDT_ZMR_RSTEN_MASK 0x00000002 /* Enable the reset output */ 110 + #define CDNS_WDT_ZMR_IRQEN_MASK 0x00000004 /* Enable IRQ output */ 111 + #define CDNS_WDT_ZMR_RSTLEN_16 0x00000030 /* Reset pulse of 16 pclk cycles */ 112 + #define CDNS_WDT_ZMR_ZKEY_VAL 0x00ABC000 /* Access key, 0xABC << 12 */ 113 + /* 114 + * Counter Control register - This register controls how fast the timer runs 115 + * and the reset value and also contains the access code to allow writes to 116 + * the register. 117 + */ 118 + #define CDNS_WDT_CCR_CRV_MASK 0x00003FFC /* Counter reset value */ 119 + 120 + /** 121 + * cdns_wdt_stop - Stop the watchdog. 122 + * 123 + * @wdd: watchdog device 124 + * 125 + * Read the contents of the ZMR register, clear the WDEN bit 126 + * in the register and set the access key for successful write. 127 + * 128 + * Return: always 0 129 + */ 130 + static int cdns_wdt_stop(struct watchdog_device *wdd) 131 + { 132 + struct cdns_wdt *wdt = watchdog_get_drvdata(wdd); 133 + 134 + spin_lock(&wdt->io_lock); 135 + cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, 136 + CDNS_WDT_ZMR_ZKEY_VAL & (~CDNS_WDT_ZMR_WDEN_MASK)); 137 + spin_unlock(&wdt->io_lock); 138 + 139 + return 0; 140 + } 141 + 142 + /** 143 + * cdns_wdt_reload - Reload the watchdog timer (i.e. pat the watchdog). 144 + * 145 + * @wdd: watchdog device 146 + * 147 + * Write the restart key value (0x00001999) to the restart register. 148 + * 149 + * Return: always 0 150 + */ 151 + static int cdns_wdt_reload(struct watchdog_device *wdd) 152 + { 153 + struct cdns_wdt *wdt = watchdog_get_drvdata(wdd); 154 + 155 + spin_lock(&wdt->io_lock); 156 + cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET, 157 + CDNS_WDT_RESTART_KEY); 158 + spin_unlock(&wdt->io_lock); 159 + 160 + return 0; 161 + } 162 + 163 + /** 164 + * cdns_wdt_start - Enable and start the watchdog. 165 + * 166 + * @wdd: watchdog device 167 + * 168 + * The counter value is calculated according to the formula: 169 + * calculated count = (timeout * clock) / prescaler + 1. 170 + * The calculated count is divided by 0x1000 to obtain the field value 171 + * to write to counter control register. 172 + * Clears the contents of prescaler and counter reset value. Sets the 173 + * prescaler to 4096 and the calculated count and access key 174 + * to write to CCR Register. 175 + * Sets the WDT (WDEN bit) and either the Reset signal(RSTEN bit) 176 + * or Interrupt signal(IRQEN) with a specified cycles and the access 177 + * key to write to ZMR Register. 178 + * 179 + * Return: always 0 180 + */ 181 + static int cdns_wdt_start(struct watchdog_device *wdd) 182 + { 183 + struct cdns_wdt *wdt = watchdog_get_drvdata(wdd); 184 + unsigned int data = 0; 185 + unsigned short count; 186 + unsigned long clock_f = clk_get_rate(wdt->clk); 187 + 188 + /* 189 + * Counter value divisor to obtain the value of 190 + * counter reset to be written to control register. 191 + */ 192 + count = (wdd->timeout * (clock_f / wdt->prescaler)) / 193 + CDNS_WDT_COUNTER_VALUE_DIVISOR + 1; 194 + 195 + if (count > CDNS_WDT_COUNTER_MAX) 196 + count = CDNS_WDT_COUNTER_MAX; 197 + 198 + spin_lock(&wdt->io_lock); 199 + cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, 200 + CDNS_WDT_ZMR_ZKEY_VAL); 201 + 202 + count = (count << 2) & CDNS_WDT_CCR_CRV_MASK; 203 + 204 + /* Write counter access key first to be able write to register */ 205 + data = count | CDNS_WDT_REGISTER_ACCESS_KEY | wdt->ctrl_clksel; 206 + cdns_wdt_writereg(wdt, CDNS_WDT_CCR_OFFSET, data); 207 + data = CDNS_WDT_ZMR_WDEN_MASK | CDNS_WDT_ZMR_RSTLEN_16 | 208 + CDNS_WDT_ZMR_ZKEY_VAL; 209 + 210 + /* Reset on timeout if specified in device tree. */ 211 + if (wdt->rst) { 212 + data |= CDNS_WDT_ZMR_RSTEN_MASK; 213 + data &= ~CDNS_WDT_ZMR_IRQEN_MASK; 214 + } else { 215 + data &= ~CDNS_WDT_ZMR_RSTEN_MASK; 216 + data |= CDNS_WDT_ZMR_IRQEN_MASK; 217 + } 218 + cdns_wdt_writereg(wdt, CDNS_WDT_ZMR_OFFSET, data); 219 + cdns_wdt_writereg(wdt, CDNS_WDT_RESTART_OFFSET, 220 + CDNS_WDT_RESTART_KEY); 221 + spin_unlock(&wdt->io_lock); 222 + 223 + return 0; 224 + } 225 + 226 + /** 227 + * cdns_wdt_settimeout - Set a new timeout value for the watchdog device. 228 + * 229 + * @wdd: watchdog device 230 + * @new_time: new timeout value that needs to be set 231 + * Return: 0 on success 232 + * 233 + * Update the watchdog_device timeout with new value which is used when 234 + * cdns_wdt_start is called. 235 + */ 236 + static int cdns_wdt_settimeout(struct watchdog_device *wdd, 237 + unsigned int new_time) 238 + { 239 + wdd->timeout = new_time; 240 + 241 + return cdns_wdt_start(wdd); 242 + } 243 + 244 + /** 245 + * cdns_wdt_irq_handler - Notifies of watchdog timeout. 246 + * 247 + * @irq: interrupt number 248 + * @dev_id: pointer to a platform device structure 249 + * Return: IRQ_HANDLED 250 + * 251 + * The handler is invoked when the watchdog times out and a 252 + * reset on timeout has not been enabled. 253 + */ 254 + static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id) 255 + { 256 + struct platform_device *pdev = dev_id; 257 + 258 + dev_info(&pdev->dev, 259 + "Watchdog timed out. Internal reset not enabled\n"); 260 + 261 + return IRQ_HANDLED; 262 + } 263 + 264 + /* 265 + * Info structure used to indicate the features supported by the device 266 + * to the upper layers. This is defined in watchdog.h header file. 267 + */ 268 + static struct watchdog_info cdns_wdt_info = { 269 + .identity = "cdns_wdt watchdog", 270 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 271 + WDIOF_MAGICCLOSE, 272 + }; 273 + 274 + /* Watchdog Core Ops */ 275 + static struct watchdog_ops cdns_wdt_ops = { 276 + .owner = THIS_MODULE, 277 + .start = cdns_wdt_start, 278 + .stop = cdns_wdt_stop, 279 + .ping = cdns_wdt_reload, 280 + .set_timeout = cdns_wdt_settimeout, 281 + }; 282 + 283 + /** 284 + * cdns_wdt_notify_sys - Notifier for reboot or shutdown. 285 + * 286 + * @this: handle to notifier block 287 + * @code: turn off indicator 288 + * @unused: unused 289 + * Return: NOTIFY_DONE 290 + * 291 + * This notifier is invoked whenever the system reboot or shutdown occur 292 + * because we need to disable the WDT before system goes down as WDT might 293 + * reset on the next boot. 294 + */ 295 + static int cdns_wdt_notify_sys(struct notifier_block *this, unsigned long code, 296 + void *unused) 297 + { 298 + struct cdns_wdt *wdt = container_of(this, struct cdns_wdt, 299 + cdns_wdt_notifier); 300 + if (code == SYS_DOWN || code == SYS_HALT) 301 + cdns_wdt_stop(&wdt->cdns_wdt_device); 302 + 303 + return NOTIFY_DONE; 304 + } 305 + 306 + /************************Platform Operations*****************************/ 307 + /** 308 + * cdns_wdt_probe - Probe call for the device. 309 + * 310 + * @pdev: handle to the platform device structure. 311 + * Return: 0 on success, negative error otherwise. 312 + * 313 + * It does all the memory allocation and registration for the device. 314 + */ 315 + static int cdns_wdt_probe(struct platform_device *pdev) 316 + { 317 + struct resource *res; 318 + int ret, irq; 319 + unsigned long clock_f; 320 + struct cdns_wdt *wdt; 321 + struct watchdog_device *cdns_wdt_device; 322 + 323 + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 324 + if (!wdt) 325 + return -ENOMEM; 326 + 327 + cdns_wdt_device = &wdt->cdns_wdt_device; 328 + cdns_wdt_device->info = &cdns_wdt_info; 329 + cdns_wdt_device->ops = &cdns_wdt_ops; 330 + cdns_wdt_device->timeout = CDNS_WDT_DEFAULT_TIMEOUT; 331 + cdns_wdt_device->min_timeout = CDNS_WDT_MIN_TIMEOUT; 332 + cdns_wdt_device->max_timeout = CDNS_WDT_MAX_TIMEOUT; 333 + 334 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 335 + wdt->regs = devm_ioremap_resource(&pdev->dev, res); 336 + if (IS_ERR(wdt->regs)) 337 + return PTR_ERR(wdt->regs); 338 + 339 + /* Register the interrupt */ 340 + wdt->rst = of_property_read_bool(pdev->dev.of_node, "reset-on-timeout"); 341 + irq = platform_get_irq(pdev, 0); 342 + if (!wdt->rst && irq >= 0) { 343 + ret = devm_request_irq(&pdev->dev, irq, cdns_wdt_irq_handler, 0, 344 + pdev->name, pdev); 345 + if (ret) { 346 + dev_err(&pdev->dev, 347 + "cannot register interrupt handler err=%d\n", 348 + ret); 349 + return ret; 350 + } 351 + } 352 + 353 + /* Initialize the members of cdns_wdt structure */ 354 + cdns_wdt_device->parent = &pdev->dev; 355 + 356 + ret = watchdog_init_timeout(cdns_wdt_device, wdt_timeout, &pdev->dev); 357 + if (ret) { 358 + dev_err(&pdev->dev, "unable to set timeout value\n"); 359 + return ret; 360 + } 361 + 362 + watchdog_set_nowayout(cdns_wdt_device, nowayout); 363 + watchdog_set_drvdata(cdns_wdt_device, wdt); 364 + 365 + wdt->clk = devm_clk_get(&pdev->dev, NULL); 366 + if (IS_ERR(wdt->clk)) { 367 + dev_err(&pdev->dev, "input clock not found\n"); 368 + ret = PTR_ERR(wdt->clk); 369 + return ret; 370 + } 371 + 372 + ret = clk_prepare_enable(wdt->clk); 373 + if (ret) { 374 + dev_err(&pdev->dev, "unable to enable clock\n"); 375 + return ret; 376 + } 377 + 378 + clock_f = clk_get_rate(wdt->clk); 379 + if (clock_f <= CDNS_WDT_CLK_75MHZ) { 380 + wdt->prescaler = CDNS_WDT_PRESCALE_512; 381 + wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_512; 382 + } else { 383 + wdt->prescaler = CDNS_WDT_PRESCALE_4096; 384 + wdt->ctrl_clksel = CDNS_WDT_PRESCALE_SELECT_4096; 385 + } 386 + 387 + spin_lock_init(&wdt->io_lock); 388 + 389 + wdt->cdns_wdt_notifier.notifier_call = &cdns_wdt_notify_sys; 390 + ret = register_reboot_notifier(&wdt->cdns_wdt_notifier); 391 + if (ret != 0) { 392 + dev_err(&pdev->dev, "cannot register reboot notifier err=%d)\n", 393 + ret); 394 + goto err_clk_disable; 395 + } 396 + 397 + ret = watchdog_register_device(cdns_wdt_device); 398 + if (ret) { 399 + dev_err(&pdev->dev, "Failed to register wdt device\n"); 400 + goto err_clk_disable; 401 + } 402 + platform_set_drvdata(pdev, wdt); 403 + 404 + dev_dbg(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds%s\n", 405 + wdt->regs, cdns_wdt_device->timeout, 406 + nowayout ? ", nowayout" : ""); 407 + 408 + return 0; 409 + 410 + err_clk_disable: 411 + clk_disable_unprepare(wdt->clk); 412 + 413 + return ret; 414 + } 415 + 416 + /** 417 + * cdns_wdt_remove - Probe call for the device. 418 + * 419 + * @pdev: handle to the platform device structure. 420 + * Return: 0 on success, otherwise negative error. 421 + * 422 + * Unregister the device after releasing the resources. 423 + */ 424 + static int cdns_wdt_remove(struct platform_device *pdev) 425 + { 426 + struct cdns_wdt *wdt = platform_get_drvdata(pdev); 427 + 428 + cdns_wdt_stop(&wdt->cdns_wdt_device); 429 + watchdog_unregister_device(&wdt->cdns_wdt_device); 430 + unregister_reboot_notifier(&wdt->cdns_wdt_notifier); 431 + clk_disable_unprepare(wdt->clk); 432 + 433 + return 0; 434 + } 435 + 436 + /** 437 + * cdns_wdt_shutdown - Stop the device. 438 + * 439 + * @pdev: handle to the platform structure. 440 + * 441 + */ 442 + static void cdns_wdt_shutdown(struct platform_device *pdev) 443 + { 444 + struct cdns_wdt *wdt = platform_get_drvdata(pdev); 445 + 446 + cdns_wdt_stop(&wdt->cdns_wdt_device); 447 + clk_disable_unprepare(wdt->clk); 448 + } 449 + 450 + /** 451 + * cdns_wdt_suspend - Stop the device. 452 + * 453 + * @dev: handle to the device structure. 454 + * Return: 0 always. 455 + */ 456 + static int __maybe_unused cdns_wdt_suspend(struct device *dev) 457 + { 458 + struct platform_device *pdev = container_of(dev, 459 + struct platform_device, dev); 460 + struct cdns_wdt *wdt = platform_get_drvdata(pdev); 461 + 462 + cdns_wdt_stop(&wdt->cdns_wdt_device); 463 + clk_disable_unprepare(wdt->clk); 464 + 465 + return 0; 466 + } 467 + 468 + /** 469 + * cdns_wdt_resume - Resume the device. 470 + * 471 + * @dev: handle to the device structure. 472 + * Return: 0 on success, errno otherwise. 473 + */ 474 + static int __maybe_unused cdns_wdt_resume(struct device *dev) 475 + { 476 + int ret; 477 + struct platform_device *pdev = container_of(dev, 478 + struct platform_device, dev); 479 + struct cdns_wdt *wdt = platform_get_drvdata(pdev); 480 + 481 + ret = clk_prepare_enable(wdt->clk); 482 + if (ret) { 483 + dev_err(dev, "unable to enable clock\n"); 484 + return ret; 485 + } 486 + cdns_wdt_start(&wdt->cdns_wdt_device); 487 + 488 + return 0; 489 + } 490 + 491 + static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume); 492 + 493 + static struct of_device_id cdns_wdt_of_match[] = { 494 + { .compatible = "cdns,wdt-r1p2", }, 495 + { /* end of table */ } 496 + }; 497 + MODULE_DEVICE_TABLE(of, cdns_wdt_of_match); 498 + 499 + /* Driver Structure */ 500 + static struct platform_driver cdns_wdt_driver = { 501 + .probe = cdns_wdt_probe, 502 + .remove = cdns_wdt_remove, 503 + .shutdown = cdns_wdt_shutdown, 504 + .driver = { 505 + .name = "cdns-wdt", 506 + .owner = THIS_MODULE, 507 + .of_match_table = cdns_wdt_of_match, 508 + .pm = &cdns_wdt_pm_ops, 509 + }, 510 + }; 511 + 512 + module_platform_driver(cdns_wdt_driver); 513 + 514 + MODULE_AUTHOR("Xilinx, Inc."); 515 + MODULE_DESCRIPTION("Watchdog driver for Cadence WDT"); 516 + MODULE_LICENSE("GPL");
+191
drivers/watchdog/da9063_wdt.c
··· 1 + /* 2 + * Watchdog driver for DA9063 PMICs. 3 + * 4 + * Copyright(c) 2012 Dialog Semiconductor Ltd. 5 + * 6 + * Author: Mariusz Wojtasik <mariusz.wojtasik@diasemi.com> 7 + * 8 + * This program is free software; you can redistribute it and/or modify it 9 + * under the terms of the GNU General Public License as published by the 10 + * Free Software Foundation; either version 2 of the License, or (at your 11 + * option) any later version. 12 + */ 13 + 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/watchdog.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/uaccess.h> 19 + #include <linux/slab.h> 20 + #include <linux/delay.h> 21 + #include <linux/mfd/da9063/registers.h> 22 + #include <linux/mfd/da9063/core.h> 23 + #include <linux/regmap.h> 24 + 25 + /* 26 + * Watchdog selector to timeout in seconds. 27 + * 0: WDT disabled; 28 + * others: timeout = 2048 ms * 2^(TWDSCALE-1). 29 + */ 30 + static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 }; 31 + #define DA9063_TWDSCALE_DISABLE 0 32 + #define DA9063_TWDSCALE_MIN 1 33 + #define DA9063_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1) 34 + #define DA9063_WDT_MIN_TIMEOUT wdt_timeout[DA9063_TWDSCALE_MIN] 35 + #define DA9063_WDT_MAX_TIMEOUT wdt_timeout[DA9063_TWDSCALE_MAX] 36 + #define DA9063_WDG_TIMEOUT wdt_timeout[3] 37 + 38 + struct da9063_watchdog { 39 + struct da9063 *da9063; 40 + struct watchdog_device wdtdev; 41 + }; 42 + 43 + static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) 44 + { 45 + unsigned int i; 46 + 47 + for (i = DA9063_TWDSCALE_MIN; i <= DA9063_TWDSCALE_MAX; i++) { 48 + if (wdt_timeout[i] >= secs) 49 + return i; 50 + } 51 + 52 + return DA9063_TWDSCALE_MAX; 53 + } 54 + 55 + static int _da9063_wdt_set_timeout(struct da9063 *da9063, unsigned int regval) 56 + { 57 + return regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D, 58 + DA9063_TWDSCALE_MASK, regval); 59 + } 60 + 61 + static int da9063_wdt_start(struct watchdog_device *wdd) 62 + { 63 + struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd); 64 + unsigned int selector; 65 + int ret; 66 + 67 + selector = da9063_wdt_timeout_to_sel(wdt->wdtdev.timeout); 68 + ret = _da9063_wdt_set_timeout(wdt->da9063, selector); 69 + if (ret) 70 + dev_err(wdt->da9063->dev, "Watchdog failed to start (err = %d)\n", 71 + ret); 72 + 73 + return ret; 74 + } 75 + 76 + static int da9063_wdt_stop(struct watchdog_device *wdd) 77 + { 78 + struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd); 79 + int ret; 80 + 81 + ret = regmap_update_bits(wdt->da9063->regmap, DA9063_REG_CONTROL_D, 82 + DA9063_TWDSCALE_MASK, DA9063_TWDSCALE_DISABLE); 83 + if (ret) 84 + dev_alert(wdt->da9063->dev, "Watchdog failed to stop (err = %d)\n", 85 + ret); 86 + 87 + return ret; 88 + } 89 + 90 + static int da9063_wdt_ping(struct watchdog_device *wdd) 91 + { 92 + struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd); 93 + int ret; 94 + 95 + ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F, 96 + DA9063_WATCHDOG); 97 + if (ret) 98 + dev_alert(wdt->da9063->dev, "Failed to ping the watchdog (err = %d)\n", 99 + ret); 100 + 101 + return ret; 102 + } 103 + 104 + static int da9063_wdt_set_timeout(struct watchdog_device *wdd, 105 + unsigned int timeout) 106 + { 107 + struct da9063_watchdog *wdt = watchdog_get_drvdata(wdd); 108 + unsigned int selector; 109 + int ret; 110 + 111 + selector = da9063_wdt_timeout_to_sel(timeout); 112 + ret = _da9063_wdt_set_timeout(wdt->da9063, selector); 113 + if (ret) 114 + dev_err(wdt->da9063->dev, "Failed to set watchdog timeout (err = %d)\n", 115 + ret); 116 + else 117 + wdd->timeout = wdt_timeout[selector]; 118 + 119 + return ret; 120 + } 121 + 122 + static const struct watchdog_info da9063_watchdog_info = { 123 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 124 + .identity = "DA9063 Watchdog", 125 + }; 126 + 127 + static const struct watchdog_ops da9063_watchdog_ops = { 128 + .owner = THIS_MODULE, 129 + .start = da9063_wdt_start, 130 + .stop = da9063_wdt_stop, 131 + .ping = da9063_wdt_ping, 132 + .set_timeout = da9063_wdt_set_timeout, 133 + }; 134 + 135 + static int da9063_wdt_probe(struct platform_device *pdev) 136 + { 137 + int ret; 138 + struct da9063 *da9063; 139 + struct da9063_watchdog *wdt; 140 + 141 + if (!pdev->dev.parent) 142 + return -EINVAL; 143 + 144 + da9063 = dev_get_drvdata(pdev->dev.parent); 145 + if (!da9063) 146 + return -EINVAL; 147 + 148 + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 149 + if (!wdt) 150 + return -ENOMEM; 151 + 152 + wdt->da9063 = da9063; 153 + 154 + wdt->wdtdev.info = &da9063_watchdog_info; 155 + wdt->wdtdev.ops = &da9063_watchdog_ops; 156 + wdt->wdtdev.min_timeout = DA9063_WDT_MIN_TIMEOUT; 157 + wdt->wdtdev.max_timeout = DA9063_WDT_MAX_TIMEOUT; 158 + wdt->wdtdev.timeout = DA9063_WDG_TIMEOUT; 159 + 160 + wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; 161 + 162 + watchdog_set_drvdata(&wdt->wdtdev, wdt); 163 + dev_set_drvdata(&pdev->dev, wdt); 164 + 165 + ret = watchdog_register_device(&wdt->wdtdev); 166 + 167 + return ret; 168 + } 169 + 170 + static int da9063_wdt_remove(struct platform_device *pdev) 171 + { 172 + struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev); 173 + 174 + watchdog_unregister_device(&wdt->wdtdev); 175 + 176 + return 0; 177 + } 178 + 179 + static struct platform_driver da9063_wdt_driver = { 180 + .probe = da9063_wdt_probe, 181 + .remove = da9063_wdt_remove, 182 + .driver = { 183 + .name = DA9063_DRVNAME_WATCHDOG, 184 + }, 185 + }; 186 + module_platform_driver(da9063_wdt_driver); 187 + 188 + MODULE_AUTHOR("Mariusz Wojtasik <mariusz.wojtasik@diasemi.com>"); 189 + MODULE_DESCRIPTION("Watchdog driver for Dialog DA9063"); 190 + MODULE_LICENSE("GPL"); 191 + MODULE_ALIAS("platform:" DA9063_DRVNAME_WATCHDOG);
+35 -1
drivers/watchdog/dw_wdt.c
··· 21 21 22 22 #include <linux/bitops.h> 23 23 #include <linux/clk.h> 24 + #include <linux/delay.h> 24 25 #include <linux/device.h> 25 26 #include <linux/err.h> 26 27 #include <linux/fs.h> ··· 30 29 #include <linux/miscdevice.h> 31 30 #include <linux/module.h> 32 31 #include <linux/moduleparam.h> 32 + #include <linux/notifier.h> 33 33 #include <linux/of.h> 34 34 #include <linux/pm.h> 35 35 #include <linux/platform_device.h> 36 + #include <linux/reboot.h> 36 37 #include <linux/spinlock.h> 37 38 #include <linux/timer.h> 38 39 #include <linux/uaccess.h> ··· 43 40 #define WDOG_CONTROL_REG_OFFSET 0x00 44 41 #define WDOG_CONTROL_REG_WDT_EN_MASK 0x01 45 42 #define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04 43 + #define WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT 4 46 44 #define WDOG_CURRENT_COUNT_REG_OFFSET 0x08 47 45 #define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c 48 46 #define WDOG_COUNTER_RESTART_KICK_VALUE 0x76 ··· 66 62 unsigned long next_heartbeat; 67 63 struct timer_list timer; 68 64 int expect_close; 65 + struct notifier_block restart_handler; 69 66 } dw_wdt; 70 67 71 68 static inline int dw_wdt_is_enabled(void) ··· 111 106 } 112 107 113 108 /* Set the new value in the watchdog. */ 114 - writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 109 + writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT, 110 + dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 115 111 116 112 dw_wdt_set_next_heartbeat(); 117 113 ··· 123 117 { 124 118 writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + 125 119 WDOG_COUNTER_RESTART_REG_OFFSET); 120 + } 121 + 122 + static int dw_wdt_restart_handle(struct notifier_block *this, 123 + unsigned long mode, void *cmd) 124 + { 125 + u32 val; 126 + 127 + writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); 128 + val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); 129 + if (val & WDOG_CONTROL_REG_WDT_EN_MASK) 130 + writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + 131 + WDOG_COUNTER_RESTART_REG_OFFSET); 132 + else 133 + writel(WDOG_CONTROL_REG_WDT_EN_MASK, 134 + dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); 135 + 136 + /* wait for reset to assert... */ 137 + mdelay(500); 138 + 139 + return NOTIFY_DONE; 126 140 } 127 141 128 142 static void dw_wdt_ping(unsigned long data) ··· 340 314 if (ret) 341 315 goto out_disable_clk; 342 316 317 + dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle; 318 + dw_wdt.restart_handler.priority = 128; 319 + ret = register_restart_handler(&dw_wdt.restart_handler); 320 + if (ret) 321 + pr_warn("cannot register restart handler\n"); 322 + 343 323 dw_wdt_set_next_heartbeat(); 344 324 setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); 345 325 mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); ··· 360 328 361 329 static int dw_wdt_drv_remove(struct platform_device *pdev) 362 330 { 331 + unregister_restart_handler(&dw_wdt.restart_handler); 332 + 363 333 misc_deregister(&dw_wdt_miscdev); 364 334 365 335 clk_disable_unprepare(dw_wdt.clk);
+37 -6
drivers/watchdog/imx2_wdt.c
··· 22 22 */ 23 23 24 24 #include <linux/clk.h> 25 + #include <linux/delay.h> 25 26 #include <linux/init.h> 26 27 #include <linux/io.h> 27 28 #include <linux/jiffies.h> 28 29 #include <linux/kernel.h> 29 30 #include <linux/module.h> 30 31 #include <linux/moduleparam.h> 32 + #include <linux/notifier.h> 31 33 #include <linux/of_address.h> 32 34 #include <linux/platform_device.h> 35 + #include <linux/reboot.h> 33 36 #include <linux/regmap.h> 34 37 #include <linux/timer.h> 35 38 #include <linux/watchdog.h> ··· 62 59 struct regmap *regmap; 63 60 struct timer_list timer; /* Pings the watchdog when closed */ 64 61 struct watchdog_device wdog; 62 + struct notifier_block restart_handler; 65 63 }; 66 64 67 65 static bool nowayout = WATCHDOG_NOWAYOUT; ··· 80 76 .identity = "imx2+ watchdog", 81 77 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 82 78 }; 79 + 80 + static int imx2_restart_handler(struct notifier_block *this, unsigned long mode, 81 + void *cmd) 82 + { 83 + unsigned int wcr_enable = IMX2_WDT_WCR_WDE; 84 + struct imx2_wdt_device *wdev = container_of(this, 85 + struct imx2_wdt_device, 86 + restart_handler); 87 + /* Assert SRS signal */ 88 + regmap_write(wdev->regmap, 0, wcr_enable); 89 + /* 90 + * Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be 91 + * written twice), we add another two writes to ensure there must be at 92 + * least two writes happen in the same one 32kHz clock period. We save 93 + * the target check here, since the writes shouldn't be a huge burden 94 + * for other platforms. 95 + */ 96 + regmap_write(wdev->regmap, 0, wcr_enable); 97 + regmap_write(wdev->regmap, 0, wcr_enable); 98 + 99 + /* wait for reset to assert... */ 100 + mdelay(500); 101 + 102 + return NOTIFY_DONE; 103 + } 83 104 84 105 static inline void imx2_wdt_setup(struct watchdog_device *wdog) 85 106 { ··· 220 191 221 192 static int __init imx2_wdt_probe(struct platform_device *pdev) 222 193 { 223 - struct device_node *np = pdev->dev.of_node; 224 194 struct imx2_wdt_device *wdev; 225 195 struct watchdog_device *wdog; 226 196 struct resource *res; 227 197 void __iomem *base; 228 - bool big_endian; 229 198 int ret; 230 199 u32 val; 231 200 232 201 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); 233 202 if (!wdev) 234 203 return -ENOMEM; 235 - 236 - big_endian = of_property_read_bool(np, "big-endian"); 237 - if (big_endian) 238 - imx2_wdt_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; 239 204 240 205 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 241 206 base = devm_ioremap_resource(&pdev->dev, res); ··· 280 257 return ret; 281 258 } 282 259 260 + wdev->restart_handler.notifier_call = imx2_restart_handler; 261 + wdev->restart_handler.priority = 128; 262 + ret = register_restart_handler(&wdev->restart_handler); 263 + if (ret) 264 + dev_err(&pdev->dev, "cannot register restart handler\n"); 265 + 283 266 dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n", 284 267 wdog->timeout, nowayout); 285 268 ··· 296 267 { 297 268 struct watchdog_device *wdog = platform_get_drvdata(pdev); 298 269 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); 270 + 271 + unregister_restart_handler(&wdev->restart_handler); 299 272 300 273 watchdog_unregister_device(wdog); 301 274
+236
drivers/watchdog/meson_wdt.c
··· 1 + /* 2 + * Meson Watchdog Driver 3 + * 4 + * Copyright (c) 2014 Carlo Caione 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/delay.h> 14 + #include <linux/err.h> 15 + #include <linux/init.h> 16 + #include <linux/io.h> 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/moduleparam.h> 20 + #include <linux/notifier.h> 21 + #include <linux/of.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/reboot.h> 24 + #include <linux/types.h> 25 + #include <linux/watchdog.h> 26 + 27 + #define DRV_NAME "meson_wdt" 28 + 29 + #define MESON_WDT_TC 0x00 30 + #define MESON_WDT_TC_EN BIT(22) 31 + #define MESON_WDT_TC_TM_MASK 0x3fffff 32 + #define MESON_WDT_DC_RESET (3 << 24) 33 + 34 + #define MESON_WDT_RESET 0x04 35 + 36 + #define MESON_WDT_TIMEOUT 30 37 + #define MESON_WDT_MIN_TIMEOUT 1 38 + #define MESON_WDT_MAX_TIMEOUT (MESON_WDT_TC_TM_MASK / 100000) 39 + 40 + #define MESON_SEC_TO_TC(s) ((s) * 100000) 41 + 42 + static bool nowayout = WATCHDOG_NOWAYOUT; 43 + static unsigned int timeout = MESON_WDT_TIMEOUT; 44 + 45 + struct meson_wdt_dev { 46 + struct watchdog_device wdt_dev; 47 + void __iomem *wdt_base; 48 + struct notifier_block restart_handler; 49 + }; 50 + 51 + static int meson_restart_handle(struct notifier_block *this, unsigned long mode, 52 + void *cmd) 53 + { 54 + u32 tc_reboot = MESON_WDT_DC_RESET | MESON_WDT_TC_EN; 55 + struct meson_wdt_dev *meson_wdt = container_of(this, 56 + struct meson_wdt_dev, 57 + restart_handler); 58 + 59 + while (1) { 60 + writel(tc_reboot, meson_wdt->wdt_base + MESON_WDT_TC); 61 + mdelay(5); 62 + } 63 + 64 + return NOTIFY_DONE; 65 + } 66 + 67 + static int meson_wdt_ping(struct watchdog_device *wdt_dev) 68 + { 69 + struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev); 70 + 71 + writel(0, meson_wdt->wdt_base + MESON_WDT_RESET); 72 + 73 + return 0; 74 + } 75 + 76 + static void meson_wdt_change_timeout(struct watchdog_device *wdt_dev, 77 + unsigned int timeout) 78 + { 79 + struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev); 80 + u32 reg; 81 + 82 + reg = readl(meson_wdt->wdt_base + MESON_WDT_TC); 83 + reg &= ~MESON_WDT_TC_TM_MASK; 84 + reg |= MESON_SEC_TO_TC(timeout); 85 + writel(reg, meson_wdt->wdt_base + MESON_WDT_TC); 86 + } 87 + 88 + static int meson_wdt_set_timeout(struct watchdog_device *wdt_dev, 89 + unsigned int timeout) 90 + { 91 + wdt_dev->timeout = timeout; 92 + 93 + meson_wdt_change_timeout(wdt_dev, timeout); 94 + meson_wdt_ping(wdt_dev); 95 + 96 + return 0; 97 + } 98 + 99 + static int meson_wdt_stop(struct watchdog_device *wdt_dev) 100 + { 101 + struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev); 102 + u32 reg; 103 + 104 + reg = readl(meson_wdt->wdt_base + MESON_WDT_TC); 105 + reg &= ~MESON_WDT_TC_EN; 106 + writel(reg, meson_wdt->wdt_base + MESON_WDT_TC); 107 + 108 + return 0; 109 + } 110 + 111 + static int meson_wdt_start(struct watchdog_device *wdt_dev) 112 + { 113 + struct meson_wdt_dev *meson_wdt = watchdog_get_drvdata(wdt_dev); 114 + u32 reg; 115 + 116 + meson_wdt_change_timeout(wdt_dev, meson_wdt->wdt_dev.timeout); 117 + meson_wdt_ping(wdt_dev); 118 + 119 + reg = readl(meson_wdt->wdt_base + MESON_WDT_TC); 120 + reg |= MESON_WDT_TC_EN; 121 + writel(reg, meson_wdt->wdt_base + MESON_WDT_TC); 122 + 123 + return 0; 124 + } 125 + 126 + static const struct watchdog_info meson_wdt_info = { 127 + .identity = DRV_NAME, 128 + .options = WDIOF_SETTIMEOUT | 129 + WDIOF_KEEPALIVEPING | 130 + WDIOF_MAGICCLOSE, 131 + }; 132 + 133 + static const struct watchdog_ops meson_wdt_ops = { 134 + .owner = THIS_MODULE, 135 + .start = meson_wdt_start, 136 + .stop = meson_wdt_stop, 137 + .ping = meson_wdt_ping, 138 + .set_timeout = meson_wdt_set_timeout, 139 + }; 140 + 141 + static int meson_wdt_probe(struct platform_device *pdev) 142 + { 143 + struct resource *res; 144 + struct meson_wdt_dev *meson_wdt; 145 + int err; 146 + 147 + meson_wdt = devm_kzalloc(&pdev->dev, sizeof(*meson_wdt), GFP_KERNEL); 148 + if (!meson_wdt) 149 + return -ENOMEM; 150 + 151 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 152 + meson_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); 153 + if (IS_ERR(meson_wdt->wdt_base)) 154 + return PTR_ERR(meson_wdt->wdt_base); 155 + 156 + meson_wdt->wdt_dev.parent = &pdev->dev; 157 + meson_wdt->wdt_dev.info = &meson_wdt_info; 158 + meson_wdt->wdt_dev.ops = &meson_wdt_ops; 159 + meson_wdt->wdt_dev.timeout = MESON_WDT_TIMEOUT; 160 + meson_wdt->wdt_dev.max_timeout = MESON_WDT_MAX_TIMEOUT; 161 + meson_wdt->wdt_dev.min_timeout = MESON_WDT_MIN_TIMEOUT; 162 + 163 + watchdog_set_drvdata(&meson_wdt->wdt_dev, meson_wdt); 164 + 165 + watchdog_init_timeout(&meson_wdt->wdt_dev, timeout, &pdev->dev); 166 + watchdog_set_nowayout(&meson_wdt->wdt_dev, nowayout); 167 + 168 + meson_wdt_stop(&meson_wdt->wdt_dev); 169 + 170 + err = watchdog_register_device(&meson_wdt->wdt_dev); 171 + if (err) 172 + return err; 173 + 174 + platform_set_drvdata(pdev, meson_wdt); 175 + 176 + meson_wdt->restart_handler.notifier_call = meson_restart_handle; 177 + meson_wdt->restart_handler.priority = 128; 178 + err = register_restart_handler(&meson_wdt->restart_handler); 179 + if (err) 180 + dev_err(&pdev->dev, 181 + "cannot register restart handler (err=%d)\n", err); 182 + 183 + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", 184 + meson_wdt->wdt_dev.timeout, nowayout); 185 + 186 + return 0; 187 + } 188 + 189 + static int meson_wdt_remove(struct platform_device *pdev) 190 + { 191 + struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); 192 + 193 + unregister_restart_handler(&meson_wdt->restart_handler); 194 + 195 + watchdog_unregister_device(&meson_wdt->wdt_dev); 196 + 197 + return 0; 198 + } 199 + 200 + static void meson_wdt_shutdown(struct platform_device *pdev) 201 + { 202 + struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); 203 + 204 + meson_wdt_stop(&meson_wdt->wdt_dev); 205 + } 206 + 207 + static const struct of_device_id meson_wdt_dt_ids[] = { 208 + { .compatible = "amlogic,meson6-wdt" }, 209 + { /* sentinel */ } 210 + }; 211 + MODULE_DEVICE_TABLE(of, meson_wdt_dt_ids); 212 + 213 + static struct platform_driver meson_wdt_driver = { 214 + .probe = meson_wdt_probe, 215 + .remove = meson_wdt_remove, 216 + .shutdown = meson_wdt_shutdown, 217 + .driver = { 218 + .owner = THIS_MODULE, 219 + .name = DRV_NAME, 220 + .of_match_table = meson_wdt_dt_ids, 221 + }, 222 + }; 223 + 224 + module_platform_driver(meson_wdt_driver); 225 + 226 + module_param(timeout, uint, 0); 227 + MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); 228 + 229 + module_param(nowayout, bool, 0); 230 + MODULE_PARM_DESC(nowayout, 231 + "Watchdog cannot be stopped once started (default=" 232 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 233 + 234 + MODULE_LICENSE("GPL"); 235 + MODULE_AUTHOR("Carlo Caione <carlo@caione.org>"); 236 + MODULE_DESCRIPTION("Meson Watchdog Timer Driver");
-1
drivers/watchdog/of_xilinx_wdt.c
··· 236 236 .probe = xwdt_probe, 237 237 .remove = xwdt_remove, 238 238 .driver = { 239 - .owner = THIS_MODULE, 240 239 .name = WATCHDOG_NAME, 241 240 .of_match_table = xwdt_of_match, 242 241 },
+224
drivers/watchdog/qcom-wdt.c
··· 1 + /* Copyright (c) 2014, The Linux Foundation. All rights reserved. 2 + * 3 + * This program is free software; you can redistribute it and/or modify 4 + * it under the terms of the GNU General Public License version 2 and 5 + * only version 2 as published by the Free Software Foundation. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + */ 13 + #include <linux/clk.h> 14 + #include <linux/delay.h> 15 + #include <linux/io.h> 16 + #include <linux/kernel.h> 17 + #include <linux/module.h> 18 + #include <linux/of.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/reboot.h> 21 + #include <linux/watchdog.h> 22 + 23 + #define WDT_RST 0x0 24 + #define WDT_EN 0x8 25 + #define WDT_BITE_TIME 0x24 26 + 27 + struct qcom_wdt { 28 + struct watchdog_device wdd; 29 + struct clk *clk; 30 + unsigned long rate; 31 + struct notifier_block restart_nb; 32 + void __iomem *base; 33 + }; 34 + 35 + static inline 36 + struct qcom_wdt *to_qcom_wdt(struct watchdog_device *wdd) 37 + { 38 + return container_of(wdd, struct qcom_wdt, wdd); 39 + } 40 + 41 + static int qcom_wdt_start(struct watchdog_device *wdd) 42 + { 43 + struct qcom_wdt *wdt = to_qcom_wdt(wdd); 44 + 45 + writel(0, wdt->base + WDT_EN); 46 + writel(1, wdt->base + WDT_RST); 47 + writel(wdd->timeout * wdt->rate, wdt->base + WDT_BITE_TIME); 48 + writel(1, wdt->base + WDT_EN); 49 + return 0; 50 + } 51 + 52 + static int qcom_wdt_stop(struct watchdog_device *wdd) 53 + { 54 + struct qcom_wdt *wdt = to_qcom_wdt(wdd); 55 + 56 + writel(0, wdt->base + WDT_EN); 57 + return 0; 58 + } 59 + 60 + static int qcom_wdt_ping(struct watchdog_device *wdd) 61 + { 62 + struct qcom_wdt *wdt = to_qcom_wdt(wdd); 63 + 64 + writel(1, wdt->base + WDT_RST); 65 + return 0; 66 + } 67 + 68 + static int qcom_wdt_set_timeout(struct watchdog_device *wdd, 69 + unsigned int timeout) 70 + { 71 + wdd->timeout = timeout; 72 + return qcom_wdt_start(wdd); 73 + } 74 + 75 + static const struct watchdog_ops qcom_wdt_ops = { 76 + .start = qcom_wdt_start, 77 + .stop = qcom_wdt_stop, 78 + .ping = qcom_wdt_ping, 79 + .set_timeout = qcom_wdt_set_timeout, 80 + .owner = THIS_MODULE, 81 + }; 82 + 83 + static const struct watchdog_info qcom_wdt_info = { 84 + .options = WDIOF_KEEPALIVEPING 85 + | WDIOF_MAGICCLOSE 86 + | WDIOF_SETTIMEOUT, 87 + .identity = KBUILD_MODNAME, 88 + }; 89 + 90 + static int qcom_wdt_restart(struct notifier_block *nb, unsigned long action, 91 + void *data) 92 + { 93 + struct qcom_wdt *wdt = container_of(nb, struct qcom_wdt, restart_nb); 94 + u32 timeout; 95 + 96 + /* 97 + * Trigger watchdog bite: 98 + * Setup BITE_TIME to be 128ms, and enable WDT. 99 + */ 100 + timeout = 128 * wdt->rate / 1000; 101 + 102 + writel(0, wdt->base + WDT_EN); 103 + writel(1, wdt->base + WDT_RST); 104 + writel(timeout, wdt->base + WDT_BITE_TIME); 105 + writel(1, wdt->base + WDT_EN); 106 + 107 + /* 108 + * Actually make sure the above sequence hits hardware before sleeping. 109 + */ 110 + wmb(); 111 + 112 + msleep(150); 113 + return NOTIFY_DONE; 114 + } 115 + 116 + static int qcom_wdt_probe(struct platform_device *pdev) 117 + { 118 + struct qcom_wdt *wdt; 119 + struct resource *res; 120 + int ret; 121 + 122 + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 123 + if (!wdt) 124 + return -ENOMEM; 125 + 126 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 127 + wdt->base = devm_ioremap_resource(&pdev->dev, res); 128 + if (IS_ERR(wdt->base)) 129 + return PTR_ERR(wdt->base); 130 + 131 + wdt->clk = devm_clk_get(&pdev->dev, NULL); 132 + if (IS_ERR(wdt->clk)) { 133 + dev_err(&pdev->dev, "failed to get input clock\n"); 134 + return PTR_ERR(wdt->clk); 135 + } 136 + 137 + ret = clk_prepare_enable(wdt->clk); 138 + if (ret) { 139 + dev_err(&pdev->dev, "failed to setup clock\n"); 140 + return ret; 141 + } 142 + 143 + /* 144 + * We use the clock rate to calculate the max timeout, so ensure it's 145 + * not zero to avoid a divide-by-zero exception. 146 + * 147 + * WATCHDOG_CORE assumes units of seconds, if the WDT is clocked such 148 + * that it would bite before a second elapses it's usefulness is 149 + * limited. Bail if this is the case. 150 + */ 151 + wdt->rate = clk_get_rate(wdt->clk); 152 + if (wdt->rate == 0 || 153 + wdt->rate > 0x10000000U) { 154 + dev_err(&pdev->dev, "invalid clock rate\n"); 155 + ret = -EINVAL; 156 + goto err_clk_unprepare; 157 + } 158 + 159 + wdt->wdd.dev = &pdev->dev; 160 + wdt->wdd.info = &qcom_wdt_info; 161 + wdt->wdd.ops = &qcom_wdt_ops; 162 + wdt->wdd.min_timeout = 1; 163 + wdt->wdd.max_timeout = 0x10000000U / wdt->rate; 164 + 165 + /* 166 + * If 'timeout-sec' unspecified in devicetree, assume a 30 second 167 + * default, unless the max timeout is less than 30 seconds, then use 168 + * the max instead. 169 + */ 170 + wdt->wdd.timeout = min(wdt->wdd.max_timeout, 30U); 171 + watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev); 172 + 173 + ret = watchdog_register_device(&wdt->wdd); 174 + if (ret) { 175 + dev_err(&pdev->dev, "failed to register watchdog\n"); 176 + goto err_clk_unprepare; 177 + } 178 + 179 + /* 180 + * WDT restart notifier has priority 0 (use as a last resort) 181 + */ 182 + wdt->restart_nb.notifier_call = qcom_wdt_restart; 183 + ret = register_restart_handler(&wdt->restart_nb); 184 + if (ret) 185 + dev_err(&pdev->dev, "failed to setup restart handler\n"); 186 + 187 + platform_set_drvdata(pdev, wdt); 188 + return 0; 189 + 190 + err_clk_unprepare: 191 + clk_disable_unprepare(wdt->clk); 192 + return ret; 193 + } 194 + 195 + static int qcom_wdt_remove(struct platform_device *pdev) 196 + { 197 + struct qcom_wdt *wdt = platform_get_drvdata(pdev); 198 + 199 + unregister_restart_handler(&wdt->restart_nb); 200 + watchdog_unregister_device(&wdt->wdd); 201 + clk_disable_unprepare(wdt->clk); 202 + return 0; 203 + } 204 + 205 + static const struct of_device_id qcom_wdt_of_table[] = { 206 + { .compatible = "qcom,kpss-wdt-msm8960", }, 207 + { .compatible = "qcom,kpss-wdt-apq8064", }, 208 + { .compatible = "qcom,kpss-wdt-ipq8064", }, 209 + { }, 210 + }; 211 + MODULE_DEVICE_TABLE(of, qcom_wdt_of_table); 212 + 213 + static struct platform_driver qcom_watchdog_driver = { 214 + .probe = qcom_wdt_probe, 215 + .remove = qcom_wdt_remove, 216 + .driver = { 217 + .name = KBUILD_MODNAME, 218 + .of_match_table = qcom_wdt_of_table, 219 + }, 220 + }; 221 + module_platform_driver(qcom_watchdog_driver); 222 + 223 + MODULE_DESCRIPTION("QCOM KPSS Watchdog Driver"); 224 + MODULE_LICENSE("GPL v2");
+198
drivers/watchdog/rn5t618_wdt.c
··· 1 + /* 2 + * Watchdog driver for Ricoh RN5T618 PMIC 3 + * 4 + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * version 2 as published by the Free Software Foundation. 9 + * 10 + * You should have received a copy of the GNU General Public License 11 + * along with this program. If not, see <http://www.gnu.org/licenses/>. 12 + */ 13 + 14 + #include <linux/device.h> 15 + #include <linux/mfd/rn5t618.h> 16 + #include <linux/module.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/watchdog.h> 19 + 20 + #define DRIVER_NAME "rn5t618-wdt" 21 + 22 + static bool nowayout = WATCHDOG_NOWAYOUT; 23 + static unsigned int timeout; 24 + 25 + module_param(timeout, uint, 0); 26 + MODULE_PARM_DESC(timeout, "Initial watchdog timeout in seconds"); 27 + 28 + module_param(nowayout, bool, 0); 29 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 30 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 31 + 32 + struct rn5t618_wdt { 33 + struct watchdog_device wdt_dev; 34 + struct rn5t618 *rn5t618; 35 + }; 36 + 37 + /* 38 + * This array encodes the values of WDOGTIM field for the supported 39 + * watchdog expiration times. If the watchdog is not accessed before 40 + * the timer expiration, the PMU generates an interrupt and if the CPU 41 + * doesn't clear it within one second the system is restarted. 42 + */ 43 + static const struct { 44 + u8 reg_val; 45 + unsigned int time; 46 + } rn5t618_wdt_map[] = { 47 + { 0, 1 }, 48 + { 1, 8 }, 49 + { 2, 32 }, 50 + { 3, 128 }, 51 + }; 52 + 53 + static int rn5t618_wdt_set_timeout(struct watchdog_device *wdt_dev, 54 + unsigned int t) 55 + { 56 + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); 57 + int ret, i; 58 + 59 + for (i = 0; i < ARRAY_SIZE(rn5t618_wdt_map); i++) { 60 + if (rn5t618_wdt_map[i].time + 1 >= t) 61 + break; 62 + } 63 + 64 + if (i == ARRAY_SIZE(rn5t618_wdt_map)) 65 + return -EINVAL; 66 + 67 + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, 68 + RN5T618_WATCHDOG_WDOGTIM_M, 69 + rn5t618_wdt_map[i].reg_val); 70 + if (!ret) 71 + wdt_dev->timeout = rn5t618_wdt_map[i].time; 72 + 73 + return ret; 74 + } 75 + 76 + static int rn5t618_wdt_start(struct watchdog_device *wdt_dev) 77 + { 78 + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); 79 + int ret; 80 + 81 + ret = rn5t618_wdt_set_timeout(wdt_dev, wdt_dev->timeout); 82 + if (ret) 83 + return ret; 84 + 85 + /* enable repower-on */ 86 + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_REPCNT, 87 + RN5T618_REPCNT_REPWRON, 88 + RN5T618_REPCNT_REPWRON); 89 + if (ret) 90 + return ret; 91 + 92 + /* enable watchdog */ 93 + ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, 94 + RN5T618_WATCHDOG_WDOGEN, 95 + RN5T618_WATCHDOG_WDOGEN); 96 + if (ret) 97 + return ret; 98 + 99 + /* enable watchdog interrupt */ 100 + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIREN, 101 + RN5T618_PWRIRQ_IR_WDOG, 102 + RN5T618_PWRIRQ_IR_WDOG); 103 + } 104 + 105 + static int rn5t618_wdt_stop(struct watchdog_device *wdt_dev) 106 + { 107 + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); 108 + 109 + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG, 110 + RN5T618_WATCHDOG_WDOGEN, 0); 111 + } 112 + 113 + static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev) 114 + { 115 + struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev); 116 + unsigned int val; 117 + int ret; 118 + 119 + /* The counter is restarted after a R/W access to watchdog register */ 120 + ret = regmap_read(wdt->rn5t618->regmap, RN5T618_WATCHDOG, &val); 121 + if (ret) 122 + return ret; 123 + 124 + ret = regmap_write(wdt->rn5t618->regmap, RN5T618_WATCHDOG, val); 125 + if (ret) 126 + return ret; 127 + 128 + /* Clear pending watchdog interrupt */ 129 + return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIRQ, 130 + RN5T618_PWRIRQ_IR_WDOG, 0); 131 + } 132 + 133 + static struct watchdog_info rn5t618_wdt_info = { 134 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | 135 + WDIOF_KEEPALIVEPING, 136 + .identity = DRIVER_NAME, 137 + }; 138 + 139 + static struct watchdog_ops rn5t618_wdt_ops = { 140 + .owner = THIS_MODULE, 141 + .start = rn5t618_wdt_start, 142 + .stop = rn5t618_wdt_stop, 143 + .ping = rn5t618_wdt_ping, 144 + .set_timeout = rn5t618_wdt_set_timeout, 145 + }; 146 + 147 + static int rn5t618_wdt_probe(struct platform_device *pdev) 148 + { 149 + struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent); 150 + struct rn5t618_wdt *wdt; 151 + int min_timeout, max_timeout; 152 + 153 + wdt = devm_kzalloc(&pdev->dev, sizeof(struct rn5t618_wdt), GFP_KERNEL); 154 + if (!wdt) 155 + return -ENOMEM; 156 + 157 + min_timeout = rn5t618_wdt_map[0].time; 158 + max_timeout = rn5t618_wdt_map[ARRAY_SIZE(rn5t618_wdt_map) - 1].time; 159 + 160 + wdt->rn5t618 = rn5t618; 161 + wdt->wdt_dev.info = &rn5t618_wdt_info; 162 + wdt->wdt_dev.ops = &rn5t618_wdt_ops; 163 + wdt->wdt_dev.min_timeout = min_timeout; 164 + wdt->wdt_dev.max_timeout = max_timeout; 165 + wdt->wdt_dev.timeout = max_timeout; 166 + wdt->wdt_dev.parent = &pdev->dev; 167 + 168 + watchdog_set_drvdata(&wdt->wdt_dev, wdt); 169 + watchdog_init_timeout(&wdt->wdt_dev, timeout, &pdev->dev); 170 + watchdog_set_nowayout(&wdt->wdt_dev, nowayout); 171 + 172 + platform_set_drvdata(pdev, wdt); 173 + 174 + return watchdog_register_device(&wdt->wdt_dev); 175 + } 176 + 177 + static int rn5t618_wdt_remove(struct platform_device *pdev) 178 + { 179 + struct rn5t618_wdt *wdt = platform_get_drvdata(pdev); 180 + 181 + watchdog_unregister_device(&wdt->wdt_dev); 182 + 183 + return 0; 184 + } 185 + 186 + static struct platform_driver rn5t618_wdt_driver = { 187 + .probe = rn5t618_wdt_probe, 188 + .remove = rn5t618_wdt_remove, 189 + .driver = { 190 + .name = DRIVER_NAME, 191 + }, 192 + }; 193 + 194 + module_platform_driver(rn5t618_wdt_driver); 195 + 196 + MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); 197 + MODULE_DESCRIPTION("RN5T618 watchdog driver"); 198 + MODULE_LICENSE("GPL v2");
+47
drivers/watchdog/s3c2410_wdt.c
··· 41 41 #include <linux/of.h> 42 42 #include <linux/mfd/syscon.h> 43 43 #include <linux/regmap.h> 44 + #include <linux/reboot.h> 45 + #include <linux/delay.h> 44 46 45 47 #define S3C2410_WTCON 0x00 46 48 #define S3C2410_WTDAT 0x04 ··· 130 128 unsigned long wtdat_save; 131 129 struct watchdog_device wdt_device; 132 130 struct notifier_block freq_transition; 131 + struct notifier_block restart_handler; 133 132 struct s3c2410_wdt_variant *drv_data; 134 133 struct regmap *pmureg; 135 134 }; ··· 158 155 .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, 159 156 }; 160 157 158 + static const struct s3c2410_wdt_variant drv_data_exynos7 = { 159 + .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, 160 + .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, 161 + .mask_bit = 0, 162 + .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, 163 + .rst_stat_bit = 23, /* A57 WDTRESET */ 164 + .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, 165 + }; 166 + 161 167 static const struct of_device_id s3c2410_wdt_match[] = { 162 168 { .compatible = "samsung,s3c2410-wdt", 163 169 .data = &drv_data_s3c2410 }, ··· 174 162 .data = &drv_data_exynos5250 }, 175 163 { .compatible = "samsung,exynos5420-wdt", 176 164 .data = &drv_data_exynos5420 }, 165 + { .compatible = "samsung,exynos7-wdt", 166 + .data = &drv_data_exynos7 }, 177 167 {}, 178 168 }; 179 169 MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); ··· 452 438 } 453 439 #endif 454 440 441 + static int s3c2410wdt_restart(struct notifier_block *this, 442 + unsigned long mode, void *cmd) 443 + { 444 + struct s3c2410_wdt *wdt = container_of(this, struct s3c2410_wdt, 445 + restart_handler); 446 + void __iomem *wdt_base = wdt->reg_base; 447 + 448 + /* disable watchdog, to be safe */ 449 + writel(0, wdt_base + S3C2410_WTCON); 450 + 451 + /* put initial values into count and data */ 452 + writel(0x80, wdt_base + S3C2410_WTCNT); 453 + writel(0x80, wdt_base + S3C2410_WTDAT); 454 + 455 + /* set the watchdog to go and reset... */ 456 + writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 | 457 + S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20), 458 + wdt_base + S3C2410_WTCON); 459 + 460 + /* wait for reset to assert... */ 461 + mdelay(500); 462 + 463 + return NOTIFY_DONE; 464 + } 465 + 455 466 static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) 456 467 { 457 468 unsigned int rst_stat; ··· 631 592 632 593 platform_set_drvdata(pdev, wdt); 633 594 595 + wdt->restart_handler.notifier_call = s3c2410wdt_restart; 596 + wdt->restart_handler.priority = 128; 597 + ret = register_restart_handler(&wdt->restart_handler); 598 + if (ret) 599 + pr_err("cannot register restart handler, %d\n", ret); 600 + 634 601 /* print out a statement of readiness */ 635 602 636 603 wtcon = readl(wdt->reg_base + S3C2410_WTCON); ··· 665 620 { 666 621 int ret; 667 622 struct s3c2410_wdt *wdt = platform_get_drvdata(dev); 623 + 624 + unregister_restart_handler(&wdt->restart_handler); 668 625 669 626 ret = s3c2410wdt_mask_and_disable_reset(wdt, true); 670 627 if (ret < 0)
+24
drivers/watchdog/stmp3xxx_rtc_wdt.c
··· 94 94 return 0; 95 95 } 96 96 97 + static int __maybe_unused stmp3xxx_wdt_suspend(struct device *dev) 98 + { 99 + struct watchdog_device *wdd = &stmp3xxx_wdd; 100 + 101 + if (watchdog_active(wdd)) 102 + return wdt_stop(wdd); 103 + 104 + return 0; 105 + } 106 + 107 + static int __maybe_unused stmp3xxx_wdt_resume(struct device *dev) 108 + { 109 + struct watchdog_device *wdd = &stmp3xxx_wdd; 110 + 111 + if (watchdog_active(wdd)) 112 + return wdt_start(wdd); 113 + 114 + return 0; 115 + } 116 + 117 + static SIMPLE_DEV_PM_OPS(stmp3xxx_wdt_pm_ops, 118 + stmp3xxx_wdt_suspend, stmp3xxx_wdt_resume); 119 + 97 120 static struct platform_driver stmp3xxx_wdt_driver = { 98 121 .driver = { 99 122 .name = "stmp3xxx_rtc_wdt", 123 + .pm = &stmp3xxx_wdt_pm_ops, 100 124 }, 101 125 .probe = stmp3xxx_wdt_probe, 102 126 .remove = stmp3xxx_wdt_remove,
+86 -25
drivers/watchdog/sunxi_wdt.c
··· 23 23 #include <linux/moduleparam.h> 24 24 #include <linux/notifier.h> 25 25 #include <linux/of.h> 26 + #include <linux/of_device.h> 26 27 #include <linux/platform_device.h> 27 28 #include <linux/reboot.h> 28 29 #include <linux/types.h> ··· 31 30 32 31 #define WDT_MAX_TIMEOUT 16 33 32 #define WDT_MIN_TIMEOUT 1 34 - #define WDT_MODE_TIMEOUT(n) ((n) << 3) 35 - #define WDT_TIMEOUT_MASK WDT_MODE_TIMEOUT(0x0F) 33 + #define WDT_TIMEOUT_MASK 0x0F 36 34 37 - #define WDT_CTRL 0x00 38 35 #define WDT_CTRL_RELOAD ((1 << 0) | (0x0a57 << 1)) 39 36 40 - #define WDT_MODE 0x04 41 37 #define WDT_MODE_EN (1 << 0) 42 - #define WDT_MODE_RST_EN (1 << 1) 43 38 44 39 #define DRV_NAME "sunxi-wdt" 45 40 #define DRV_VERSION "1.0" ··· 43 46 static bool nowayout = WATCHDOG_NOWAYOUT; 44 47 static unsigned int timeout = WDT_MAX_TIMEOUT; 45 48 49 + /* 50 + * This structure stores the register offsets for different variants 51 + * of Allwinner's watchdog hardware. 52 + */ 53 + struct sunxi_wdt_reg { 54 + u8 wdt_ctrl; 55 + u8 wdt_cfg; 56 + u8 wdt_mode; 57 + u8 wdt_timeout_shift; 58 + u8 wdt_reset_mask; 59 + u8 wdt_reset_val; 60 + }; 61 + 46 62 struct sunxi_wdt_dev { 47 63 struct watchdog_device wdt_dev; 48 64 void __iomem *wdt_base; 65 + const struct sunxi_wdt_reg *wdt_regs; 49 66 struct notifier_block restart_handler; 50 67 }; 51 68 52 69 /* 53 70 * wdt_timeout_map maps the watchdog timer interval value in seconds to 54 - * the value of the register WDT_MODE bit 3:6 71 + * the value of the register WDT_MODE at bits .wdt_timeout_shift ~ +3 55 72 * 56 73 * [timeout seconds] = register value 57 74 * ··· 93 82 struct sunxi_wdt_dev, 94 83 restart_handler); 95 84 void __iomem *wdt_base = sunxi_wdt->wdt_base; 85 + const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; 86 + u32 val; 96 87 97 - /* Enable timer and set reset bit in the watchdog */ 98 - writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE); 88 + /* Set system reset function */ 89 + val = readl(wdt_base + regs->wdt_cfg); 90 + val &= ~(regs->wdt_reset_mask); 91 + val |= regs->wdt_reset_val; 92 + writel(val, wdt_base + regs->wdt_cfg); 93 + 94 + /* Set lowest timeout and enable watchdog */ 95 + val = readl(wdt_base + regs->wdt_mode); 96 + val &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift); 97 + val |= WDT_MODE_EN; 98 + writel(val, wdt_base + regs->wdt_mode); 99 99 100 100 /* 101 101 * Restart the watchdog. The default (and lowest) interval 102 102 * value for the watchdog is 0.5s. 103 103 */ 104 - writel(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL); 104 + writel(WDT_CTRL_RELOAD, wdt_base + regs->wdt_ctrl); 105 105 106 106 while (1) { 107 107 mdelay(5); 108 - writel(WDT_MODE_EN | WDT_MODE_RST_EN, wdt_base + WDT_MODE); 108 + val = readl(wdt_base + regs->wdt_mode); 109 + val |= WDT_MODE_EN; 110 + writel(val, wdt_base + regs->wdt_mode); 109 111 } 110 112 return NOTIFY_DONE; 111 113 } ··· 127 103 { 128 104 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev); 129 105 void __iomem *wdt_base = sunxi_wdt->wdt_base; 106 + const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; 130 107 131 - iowrite32(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL); 108 + writel(WDT_CTRL_RELOAD, wdt_base + regs->wdt_ctrl); 132 109 133 110 return 0; 134 111 } ··· 139 114 { 140 115 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev); 141 116 void __iomem *wdt_base = sunxi_wdt->wdt_base; 117 + const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; 142 118 u32 reg; 143 119 144 120 if (wdt_timeout_map[timeout] == 0) ··· 147 121 148 122 sunxi_wdt->wdt_dev.timeout = timeout; 149 123 150 - reg = ioread32(wdt_base + WDT_MODE); 151 - reg &= ~WDT_TIMEOUT_MASK; 152 - reg |= WDT_MODE_TIMEOUT(wdt_timeout_map[timeout]); 153 - iowrite32(reg, wdt_base + WDT_MODE); 124 + reg = readl(wdt_base + regs->wdt_mode); 125 + reg &= ~(WDT_TIMEOUT_MASK << regs->wdt_timeout_shift); 126 + reg |= wdt_timeout_map[timeout] << regs->wdt_timeout_shift; 127 + writel(reg, wdt_base + regs->wdt_mode); 154 128 155 129 sunxi_wdt_ping(wdt_dev); 156 130 ··· 161 135 { 162 136 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev); 163 137 void __iomem *wdt_base = sunxi_wdt->wdt_base; 138 + const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; 164 139 165 - iowrite32(0, wdt_base + WDT_MODE); 140 + writel(0, wdt_base + regs->wdt_mode); 166 141 167 142 return 0; 168 143 } ··· 173 146 u32 reg; 174 147 struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev); 175 148 void __iomem *wdt_base = sunxi_wdt->wdt_base; 149 + const struct sunxi_wdt_reg *regs = sunxi_wdt->wdt_regs; 176 150 int ret; 177 151 178 152 ret = sunxi_wdt_set_timeout(&sunxi_wdt->wdt_dev, ··· 181 153 if (ret < 0) 182 154 return ret; 183 155 184 - reg = ioread32(wdt_base + WDT_MODE); 185 - reg |= (WDT_MODE_RST_EN | WDT_MODE_EN); 186 - iowrite32(reg, wdt_base + WDT_MODE); 156 + /* Set system reset function */ 157 + reg = readl(wdt_base + regs->wdt_cfg); 158 + reg &= ~(regs->wdt_reset_mask); 159 + reg |= ~(regs->wdt_reset_val); 160 + writel(reg, wdt_base + regs->wdt_cfg); 161 + 162 + /* Enable watchdog */ 163 + reg = readl(wdt_base + regs->wdt_mode); 164 + reg |= WDT_MODE_EN; 165 + writel(reg, wdt_base + regs->wdt_mode); 187 166 188 167 return 0; 189 168 } ··· 210 175 .set_timeout = sunxi_wdt_set_timeout, 211 176 }; 212 177 178 + static const struct sunxi_wdt_reg sun4i_wdt_reg = { 179 + .wdt_ctrl = 0x00, 180 + .wdt_cfg = 0x04, 181 + .wdt_mode = 0x04, 182 + .wdt_timeout_shift = 3, 183 + .wdt_reset_mask = 0x02, 184 + .wdt_reset_val = 0x02, 185 + }; 186 + 187 + static const struct sunxi_wdt_reg sun6i_wdt_reg = { 188 + .wdt_ctrl = 0x10, 189 + .wdt_cfg = 0x14, 190 + .wdt_mode = 0x18, 191 + .wdt_timeout_shift = 4, 192 + .wdt_reset_mask = 0x03, 193 + .wdt_reset_val = 0x01, 194 + }; 195 + 196 + static const struct of_device_id sunxi_wdt_dt_ids[] = { 197 + { .compatible = "allwinner,sun4i-a10-wdt", .data = &sun4i_wdt_reg }, 198 + { .compatible = "allwinner,sun6i-a31-wdt", .data = &sun6i_wdt_reg }, 199 + { /* sentinel */ } 200 + }; 201 + MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids); 202 + 213 203 static int sunxi_wdt_probe(struct platform_device *pdev) 214 204 { 215 205 struct sunxi_wdt_dev *sunxi_wdt; 206 + const struct of_device_id *device; 216 207 struct resource *res; 217 208 int err; 218 209 ··· 247 186 return -EINVAL; 248 187 249 188 platform_set_drvdata(pdev, sunxi_wdt); 189 + 190 + device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev); 191 + if (!device) 192 + return -ENODEV; 193 + 194 + sunxi_wdt->wdt_regs = device->data; 250 195 251 196 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 252 197 sunxi_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); ··· 308 241 309 242 sunxi_wdt_stop(&sunxi_wdt->wdt_dev); 310 243 } 311 - 312 - static const struct of_device_id sunxi_wdt_dt_ids[] = { 313 - { .compatible = "allwinner,sun4i-a10-wdt" }, 314 - { /* sentinel */ } 315 - }; 316 - MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids); 317 244 318 245 static struct platform_driver sunxi_wdt_driver = { 319 246 .probe = sunxi_wdt_probe,
+1 -5
drivers/watchdog/ts72xx_wdt.c
··· 428 428 429 429 static int ts72xx_wdt_remove(struct platform_device *pdev) 430 430 { 431 - int error; 432 - 433 - error = misc_deregister(&ts72xx_wdt_miscdev); 434 - 435 - return error; 431 + return misc_deregister(&ts72xx_wdt_miscdev); 436 432 } 437 433 438 434 static struct platform_driver ts72xx_wdt_driver = {
+2 -7
include/linux/watchdog.h
··· 97 97 #define WDOG_UNREGISTERED 4 /* Has the device been unregistered */ 98 98 }; 99 99 100 - #ifdef CONFIG_WATCHDOG_NOWAYOUT 101 - #define WATCHDOG_NOWAYOUT 1 102 - #define WATCHDOG_NOWAYOUT_INIT_STATUS (1 << WDOG_NO_WAY_OUT) 103 - #else 104 - #define WATCHDOG_NOWAYOUT 0 105 - #define WATCHDOG_NOWAYOUT_INIT_STATUS 0 106 - #endif 100 + #define WATCHDOG_NOWAYOUT IS_BUILTIN(CONFIG_WATCHDOG_NOWAYOUT) 101 + #define WATCHDOG_NOWAYOUT_INIT_STATUS (WATCHDOG_NOWAYOUT << WDOG_NO_WAY_OUT) 107 102 108 103 /* Use the following function to check whether or not the watchdog is active */ 109 104 static inline bool watchdog_active(struct watchdog_device *wdd)