1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) STMicroelectronics 2018 3 // Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics. 4 5 #include <linux/kernel.h> 6 #include <linux/mfd/stpmic1.h> 7 #include <linux/module.h> 8 #include <linux/platform_device.h> 9 #include <linux/of.h> 10 #include <linux/regmap.h> 11 #include <linux/slab.h> 12 #include <linux/watchdog.h> 13 14 /* WATCHDOG CONTROL REGISTER bit */ 15 #define WDT_START BIT(0) 16 #define WDT_PING BIT(1) 17 #define WDT_START_MASK BIT(0) 18 #define WDT_PING_MASK BIT(1) 19 #define WDT_STOP 0 20 21 #define PMIC_WDT_MIN_TIMEOUT 1 22 #define PMIC_WDT_MAX_TIMEOUT 256 23 #define PMIC_WDT_DEFAULT_TIMEOUT 30 24 25 static bool nowayout = WATCHDOG_NOWAYOUT; 26 module_param(nowayout, bool, 0); 27 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 28 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 29 30 struct stpmic1_wdt { 31 struct stpmic1 *pmic; 32 struct watchdog_device wdtdev; 33 }; 34 35 static int pmic_wdt_start(struct watchdog_device *wdd) 36 { 37 struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); 38 39 return regmap_update_bits(wdt->pmic->regmap, 40 WCHDG_CR, WDT_START_MASK, WDT_START); 41 } 42 43 static int pmic_wdt_stop(struct watchdog_device *wdd) 44 { 45 struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); 46 47 return regmap_update_bits(wdt->pmic->regmap, 48 WCHDG_CR, WDT_START_MASK, WDT_STOP); 49 } 50 51 static int pmic_wdt_ping(struct watchdog_device *wdd) 52 { 53 struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); 54 55 return regmap_update_bits(wdt->pmic->regmap, 56 WCHDG_CR, WDT_PING_MASK, WDT_PING); 57 } 58 59 static int pmic_wdt_set_timeout(struct watchdog_device *wdd, 60 unsigned int timeout) 61 { 62 struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd); 63 64 wdd->timeout = timeout; 65 /* timeout is equal to register value + 1 */ 66 return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1); 67 } 68 69 static const struct watchdog_info pmic_watchdog_info = { 70 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 71 .identity = "STPMIC1 PMIC Watchdog", 72 }; 73 74 static const struct watchdog_ops pmic_watchdog_ops = { 75 .owner = THIS_MODULE, 76 .start = pmic_wdt_start, 77 .stop = pmic_wdt_stop, 78 .ping = pmic_wdt_ping, 79 .set_timeout = pmic_wdt_set_timeout, 80 }; 81 82 static int pmic_wdt_probe(struct platform_device *pdev) 83 { 84 struct device *dev = &pdev->dev; 85 int ret; 86 struct stpmic1 *pmic; 87 struct stpmic1_wdt *wdt; 88 89 if (!dev->parent) 90 return -EINVAL; 91 92 pmic = dev_get_drvdata(dev->parent); 93 if (!pmic) 94 return -EINVAL; 95 96 wdt = devm_kzalloc(dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); 97 if (!wdt) 98 return -ENOMEM; 99 100 wdt->pmic = pmic; 101 102 wdt->wdtdev.info = &pmic_watchdog_info; 103 wdt->wdtdev.ops = &pmic_watchdog_ops; 104 wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT; 105 wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT; 106 wdt->wdtdev.parent = dev; 107 108 wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT; 109 watchdog_init_timeout(&wdt->wdtdev, 0, dev); 110 111 watchdog_set_nowayout(&wdt->wdtdev, nowayout); 112 watchdog_set_drvdata(&wdt->wdtdev, wdt); 113 114 ret = devm_watchdog_register_device(dev, &wdt->wdtdev); 115 if (ret) 116 return ret; 117 118 dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n"); 119 return 0; 120 } 121 122 static const struct of_device_id of_pmic_wdt_match[] = { 123 { .compatible = "st,stpmic1-wdt" }, 124 { }, 125 }; 126 127 MODULE_DEVICE_TABLE(of, of_pmic_wdt_match); 128 129 static struct platform_driver stpmic1_wdt_driver = { 130 .probe = pmic_wdt_probe, 131 .driver = { 132 .name = "stpmic1-wdt", 133 .of_match_table = of_pmic_wdt_match, 134 }, 135 }; 136 module_platform_driver(stpmic1_wdt_driver); 137 138 MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device"); 139 MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); 140 MODULE_LICENSE("GPL v2"); 141