linux/drivers/watchdog/stpmic1_wdt.c
<<
>>
Prefs
   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");
 141