141 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) STMicroelectronics 20183// 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 020 21#define PMIC_WDT_MIN_TIMEOUT 122#define PMIC_WDT_MAX_TIMEOUT 25623#define PMIC_WDT_DEFAULT_TIMEOUT 3024 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");141