1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer 4 * 5 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 6 * Copyright (C) 2013 John Crispin <john@phrozen.org> 7 * 8 * This driver was based on: drivers/watchdog/softdog.c 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/reset.h> 13 #include <linux/module.h> 14 #include <linux/kernel.h> 15 #include <linux/watchdog.h> 16 #include <linux/moduleparam.h> 17 #include <linux/platform_device.h> 18 #include <linux/mod_devicetable.h> 19 20 #include <asm/mach-ralink/ralink_regs.h> 21 22 #define SYSC_RSTSTAT 0x38 23 #define WDT_RST_CAUSE BIT(1) 24 25 #define RALINK_WDT_TIMEOUT 30 26 #define RALINK_WDT_PRESCALE 65536 27 28 #define TIMER_REG_TMR1LOAD 0x00 29 #define TIMER_REG_TMR1CTL 0x08 30 31 #define TMRSTAT_TMR1RST BIT(5) 32 33 #define TMR1CTL_ENABLE BIT(7) 34 #define TMR1CTL_MODE_SHIFT 4 35 #define TMR1CTL_MODE_MASK 0x3 36 #define TMR1CTL_MODE_FREE_RUNNING 0x0 37 #define TMR1CTL_MODE_PERIODIC 0x1 38 #define TMR1CTL_MODE_TIMEOUT 0x2 39 #define TMR1CTL_MODE_WDT 0x3 40 #define TMR1CTL_PRESCALE_MASK 0xf 41 #define TMR1CTL_PRESCALE_65536 0xf 42 43 struct rt2880_wdt_data { 44 void __iomem *base; 45 unsigned long freq; 46 struct clk *clk; 47 struct reset_control *rst; 48 struct watchdog_device wdt; 49 }; 50 51 static bool nowayout = WATCHDOG_NOWAYOUT; 52 module_param(nowayout, bool, 0); 53 MODULE_PARM_DESC(nowayout, 54 "Watchdog cannot be stopped once started (default=" 55 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 56 57 static inline void rt_wdt_w32(void __iomem *base, unsigned int reg, u32 val) 58 { 59 iowrite32(val, base + reg); 60 } 61 62 static inline u32 rt_wdt_r32(void __iomem *base, unsigned int reg) 63 { 64 return ioread32(base + reg); 65 } 66 67 static int rt288x_wdt_ping(struct watchdog_device *w) 68 { 69 struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w); 70 71 rt_wdt_w32(drvdata->base, TIMER_REG_TMR1LOAD, w->timeout * drvdata->freq); 72 73 return 0; 74 } 75 76 static int rt288x_wdt_start(struct watchdog_device *w) 77 { 78 struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w); 79 u32 t; 80 81 t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL); 82 t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT | 83 TMR1CTL_PRESCALE_MASK); 84 t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT | 85 TMR1CTL_PRESCALE_65536); 86 rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t); 87 88 rt288x_wdt_ping(w); 89 90 t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL); 91 t |= TMR1CTL_ENABLE; 92 rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t); 93 94 return 0; 95 } 96 97 static int rt288x_wdt_stop(struct watchdog_device *w) 98 { 99 struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w); 100 u32 t; 101 102 rt288x_wdt_ping(w); 103 104 t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL); 105 t &= ~TMR1CTL_ENABLE; 106 rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t); 107 108 return 0; 109 } 110 111 static int rt288x_wdt_set_timeout(struct watchdog_device *w, unsigned int t) 112 { 113 w->timeout = t; 114 rt288x_wdt_ping(w); 115 116 return 0; 117 } 118 119 static int rt288x_wdt_bootcause(void) 120 { 121 if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) 122 return WDIOF_CARDRESET; 123 124 return 0; 125 } 126 127 static const struct watchdog_info rt288x_wdt_info = { 128 .identity = "Ralink Watchdog", 129 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 130 }; 131 132 static const struct watchdog_ops rt288x_wdt_ops = { 133 .owner = THIS_MODULE, 134 .start = rt288x_wdt_start, 135 .stop = rt288x_wdt_stop, 136 .ping = rt288x_wdt_ping, 137 .set_timeout = rt288x_wdt_set_timeout, 138 }; 139 140 static int rt288x_wdt_probe(struct platform_device *pdev) 141 { 142 struct device *dev = &pdev->dev; 143 struct watchdog_device *wdt; 144 struct rt2880_wdt_data *drvdata; 145 int ret; 146 147 drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); 148 if (!drvdata) 149 return -ENOMEM; 150 151 drvdata->base = devm_platform_ioremap_resource(pdev, 0); 152 if (IS_ERR(drvdata->base)) 153 return PTR_ERR(drvdata->base); 154 155 drvdata->clk = devm_clk_get(dev, NULL); 156 if (IS_ERR(drvdata->clk)) 157 return PTR_ERR(drvdata->clk); 158 159 drvdata->rst = devm_reset_control_get_exclusive(dev, NULL); 160 if (!IS_ERR(drvdata->rst)) 161 reset_control_deassert(drvdata->rst); 162 163 drvdata->freq = clk_get_rate(drvdata->clk) / RALINK_WDT_PRESCALE; 164 165 wdt = &drvdata->wdt; 166 wdt->info = &rt288x_wdt_info; 167 wdt->ops = &rt288x_wdt_ops; 168 wdt->min_timeout = 1; 169 wdt->max_timeout = (0xfffful / drvdata->freq); 170 wdt->parent = dev; 171 wdt->bootstatus = rt288x_wdt_bootcause(); 172 173 watchdog_init_timeout(wdt, wdt->max_timeout, dev); 174 watchdog_set_nowayout(wdt, nowayout); 175 watchdog_set_drvdata(wdt, drvdata); 176 177 watchdog_stop_on_reboot(wdt); 178 ret = devm_watchdog_register_device(dev, &drvdata->wdt); 179 if (!ret) 180 dev_info(dev, "Initialized\n"); 181 182 return 0; 183 } 184 185 static const struct of_device_id rt288x_wdt_match[] = { 186 { .compatible = "ralink,rt2880-wdt" }, 187 {}, 188 }; 189 MODULE_DEVICE_TABLE(of, rt288x_wdt_match); 190 191 static struct platform_driver rt288x_wdt_driver = { 192 .probe = rt288x_wdt_probe, 193 .driver = { 194 .name = KBUILD_MODNAME, 195 .of_match_table = rt288x_wdt_match, 196 }, 197 }; 198 199 module_platform_driver(rt288x_wdt_driver); 200 201 MODULE_DESCRIPTION("MediaTek/Ralink RT288x/RT3xxx hardware watchdog driver"); 202 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); 203 MODULE_LICENSE("GPL v2"); 204