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 int ret; 85 struct stpmic1 *pmic; 86 struct stpmic1_wdt *wdt; 87 88 if (!pdev->dev.parent) 89 return -EINVAL; 90 91 pmic = dev_get_drvdata(pdev->dev.parent); 92 if (!pmic) 93 return -EINVAL; 94 95 wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL); 96 if (!wdt) 97 return -ENOMEM; 98 99 wdt->pmic = pmic; 100 101 wdt->wdtdev.info = &pmic_watchdog_info; 102 wdt->wdtdev.ops = &pmic_watchdog_ops; 103 wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT; 104 wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT; 105 wdt->wdtdev.parent = &pdev->dev; 106 107 wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT; 108 watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev); 109 110 watchdog_set_nowayout(&wdt->wdtdev, nowayout); 111 watchdog_set_drvdata(&wdt->wdtdev, wdt); 112 113 ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); 114 if (ret) 115 return ret; 116 117 dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n"); 118 return 0; 119 } 120 121 static const struct of_device_id of_pmic_wdt_match[] = { 122 { .compatible = "st,stpmic1-wdt" }, 123 { }, 124 }; 125 126 MODULE_DEVICE_TABLE(of, of_pmic_wdt_match); 127 128 static struct platform_driver stpmic1_wdt_driver = { 129 .probe = pmic_wdt_probe, 130 .driver = { 131 .name = "stpmic1-wdt", 132 .of_match_table = of_pmic_wdt_match, 133 }, 134 }; 135 module_platform_driver(stpmic1_wdt_driver); 136 137 MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device"); 138 MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); 139 MODULE_LICENSE("GPL v2"); 140