1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * ST's LPC Watchdog 4 * 5 * Copyright (C) 2014 STMicroelectronics -- All Rights Reserved 6 * 7 * Author: David Paris <david.paris@st.com> for STMicroelectronics 8 * Lee Jones <lee.jones@linaro.org> for STMicroelectronics 9 */ 10 11 #include <linux/clk.h> 12 #include <linux/init.h> 13 #include <linux/io.h> 14 #include <linux/kernel.h> 15 #include <linux/mfd/syscon.h> 16 #include <linux/module.h> 17 #include <linux/of.h> 18 #include <linux/platform_device.h> 19 #include <linux/regmap.h> 20 #include <linux/watchdog.h> 21 22 #include <dt-bindings/mfd/st-lpc.h> 23 24 /* Low Power Alarm */ 25 #define LPC_LPA_LSB_OFF 0x410 26 #define LPC_LPA_START_OFF 0x418 27 28 /* LPC as WDT */ 29 #define LPC_WDT_OFF 0x510 30 31 static struct watchdog_device st_wdog_dev; 32 33 struct st_wdog_syscfg { 34 unsigned int reset_type_reg; 35 unsigned int reset_type_mask; 36 unsigned int enable_reg; 37 unsigned int enable_mask; 38 }; 39 40 struct st_wdog { 41 void __iomem *base; 42 struct device *dev; 43 struct regmap *regmap; 44 const struct st_wdog_syscfg *syscfg; 45 struct clk *clk; 46 unsigned long clkrate; 47 bool warm_reset; 48 }; 49 50 static struct st_wdog_syscfg stih407_syscfg = { 51 .enable_reg = 0x204, 52 .enable_mask = BIT(19), 53 }; 54 55 static const struct of_device_id st_wdog_match[] = { 56 { 57 .compatible = "st,stih407-lpc", 58 .data = &stih407_syscfg, 59 }, 60 {}, 61 }; 62 MODULE_DEVICE_TABLE(of, st_wdog_match); 63 64 static void st_wdog_setup(struct st_wdog *st_wdog, bool enable) 65 { 66 /* Type of watchdog reset - 0: Cold 1: Warm */ 67 if (st_wdog->syscfg->reset_type_reg) 68 regmap_update_bits(st_wdog->regmap, 69 st_wdog->syscfg->reset_type_reg, 70 st_wdog->syscfg->reset_type_mask, 71 st_wdog->warm_reset); 72 73 /* Mask/unmask watchdog reset */ 74 regmap_update_bits(st_wdog->regmap, 75 st_wdog->syscfg->enable_reg, 76 st_wdog->syscfg->enable_mask, 77 enable ? 0 : st_wdog->syscfg->enable_mask); 78 } 79 80 static void st_wdog_load_timer(struct st_wdog *st_wdog, unsigned int timeout) 81 { 82 unsigned long clkrate = st_wdog->clkrate; 83 84 writel_relaxed(timeout * clkrate, st_wdog->base + LPC_LPA_LSB_OFF); 85 writel_relaxed(1, st_wdog->base + LPC_LPA_START_OFF); 86 } 87 88 static int st_wdog_start(struct watchdog_device *wdd) 89 { 90 struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); 91 92 writel_relaxed(1, st_wdog->base + LPC_WDT_OFF); 93 94 return 0; 95 } 96 97 static int st_wdog_stop(struct watchdog_device *wdd) 98 { 99 struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); 100 101 writel_relaxed(0, st_wdog->base + LPC_WDT_OFF); 102 103 return 0; 104 } 105 106 static int st_wdog_set_timeout(struct watchdog_device *wdd, 107 unsigned int timeout) 108 { 109 struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); 110 111 wdd->timeout = timeout; 112 st_wdog_load_timer(st_wdog, timeout); 113 114 return 0; 115 } 116 117 static int st_wdog_keepalive(struct watchdog_device *wdd) 118 { 119 struct st_wdog *st_wdog = watchdog_get_drvdata(wdd); 120 121 st_wdog_load_timer(st_wdog, wdd->timeout); 122 123 return 0; 124 } 125 126 static const struct watchdog_info st_wdog_info = { 127 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 128 .identity = "ST LPC WDT", 129 }; 130 131 static const struct watchdog_ops st_wdog_ops = { 132 .owner = THIS_MODULE, 133 .start = st_wdog_start, 134 .stop = st_wdog_stop, 135 .ping = st_wdog_keepalive, 136 .set_timeout = st_wdog_set_timeout, 137 }; 138 139 static struct watchdog_device st_wdog_dev = { 140 .info = &st_wdog_info, 141 .ops = &st_wdog_ops, 142 }; 143 144 static void st_clk_disable_unprepare(void *data) 145 { 146 clk_disable_unprepare(data); 147 } 148 149 static int st_wdog_probe(struct platform_device *pdev) 150 { 151 struct device *dev = &pdev->dev; 152 struct device_node *np = dev->of_node; 153 struct st_wdog *st_wdog; 154 struct regmap *regmap; 155 struct clk *clk; 156 void __iomem *base; 157 uint32_t mode; 158 int ret; 159 160 ret = of_property_read_u32(np, "st,lpc-mode", &mode); 161 if (ret) { 162 dev_err(dev, "An LPC mode must be provided\n"); 163 return -EINVAL; 164 } 165 166 /* LPC can either run as a Clocksource or in RTC or WDT mode */ 167 if (mode != ST_LPC_MODE_WDT) 168 return -ENODEV; 169 170 st_wdog = devm_kzalloc(dev, sizeof(*st_wdog), GFP_KERNEL); 171 if (!st_wdog) 172 return -ENOMEM; 173 174 st_wdog->syscfg = (struct st_wdog_syscfg *)device_get_match_data(dev); 175 176 base = devm_platform_ioremap_resource(pdev, 0); 177 if (IS_ERR(base)) 178 return PTR_ERR(base); 179 180 regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg"); 181 if (IS_ERR(regmap)) { 182 dev_err(dev, "No syscfg phandle specified\n"); 183 return PTR_ERR(regmap); 184 } 185 186 clk = devm_clk_get(dev, NULL); 187 if (IS_ERR(clk)) { 188 dev_err(dev, "Unable to request clock\n"); 189 return PTR_ERR(clk); 190 } 191 192 st_wdog->dev = dev; 193 st_wdog->base = base; 194 st_wdog->clk = clk; 195 st_wdog->regmap = regmap; 196 st_wdog->warm_reset = of_property_read_bool(np, "st,warm_reset"); 197 st_wdog->clkrate = clk_get_rate(st_wdog->clk); 198 199 if (!st_wdog->clkrate) { 200 dev_err(dev, "Unable to fetch clock rate\n"); 201 return -EINVAL; 202 } 203 st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate; 204 st_wdog_dev.parent = dev; 205 206 ret = clk_prepare_enable(clk); 207 if (ret) { 208 dev_err(dev, "Unable to enable clock\n"); 209 return ret; 210 } 211 ret = devm_add_action_or_reset(dev, st_clk_disable_unprepare, clk); 212 if (ret) 213 return ret; 214 215 watchdog_set_drvdata(&st_wdog_dev, st_wdog); 216 watchdog_set_nowayout(&st_wdog_dev, WATCHDOG_NOWAYOUT); 217 218 /* Init Watchdog timeout with value in DT */ 219 ret = watchdog_init_timeout(&st_wdog_dev, 0, dev); 220 if (ret) 221 return ret; 222 223 ret = devm_watchdog_register_device(dev, &st_wdog_dev); 224 if (ret) 225 return ret; 226 227 st_wdog_setup(st_wdog, true); 228 229 dev_info(dev, "LPC Watchdog driver registered, reset type is %s", 230 st_wdog->warm_reset ? "warm" : "cold"); 231 232 return ret; 233 } 234 235 static void st_wdog_remove(struct platform_device *pdev) 236 { 237 struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); 238 239 st_wdog_setup(st_wdog, false); 240 } 241 242 static int st_wdog_suspend(struct device *dev) 243 { 244 struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); 245 246 if (watchdog_active(&st_wdog_dev)) 247 st_wdog_stop(&st_wdog_dev); 248 249 st_wdog_setup(st_wdog, false); 250 251 clk_disable(st_wdog->clk); 252 253 return 0; 254 } 255 256 static int st_wdog_resume(struct device *dev) 257 { 258 struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); 259 int ret; 260 261 ret = clk_enable(st_wdog->clk); 262 if (ret) { 263 dev_err(dev, "Unable to re-enable clock\n"); 264 watchdog_unregister_device(&st_wdog_dev); 265 clk_unprepare(st_wdog->clk); 266 return ret; 267 } 268 269 st_wdog_setup(st_wdog, true); 270 271 if (watchdog_active(&st_wdog_dev)) { 272 st_wdog_load_timer(st_wdog, st_wdog_dev.timeout); 273 st_wdog_start(&st_wdog_dev); 274 } 275 276 return 0; 277 } 278 279 static DEFINE_SIMPLE_DEV_PM_OPS(st_wdog_pm_ops, 280 st_wdog_suspend, st_wdog_resume); 281 282 static struct platform_driver st_wdog_driver = { 283 .driver = { 284 .name = "st-lpc-wdt", 285 .pm = pm_sleep_ptr(&st_wdog_pm_ops), 286 .of_match_table = st_wdog_match, 287 }, 288 .probe = st_wdog_probe, 289 .remove_new = st_wdog_remove, 290 }; 291 module_platform_driver(st_wdog_driver); 292 293 MODULE_AUTHOR("David Paris <david.paris@st.com>"); 294 MODULE_DESCRIPTION("ST LPC Watchdog Driver"); 295 MODULE_LICENSE("GPL"); 296