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

watchdog: add ralink watchdog driver

Add a driver for the watchdog timer found on Ralink SoC

Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Cc: linux-watchdog@vger.kernel.org
Cc: linux-mips@linux-mips.org
Cc: devicetree-discuss@lists.ozlabs.org

authored by

John Crispin and committed by
Wim Van Sebroeck
473cf939 e14538e0

+235
+19
Documentation/devicetree/bindings/watchdog/rt2880-wdt.txt
··· 1 + Ralink Watchdog Timers 2 + 3 + Required properties: 4 + - compatible: must be "ralink,rt2880-wdt" 5 + - reg: physical base address of the controller and length of the register range 6 + 7 + Optional properties: 8 + - interrupt-parent: phandle to the INTC device node 9 + - interrupts: Specify the INTC interrupt number 10 + 11 + Example: 12 + 13 + watchdog@120 { 14 + compatible = "ralink,rt2880-wdt"; 15 + reg = <0x120 0x10>; 16 + 17 + interrupt-parent = <&intc>; 18 + interrupts = <1>; 19 + };
+7
drivers/watchdog/Kconfig
··· 1135 1135 help 1136 1136 Hardware driver for the Lantiq SoC Watchdog Timer. 1137 1137 1138 + config RALINK_WDT 1139 + tristate "Ralink SoC watchdog" 1140 + select WATCHDOG_CORE 1141 + depends on RALINK 1142 + help 1143 + Hardware driver for the Ralink SoC Watchdog Timer. 1144 + 1138 1145 # PARISC Architecture 1139 1146 1140 1147 # POWERPC Architecture
+1
drivers/watchdog/Makefile
··· 135 135 obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o 136 136 octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o 137 137 obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o 138 + obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o 138 139 139 140 # PARISC Architecture 140 141
+208
drivers/watchdog/rt2880_wdt.c
··· 1 + /* 2 + * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer 3 + * 4 + * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 5 + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> 6 + * 7 + * This driver was based on: drivers/watchdog/softdog.c 8 + * 9 + * This program is free software; you can redistribute it and/or modify it 10 + * under the terms of the GNU General Public License version 2 as published 11 + * by the Free Software Foundation. 12 + */ 13 + 14 + #include <linux/clk.h> 15 + #include <linux/reset.h> 16 + #include <linux/module.h> 17 + #include <linux/kernel.h> 18 + #include <linux/watchdog.h> 19 + #include <linux/miscdevice.h> 20 + #include <linux/moduleparam.h> 21 + #include <linux/platform_device.h> 22 + 23 + #include <asm/mach-ralink/ralink_regs.h> 24 + 25 + #define SYSC_RSTSTAT 0x38 26 + #define WDT_RST_CAUSE BIT(1) 27 + 28 + #define RALINK_WDT_TIMEOUT 30 29 + #define RALINK_WDT_PRESCALE 65536 30 + 31 + #define TIMER_REG_TMR1LOAD 0x00 32 + #define TIMER_REG_TMR1CTL 0x08 33 + 34 + #define TMRSTAT_TMR1RST BIT(5) 35 + 36 + #define TMR1CTL_ENABLE BIT(7) 37 + #define TMR1CTL_MODE_SHIFT 4 38 + #define TMR1CTL_MODE_MASK 0x3 39 + #define TMR1CTL_MODE_FREE_RUNNING 0x0 40 + #define TMR1CTL_MODE_PERIODIC 0x1 41 + #define TMR1CTL_MODE_TIMEOUT 0x2 42 + #define TMR1CTL_MODE_WDT 0x3 43 + #define TMR1CTL_PRESCALE_MASK 0xf 44 + #define TMR1CTL_PRESCALE_65536 0xf 45 + 46 + static struct clk *rt288x_wdt_clk; 47 + static unsigned long rt288x_wdt_freq; 48 + static void __iomem *rt288x_wdt_base; 49 + 50 + static bool nowayout = WATCHDOG_NOWAYOUT; 51 + module_param(nowayout, bool, 0); 52 + MODULE_PARM_DESC(nowayout, 53 + "Watchdog cannot be stopped once started (default=" 54 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 55 + 56 + static inline void rt_wdt_w32(unsigned reg, u32 val) 57 + { 58 + iowrite32(val, rt288x_wdt_base + reg); 59 + } 60 + 61 + static inline u32 rt_wdt_r32(unsigned reg) 62 + { 63 + return ioread32(rt288x_wdt_base + reg); 64 + } 65 + 66 + static int rt288x_wdt_ping(struct watchdog_device *w) 67 + { 68 + rt_wdt_w32(TIMER_REG_TMR1LOAD, w->timeout * rt288x_wdt_freq); 69 + 70 + return 0; 71 + } 72 + 73 + static int rt288x_wdt_start(struct watchdog_device *w) 74 + { 75 + u32 t; 76 + 77 + t = rt_wdt_r32(TIMER_REG_TMR1CTL); 78 + t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT | 79 + TMR1CTL_PRESCALE_MASK); 80 + t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT | 81 + TMR1CTL_PRESCALE_65536); 82 + rt_wdt_w32(TIMER_REG_TMR1CTL, t); 83 + 84 + rt288x_wdt_ping(w); 85 + 86 + t = rt_wdt_r32(TIMER_REG_TMR1CTL); 87 + t |= TMR1CTL_ENABLE; 88 + rt_wdt_w32(TIMER_REG_TMR1CTL, t); 89 + 90 + return 0; 91 + } 92 + 93 + static int rt288x_wdt_stop(struct watchdog_device *w) 94 + { 95 + u32 t; 96 + 97 + rt288x_wdt_ping(w); 98 + 99 + t = rt_wdt_r32(TIMER_REG_TMR1CTL); 100 + t &= ~TMR1CTL_ENABLE; 101 + rt_wdt_w32(TIMER_REG_TMR1CTL, t); 102 + 103 + return 0; 104 + } 105 + 106 + static int rt288x_wdt_set_timeout(struct watchdog_device *w, unsigned int t) 107 + { 108 + w->timeout = t; 109 + rt288x_wdt_ping(w); 110 + 111 + return 0; 112 + } 113 + 114 + static int rt288x_wdt_bootcause(void) 115 + { 116 + if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) 117 + return WDIOF_CARDRESET; 118 + 119 + return 0; 120 + } 121 + 122 + static struct watchdog_info rt288x_wdt_info = { 123 + .identity = "Ralink Watchdog", 124 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 125 + }; 126 + 127 + static struct watchdog_ops rt288x_wdt_ops = { 128 + .owner = THIS_MODULE, 129 + .start = rt288x_wdt_start, 130 + .stop = rt288x_wdt_stop, 131 + .ping = rt288x_wdt_ping, 132 + .set_timeout = rt288x_wdt_set_timeout, 133 + }; 134 + 135 + static struct watchdog_device rt288x_wdt_dev = { 136 + .info = &rt288x_wdt_info, 137 + .ops = &rt288x_wdt_ops, 138 + .min_timeout = 1, 139 + }; 140 + 141 + static int rt288x_wdt_probe(struct platform_device *pdev) 142 + { 143 + struct resource *res; 144 + int ret; 145 + 146 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 147 + rt288x_wdt_base = devm_request_and_ioremap(&pdev->dev, res); 148 + if (IS_ERR(rt288x_wdt_base)) 149 + return PTR_ERR(rt288x_wdt_base); 150 + 151 + rt288x_wdt_clk = devm_clk_get(&pdev->dev, NULL); 152 + if (IS_ERR(rt288x_wdt_clk)) 153 + return PTR_ERR(rt288x_wdt_clk); 154 + 155 + device_reset(&pdev->dev); 156 + 157 + rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; 158 + 159 + rt288x_wdt_dev.dev = &pdev->dev; 160 + rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); 161 + 162 + rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); 163 + rt288x_wdt_dev.timeout = rt288x_wdt_dev.max_timeout; 164 + 165 + watchdog_set_nowayout(&rt288x_wdt_dev, nowayout); 166 + 167 + ret = watchdog_register_device(&rt288x_wdt_dev); 168 + if (!ret) 169 + dev_info(&pdev->dev, "Initialized\n"); 170 + 171 + return 0; 172 + } 173 + 174 + static int rt288x_wdt_remove(struct platform_device *pdev) 175 + { 176 + watchdog_unregister_device(&rt288x_wdt_dev); 177 + 178 + return 0; 179 + } 180 + 181 + static void rt288x_wdt_shutdown(struct platform_device *pdev) 182 + { 183 + rt288x_wdt_stop(&rt288x_wdt_dev); 184 + } 185 + 186 + static const struct of_device_id rt288x_wdt_match[] = { 187 + { .compatible = "ralink,rt2880-wdt" }, 188 + {}, 189 + }; 190 + MODULE_DEVICE_TABLE(of, rt288x_wdt_match); 191 + 192 + static struct platform_driver rt288x_wdt_driver = { 193 + .probe = rt288x_wdt_probe, 194 + .remove = rt288x_wdt_remove, 195 + .shutdown = rt288x_wdt_shutdown, 196 + .driver = { 197 + .name = KBUILD_MODNAME, 198 + .owner = THIS_MODULE, 199 + .of_match_table = rt288x_wdt_match, 200 + }, 201 + }; 202 + 203 + module_platform_driver(rt288x_wdt_driver); 204 + 205 + MODULE_DESCRIPTION("MediaTek/Ralink RT288x/RT3xxx hardware watchdog driver"); 206 + MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); 207 + MODULE_LICENSE("GPL v2"); 208 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);