stpmic1_wdt.c (3593B)
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 25static bool nowayout = WATCHDOG_NOWAYOUT; 26module_param(nowayout, bool, 0); 27MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 28 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 29 30struct stpmic1_wdt { 31 struct stpmic1 *pmic; 32 struct watchdog_device wdtdev; 33}; 34 35static 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 43static 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 51static 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 59static 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 69static const struct watchdog_info pmic_watchdog_info = { 70 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 71 .identity = "STPMIC1 PMIC Watchdog", 72}; 73 74static 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 82static 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 122static const struct of_device_id of_pmic_wdt_match[] = { 123 { .compatible = "st,stpmic1-wdt" }, 124 { }, 125}; 126 127MODULE_DEVICE_TABLE(of, of_pmic_wdt_match); 128 129static 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}; 136module_platform_driver(stpmic1_wdt_driver); 137 138MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device"); 139MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>"); 140MODULE_LICENSE("GPL v2");