mt7621_wdt.c (4633B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Ralink MT7621/MT7628 built-in hardware watchdog timer 4 * 5 * Copyright (C) 2014 John Crispin <john@phrozen.org> 6 * 7 * This driver was based on: drivers/watchdog/rt2880_wdt.c 8 */ 9 10#include <linux/clk.h> 11#include <linux/reset.h> 12#include <linux/module.h> 13#include <linux/kernel.h> 14#include <linux/watchdog.h> 15#include <linux/moduleparam.h> 16#include <linux/platform_device.h> 17#include <linux/mod_devicetable.h> 18 19#include <asm/mach-ralink/ralink_regs.h> 20 21#define SYSC_RSTSTAT 0x38 22#define WDT_RST_CAUSE BIT(1) 23 24#define RALINK_WDT_TIMEOUT 30 25 26#define TIMER_REG_TMRSTAT 0x00 27#define TIMER_REG_TMR1LOAD 0x24 28#define TIMER_REG_TMR1CTL 0x20 29 30#define TMR1CTL_ENABLE BIT(7) 31#define TMR1CTL_RESTART BIT(9) 32#define TMR1CTL_PRESCALE_SHIFT 16 33 34static void __iomem *mt7621_wdt_base; 35static struct reset_control *mt7621_wdt_reset; 36 37static bool nowayout = WATCHDOG_NOWAYOUT; 38module_param(nowayout, bool, 0); 39MODULE_PARM_DESC(nowayout, 40 "Watchdog cannot be stopped once started (default=" 41 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 42 43static inline void rt_wdt_w32(unsigned reg, u32 val) 44{ 45 iowrite32(val, mt7621_wdt_base + reg); 46} 47 48static inline u32 rt_wdt_r32(unsigned reg) 49{ 50 return ioread32(mt7621_wdt_base + reg); 51} 52 53static int mt7621_wdt_ping(struct watchdog_device *w) 54{ 55 rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART); 56 57 return 0; 58} 59 60static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t) 61{ 62 w->timeout = t; 63 rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000); 64 mt7621_wdt_ping(w); 65 66 return 0; 67} 68 69static int mt7621_wdt_start(struct watchdog_device *w) 70{ 71 u32 t; 72 73 /* set the prescaler to 1ms == 1000us */ 74 rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT); 75 76 mt7621_wdt_set_timeout(w, w->timeout); 77 78 t = rt_wdt_r32(TIMER_REG_TMR1CTL); 79 t |= TMR1CTL_ENABLE; 80 rt_wdt_w32(TIMER_REG_TMR1CTL, t); 81 82 return 0; 83} 84 85static int mt7621_wdt_stop(struct watchdog_device *w) 86{ 87 u32 t; 88 89 mt7621_wdt_ping(w); 90 91 t = rt_wdt_r32(TIMER_REG_TMR1CTL); 92 t &= ~TMR1CTL_ENABLE; 93 rt_wdt_w32(TIMER_REG_TMR1CTL, t); 94 95 return 0; 96} 97 98static int mt7621_wdt_bootcause(void) 99{ 100 if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) 101 return WDIOF_CARDRESET; 102 103 return 0; 104} 105 106static int mt7621_wdt_is_running(struct watchdog_device *w) 107{ 108 return !!(rt_wdt_r32(TIMER_REG_TMR1CTL) & TMR1CTL_ENABLE); 109} 110 111static const struct watchdog_info mt7621_wdt_info = { 112 .identity = "Mediatek Watchdog", 113 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 114}; 115 116static const struct watchdog_ops mt7621_wdt_ops = { 117 .owner = THIS_MODULE, 118 .start = mt7621_wdt_start, 119 .stop = mt7621_wdt_stop, 120 .ping = mt7621_wdt_ping, 121 .set_timeout = mt7621_wdt_set_timeout, 122}; 123 124static struct watchdog_device mt7621_wdt_dev = { 125 .info = &mt7621_wdt_info, 126 .ops = &mt7621_wdt_ops, 127 .min_timeout = 1, 128 .max_timeout = 0xfffful / 1000, 129}; 130 131static int mt7621_wdt_probe(struct platform_device *pdev) 132{ 133 struct device *dev = &pdev->dev; 134 mt7621_wdt_base = devm_platform_ioremap_resource(pdev, 0); 135 if (IS_ERR(mt7621_wdt_base)) 136 return PTR_ERR(mt7621_wdt_base); 137 138 mt7621_wdt_reset = devm_reset_control_get_exclusive(dev, NULL); 139 if (!IS_ERR(mt7621_wdt_reset)) 140 reset_control_deassert(mt7621_wdt_reset); 141 142 mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause(); 143 144 watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout, 145 dev); 146 watchdog_set_nowayout(&mt7621_wdt_dev, nowayout); 147 if (mt7621_wdt_is_running(&mt7621_wdt_dev)) { 148 /* 149 * Make sure to apply timeout from watchdog core, taking 150 * the prescaler of this driver here into account (the 151 * boot loader might be using a different prescaler). 152 * 153 * To avoid spurious resets because of different scaling, 154 * we first disable the watchdog, set the new prescaler 155 * and timeout, and then re-enable the watchdog. 156 */ 157 mt7621_wdt_stop(&mt7621_wdt_dev); 158 mt7621_wdt_start(&mt7621_wdt_dev); 159 set_bit(WDOG_HW_RUNNING, &mt7621_wdt_dev.status); 160 } 161 162 return devm_watchdog_register_device(dev, &mt7621_wdt_dev); 163} 164 165static void mt7621_wdt_shutdown(struct platform_device *pdev) 166{ 167 mt7621_wdt_stop(&mt7621_wdt_dev); 168} 169 170static const struct of_device_id mt7621_wdt_match[] = { 171 { .compatible = "mediatek,mt7621-wdt" }, 172 {}, 173}; 174MODULE_DEVICE_TABLE(of, mt7621_wdt_match); 175 176static struct platform_driver mt7621_wdt_driver = { 177 .probe = mt7621_wdt_probe, 178 .shutdown = mt7621_wdt_shutdown, 179 .driver = { 180 .name = KBUILD_MODNAME, 181 .of_match_table = mt7621_wdt_match, 182 }, 183}; 184 185module_platform_driver(mt7621_wdt_driver); 186 187MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); 188MODULE_AUTHOR("John Crispin <john@phrozen.org"); 189MODULE_LICENSE("GPL v2");