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