1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for STM32 Independent Watchdog 4 * 5 * Copyright (C) STMicroelectronics 2017 6 * Author: Yannick Fertre <yannick.fertre@st.com> for STMicroelectronics. 7 * 8 * This driver is based on tegra_wdt.c 9 * 10 */ 11 12 #include <linux/clk.h> 13 #include <linux/delay.h> 14 #include <linux/interrupt.h> 15 #include <linux/io.h> 16 #include <linux/iopoll.h> 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/of.h> 20 #include <linux/of_device.h> 21 #include <linux/platform_device.h> 22 #include <linux/watchdog.h> 23 24 /* IWDG registers */ 25 #define IWDG_KR 0x00 /* Key register */ 26 #define IWDG_PR 0x04 /* Prescaler Register */ 27 #define IWDG_RLR 0x08 /* ReLoad Register */ 28 #define IWDG_SR 0x0C /* Status Register */ 29 #define IWDG_WINR 0x10 /* Windows Register */ 30 31 /* IWDG_KR register bit mask */ 32 #define KR_KEY_RELOAD 0xAAAA /* reload counter enable */ 33 #define KR_KEY_ENABLE 0xCCCC /* peripheral enable */ 34 #define KR_KEY_EWA 0x5555 /* write access enable */ 35 #define KR_KEY_DWA 0x0000 /* write access disable */ 36 37 /* IWDG_PR register bit values */ 38 #define PR_4 0x00 /* prescaler set to 4 */ 39 #define PR_8 0x01 /* prescaler set to 8 */ 40 #define PR_16 0x02 /* prescaler set to 16 */ 41 #define PR_32 0x03 /* prescaler set to 32 */ 42 #define PR_64 0x04 /* prescaler set to 64 */ 43 #define PR_128 0x05 /* prescaler set to 128 */ 44 #define PR_256 0x06 /* prescaler set to 256 */ 45 46 /* IWDG_RLR register values */ 47 #define RLR_MIN 0x07C /* min value supported by reload register */ 48 #define RLR_MAX 0xFFF /* max value supported by reload register */ 49 50 /* IWDG_SR register bit mask */ 51 #define FLAG_PVU BIT(0) /* Watchdog prescaler value update */ 52 #define FLAG_RVU BIT(1) /* Watchdog counter reload value update */ 53 54 /* set timeout to 100000 us */ 55 #define TIMEOUT_US 100000 56 #define SLEEP_US 1000 57 58 #define HAS_PCLK true 59 60 struct stm32_iwdg { 61 struct watchdog_device wdd; 62 void __iomem *regs; 63 struct clk *clk_lsi; 64 struct clk *clk_pclk; 65 unsigned int rate; 66 bool has_pclk; 67 }; 68 69 static inline u32 reg_read(void __iomem *base, u32 reg) 70 { 71 return readl_relaxed(base + reg); 72 } 73 74 static inline void reg_write(void __iomem *base, u32 reg, u32 val) 75 { 76 writel_relaxed(val, base + reg); 77 } 78 79 static int stm32_iwdg_start(struct watchdog_device *wdd) 80 { 81 struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); 82 u32 val = FLAG_PVU | FLAG_RVU; 83 u32 reload; 84 int ret; 85 86 dev_dbg(wdd->parent, "%s\n", __func__); 87 88 /* prescaler fixed to 256 */ 89 reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1, 90 RLR_MIN, RLR_MAX); 91 92 /* enable write access */ 93 reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA); 94 95 /* set prescaler & reload registers */ 96 reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */ 97 reg_write(wdt->regs, IWDG_RLR, reload); 98 reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); 99 100 /* wait for the registers to be updated (max 100ms) */ 101 ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, val, 102 !(val & (FLAG_PVU | FLAG_RVU)), 103 SLEEP_US, TIMEOUT_US); 104 if (ret) { 105 dev_err(wdd->parent, 106 "Fail to set prescaler or reload registers\n"); 107 return ret; 108 } 109 110 /* reload watchdog */ 111 reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); 112 113 return 0; 114 } 115 116 static int stm32_iwdg_ping(struct watchdog_device *wdd) 117 { 118 struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); 119 120 dev_dbg(wdd->parent, "%s\n", __func__); 121 122 /* reload watchdog */ 123 reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); 124 125 return 0; 126 } 127 128 static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, 129 unsigned int timeout) 130 { 131 dev_dbg(wdd->parent, "%s timeout: %d sec\n", __func__, timeout); 132 133 wdd->timeout = timeout; 134 135 if (watchdog_active(wdd)) 136 return stm32_iwdg_start(wdd); 137 138 return 0; 139 } 140 141 static int stm32_iwdg_clk_init(struct platform_device *pdev, 142 struct stm32_iwdg *wdt) 143 { 144 u32 ret; 145 146 wdt->clk_lsi = devm_clk_get(&pdev->dev, "lsi"); 147 if (IS_ERR(wdt->clk_lsi)) { 148 dev_err(&pdev->dev, "Unable to get lsi clock\n"); 149 return PTR_ERR(wdt->clk_lsi); 150 } 151 152 /* optional peripheral clock */ 153 if (wdt->has_pclk) { 154 wdt->clk_pclk = devm_clk_get(&pdev->dev, "pclk"); 155 if (IS_ERR(wdt->clk_pclk)) { 156 dev_err(&pdev->dev, "Unable to get pclk clock\n"); 157 return PTR_ERR(wdt->clk_pclk); 158 } 159 160 ret = clk_prepare_enable(wdt->clk_pclk); 161 if (ret) { 162 dev_err(&pdev->dev, "Unable to prepare pclk clock\n"); 163 return ret; 164 } 165 } 166 167 ret = clk_prepare_enable(wdt->clk_lsi); 168 if (ret) { 169 dev_err(&pdev->dev, "Unable to prepare lsi clock\n"); 170 clk_disable_unprepare(wdt->clk_pclk); 171 return ret; 172 } 173 174 wdt->rate = clk_get_rate(wdt->clk_lsi); 175 176 return 0; 177 } 178 179 static const struct watchdog_info stm32_iwdg_info = { 180 .options = WDIOF_SETTIMEOUT | 181 WDIOF_MAGICCLOSE | 182 WDIOF_KEEPALIVEPING, 183 .identity = "STM32 Independent Watchdog", 184 }; 185 186 static const struct watchdog_ops stm32_iwdg_ops = { 187 .owner = THIS_MODULE, 188 .start = stm32_iwdg_start, 189 .ping = stm32_iwdg_ping, 190 .set_timeout = stm32_iwdg_set_timeout, 191 }; 192 193 static const struct of_device_id stm32_iwdg_of_match[] = { 194 { .compatible = "st,stm32-iwdg", .data = (void *)!HAS_PCLK }, 195 { .compatible = "st,stm32mp1-iwdg", .data = (void *)HAS_PCLK }, 196 { /* end node */ } 197 }; 198 MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); 199 200 static int stm32_iwdg_probe(struct platform_device *pdev) 201 { 202 struct watchdog_device *wdd; 203 const struct of_device_id *match; 204 struct stm32_iwdg *wdt; 205 struct resource *res; 206 int ret; 207 208 match = of_match_device(stm32_iwdg_of_match, &pdev->dev); 209 if (!match) 210 return -ENODEV; 211 212 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); 213 if (!wdt) 214 return -ENOMEM; 215 216 wdt->has_pclk = match->data; 217 218 /* This is the timer base. */ 219 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 220 wdt->regs = devm_ioremap_resource(&pdev->dev, res); 221 if (IS_ERR(wdt->regs)) { 222 dev_err(&pdev->dev, "Could not get resource\n"); 223 return PTR_ERR(wdt->regs); 224 } 225 226 ret = stm32_iwdg_clk_init(pdev, wdt); 227 if (ret) 228 return ret; 229 230 /* Initialize struct watchdog_device. */ 231 wdd = &wdt->wdd; 232 wdd->info = &stm32_iwdg_info; 233 wdd->ops = &stm32_iwdg_ops; 234 wdd->min_timeout = ((RLR_MIN + 1) * 256) / wdt->rate; 235 wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 256 * 1000) / wdt->rate; 236 wdd->parent = &pdev->dev; 237 238 watchdog_set_drvdata(wdd, wdt); 239 watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); 240 241 ret = watchdog_init_timeout(wdd, 0, &pdev->dev); 242 if (ret) 243 dev_warn(&pdev->dev, 244 "unable to set timeout value, using default\n"); 245 246 ret = watchdog_register_device(wdd); 247 if (ret) { 248 dev_err(&pdev->dev, "failed to register watchdog device\n"); 249 goto err; 250 } 251 252 platform_set_drvdata(pdev, wdt); 253 254 return 0; 255 err: 256 clk_disable_unprepare(wdt->clk_lsi); 257 clk_disable_unprepare(wdt->clk_pclk); 258 259 return ret; 260 } 261 262 static int stm32_iwdg_remove(struct platform_device *pdev) 263 { 264 struct stm32_iwdg *wdt = platform_get_drvdata(pdev); 265 266 watchdog_unregister_device(&wdt->wdd); 267 clk_disable_unprepare(wdt->clk_lsi); 268 clk_disable_unprepare(wdt->clk_pclk); 269 270 return 0; 271 } 272 273 static struct platform_driver stm32_iwdg_driver = { 274 .probe = stm32_iwdg_probe, 275 .remove = stm32_iwdg_remove, 276 .driver = { 277 .name = "iwdg", 278 .of_match_table = of_match_ptr(stm32_iwdg_of_match), 279 }, 280 }; 281 module_platform_driver(stm32_iwdg_driver); 282 283 MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); 284 MODULE_DESCRIPTION("STMicroelectronics STM32 Independent Watchdog Driver"); 285 MODULE_LICENSE("GPL v2"); 286