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

watchdog: add rza_wdt driver

Adds a watchdog timer driver for the Renesas RZ/A Series SoCs. A reset
handler is also included since a WDT overflow is the only method for
restarting an RZ/A SoC.

Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Chris Brandt and committed by
Wim Van Sebroeck
aea24187 5dca80f6

+208
+8
drivers/watchdog/Kconfig
··· 721 721 This driver adds watchdog support for the integrated watchdogs in the 722 722 Renesas R-Car and other SH-Mobile SoCs (usually named RWDT or SWDT). 723 723 724 + config RENESAS_RZAWDT 725 + tristate "Renesas RZ/A WDT Watchdog" 726 + depends on ARCH_RENESAS || COMPILE_TEST 727 + select WATCHDOG_CORE 728 + help 729 + This driver adds watchdog support for the integrated watchdogs in the 730 + Renesas RZ/A SoCs. These watchdogs can be used to reset a system. 731 + 724 732 config ASPEED_WATCHDOG 725 733 tristate "Aspeed 2400 watchdog support" 726 734 depends on ARCH_ASPEED || COMPILE_TEST
+1
drivers/watchdog/Makefile
··· 82 82 obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o 83 83 obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o 84 84 obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o 85 + obj-$(CONFIG_RENESAS_RZAWDT) += rza_wdt.o 85 86 obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o 86 87 obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o 87 88
+199
drivers/watchdog/rza_wdt.c
··· 1 + /* 2 + * Renesas RZ/A Series WDT Driver 3 + * 4 + * Copyright (C) 2017 Renesas Electronics America, Inc. 5 + * Copyright (C) 2017 Chris Brandt 6 + * 7 + * This file is subject to the terms and conditions of the GNU General Public 8 + * License. See the file "COPYING" in the main directory of this archive 9 + * for more details. 10 + */ 11 + 12 + #include <linux/bitops.h> 13 + #include <linux/clk.h> 14 + #include <linux/delay.h> 15 + #include <linux/module.h> 16 + #include <linux/of_address.h> 17 + #include <linux/platform_device.h> 18 + #include <linux/watchdog.h> 19 + 20 + #define DEFAULT_TIMEOUT 30 21 + 22 + /* Watchdog Timer Registers */ 23 + #define WTCSR 0 24 + #define WTCSR_MAGIC 0xA500 25 + #define WTSCR_WT BIT(6) 26 + #define WTSCR_TME BIT(5) 27 + #define WTSCR_CKS(i) (i) 28 + 29 + #define WTCNT 2 30 + #define WTCNT_MAGIC 0x5A00 31 + 32 + #define WRCSR 4 33 + #define WRCSR_MAGIC 0x5A00 34 + #define WRCSR_RSTE BIT(6) 35 + #define WRCSR_CLEAR_WOVF 0xA500 /* special value */ 36 + 37 + struct rza_wdt { 38 + struct watchdog_device wdev; 39 + void __iomem *base; 40 + struct clk *clk; 41 + }; 42 + 43 + static int rza_wdt_start(struct watchdog_device *wdev) 44 + { 45 + struct rza_wdt *priv = watchdog_get_drvdata(wdev); 46 + 47 + /* Stop timer */ 48 + writew(WTCSR_MAGIC | 0, priv->base + WTCSR); 49 + 50 + /* Must dummy read WRCSR:WOVF at least once before clearing */ 51 + readb(priv->base + WRCSR); 52 + writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR); 53 + 54 + /* 55 + * Start timer with slowest clock source and reset option enabled. 56 + */ 57 + writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR); 58 + writew(WTCNT_MAGIC | 0, priv->base + WTCNT); 59 + writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | WTSCR_CKS(7), 60 + priv->base + WTCSR); 61 + 62 + return 0; 63 + } 64 + 65 + static int rza_wdt_stop(struct watchdog_device *wdev) 66 + { 67 + struct rza_wdt *priv = watchdog_get_drvdata(wdev); 68 + 69 + writew(WTCSR_MAGIC | 0, priv->base + WTCSR); 70 + 71 + return 0; 72 + } 73 + 74 + static int rza_wdt_ping(struct watchdog_device *wdev) 75 + { 76 + struct rza_wdt *priv = watchdog_get_drvdata(wdev); 77 + 78 + writew(WTCNT_MAGIC | 0, priv->base + WTCNT); 79 + 80 + return 0; 81 + } 82 + 83 + static int rza_wdt_restart(struct watchdog_device *wdev, unsigned long action, 84 + void *data) 85 + { 86 + struct rza_wdt *priv = watchdog_get_drvdata(wdev); 87 + 88 + /* Stop timer */ 89 + writew(WTCSR_MAGIC | 0, priv->base + WTCSR); 90 + 91 + /* Must dummy read WRCSR:WOVF at least once before clearing */ 92 + readb(priv->base + WRCSR); 93 + writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR); 94 + 95 + /* 96 + * Start timer with fastest clock source and only 1 clock left before 97 + * overflow with reset option enabled. 98 + */ 99 + writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR); 100 + writew(WTCNT_MAGIC | 255, priv->base + WTCNT); 101 + writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME, priv->base + WTCSR); 102 + 103 + /* 104 + * Actually make sure the above sequence hits hardware before sleeping. 105 + */ 106 + wmb(); 107 + 108 + /* Wait for WDT overflow (reset) */ 109 + udelay(20); 110 + 111 + return 0; 112 + } 113 + 114 + static const struct watchdog_info rza_wdt_ident = { 115 + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, 116 + .identity = "Renesas RZ/A WDT Watchdog", 117 + }; 118 + 119 + static const struct watchdog_ops rza_wdt_ops = { 120 + .owner = THIS_MODULE, 121 + .start = rza_wdt_start, 122 + .stop = rza_wdt_stop, 123 + .ping = rza_wdt_ping, 124 + .restart = rza_wdt_restart, 125 + }; 126 + 127 + static int rza_wdt_probe(struct platform_device *pdev) 128 + { 129 + struct rza_wdt *priv; 130 + struct resource *res; 131 + unsigned long rate; 132 + int ret; 133 + 134 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 135 + if (!priv) 136 + return -ENOMEM; 137 + 138 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 139 + priv->base = devm_ioremap_resource(&pdev->dev, res); 140 + if (IS_ERR(priv->base)) 141 + return PTR_ERR(priv->base); 142 + 143 + priv->clk = devm_clk_get(&pdev->dev, NULL); 144 + if (IS_ERR(priv->clk)) 145 + return PTR_ERR(priv->clk); 146 + 147 + rate = clk_get_rate(priv->clk); 148 + if (rate < 16384) { 149 + dev_err(&pdev->dev, "invalid clock rate (%ld)\n", rate); 150 + return -ENOENT; 151 + } 152 + 153 + /* Assume slowest clock rate possible (CKS=7) */ 154 + rate /= 16384; 155 + 156 + priv->wdev.info = &rza_wdt_ident, 157 + priv->wdev.ops = &rza_wdt_ops, 158 + priv->wdev.parent = &pdev->dev; 159 + 160 + /* 161 + * Since the max possible timeout of our 8-bit count register is less 162 + * than a second, we must use max_hw_heartbeat_ms. 163 + */ 164 + priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate; 165 + dev_dbg(&pdev->dev, "max hw timeout of %dms\n", 166 + priv->wdev.max_hw_heartbeat_ms); 167 + 168 + priv->wdev.min_timeout = 1; 169 + priv->wdev.timeout = DEFAULT_TIMEOUT; 170 + 171 + watchdog_init_timeout(&priv->wdev, 0, &pdev->dev); 172 + watchdog_set_drvdata(&priv->wdev, priv); 173 + 174 + ret = devm_watchdog_register_device(&pdev->dev, &priv->wdev); 175 + if (ret) 176 + dev_err(&pdev->dev, "Cannot register watchdog device\n"); 177 + 178 + return ret; 179 + } 180 + 181 + static const struct of_device_id rza_wdt_of_match[] = { 182 + { .compatible = "renesas,rza-wdt", }, 183 + { /* sentinel */ } 184 + }; 185 + MODULE_DEVICE_TABLE(of, rza_wdt_of_match); 186 + 187 + static struct platform_driver rza_wdt_driver = { 188 + .probe = rza_wdt_probe, 189 + .driver = { 190 + .name = "rza_wdt", 191 + .of_match_table = rza_wdt_of_match, 192 + }, 193 + }; 194 + 195 + module_platform_driver(rza_wdt_driver); 196 + 197 + MODULE_DESCRIPTION("Renesas RZ/A WDT Driver"); 198 + MODULE_AUTHOR("Chris Brandt <chris.brandt@renesas.com>"); 199 + MODULE_LICENSE("GPL v2");