root/drivers/watchdog/rn5t618_wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rn5t618_wdt_set_timeout
  2. rn5t618_wdt_start
  3. rn5t618_wdt_stop
  4. rn5t618_wdt_ping
  5. rn5t618_wdt_probe
  6. rn5t618_wdt_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Watchdog driver for Ricoh RN5T618 PMIC
   4  *
   5  * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
   6  */
   7 
   8 #include <linux/device.h>
   9 #include <linux/mfd/rn5t618.h>
  10 #include <linux/module.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/watchdog.h>
  13 
  14 #define DRIVER_NAME "rn5t618-wdt"
  15 
  16 static bool nowayout = WATCHDOG_NOWAYOUT;
  17 static unsigned int timeout;
  18 
  19 module_param(timeout, uint, 0);
  20 MODULE_PARM_DESC(timeout, "Initial watchdog timeout in seconds");
  21 
  22 module_param(nowayout, bool, 0);
  23 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  24                  __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  25 
  26 struct rn5t618_wdt {
  27         struct watchdog_device wdt_dev;
  28         struct rn5t618 *rn5t618;
  29 };
  30 
  31 /*
  32  * This array encodes the values of WDOGTIM field for the supported
  33  * watchdog expiration times. If the watchdog is not accessed before
  34  * the timer expiration, the PMU generates an interrupt and if the CPU
  35  * doesn't clear it within one second the system is restarted.
  36  */
  37 static const struct {
  38         u8 reg_val;
  39         unsigned int time;
  40 } rn5t618_wdt_map[] = {
  41         { 0, 1 },
  42         { 1, 8 },
  43         { 2, 32 },
  44         { 3, 128 },
  45 };
  46 
  47 static int rn5t618_wdt_set_timeout(struct watchdog_device *wdt_dev,
  48                                    unsigned int t)
  49 {
  50         struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev);
  51         int ret, i;
  52 
  53         for (i = 0; i < ARRAY_SIZE(rn5t618_wdt_map); i++) {
  54                 if (rn5t618_wdt_map[i].time + 1 >= t)
  55                         break;
  56         }
  57 
  58         if (i == ARRAY_SIZE(rn5t618_wdt_map))
  59                 return -EINVAL;
  60 
  61         ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG,
  62                                  RN5T618_WATCHDOG_WDOGTIM_M,
  63                                  rn5t618_wdt_map[i].reg_val);
  64         if (!ret)
  65                 wdt_dev->timeout = rn5t618_wdt_map[i].time;
  66 
  67         return ret;
  68 }
  69 
  70 static int rn5t618_wdt_start(struct watchdog_device *wdt_dev)
  71 {
  72         struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev);
  73         int ret;
  74 
  75         ret = rn5t618_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
  76         if (ret)
  77                 return ret;
  78 
  79         /* enable repower-on */
  80         ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_REPCNT,
  81                                  RN5T618_REPCNT_REPWRON,
  82                                  RN5T618_REPCNT_REPWRON);
  83         if (ret)
  84                 return ret;
  85 
  86         /* enable watchdog */
  87         ret = regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG,
  88                                  RN5T618_WATCHDOG_WDOGEN,
  89                                  RN5T618_WATCHDOG_WDOGEN);
  90         if (ret)
  91                 return ret;
  92 
  93         /* enable watchdog interrupt */
  94         return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIREN,
  95                                   RN5T618_PWRIRQ_IR_WDOG,
  96                                   RN5T618_PWRIRQ_IR_WDOG);
  97 }
  98 
  99 static int rn5t618_wdt_stop(struct watchdog_device *wdt_dev)
 100 {
 101         struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 102 
 103         return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_WATCHDOG,
 104                                   RN5T618_WATCHDOG_WDOGEN, 0);
 105 }
 106 
 107 static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev)
 108 {
 109         struct rn5t618_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 110         unsigned int val;
 111         int ret;
 112 
 113         /* The counter is restarted after a R/W access to watchdog register */
 114         ret = regmap_read(wdt->rn5t618->regmap, RN5T618_WATCHDOG, &val);
 115         if (ret)
 116                 return ret;
 117 
 118         ret = regmap_write(wdt->rn5t618->regmap, RN5T618_WATCHDOG, val);
 119         if (ret)
 120                 return ret;
 121 
 122         /* Clear pending watchdog interrupt */
 123         return regmap_update_bits(wdt->rn5t618->regmap, RN5T618_PWRIRQ,
 124                                   RN5T618_PWRIRQ_IR_WDOG, 0);
 125 }
 126 
 127 static const struct watchdog_info rn5t618_wdt_info = {
 128         .options        = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
 129                           WDIOF_KEEPALIVEPING,
 130         .identity       = DRIVER_NAME,
 131 };
 132 
 133 static const struct watchdog_ops rn5t618_wdt_ops = {
 134         .owner          = THIS_MODULE,
 135         .start          = rn5t618_wdt_start,
 136         .stop           = rn5t618_wdt_stop,
 137         .ping           = rn5t618_wdt_ping,
 138         .set_timeout    = rn5t618_wdt_set_timeout,
 139 };
 140 
 141 static int rn5t618_wdt_probe(struct platform_device *pdev)
 142 {
 143         struct device *dev = &pdev->dev;
 144         struct rn5t618 *rn5t618 = dev_get_drvdata(dev->parent);
 145         struct rn5t618_wdt *wdt;
 146         int min_timeout, max_timeout;
 147 
 148         wdt = devm_kzalloc(dev, sizeof(struct rn5t618_wdt), GFP_KERNEL);
 149         if (!wdt)
 150                 return -ENOMEM;
 151 
 152         min_timeout = rn5t618_wdt_map[0].time;
 153         max_timeout = rn5t618_wdt_map[ARRAY_SIZE(rn5t618_wdt_map) - 1].time;
 154 
 155         wdt->rn5t618 = rn5t618;
 156         wdt->wdt_dev.info = &rn5t618_wdt_info;
 157         wdt->wdt_dev.ops = &rn5t618_wdt_ops;
 158         wdt->wdt_dev.min_timeout = min_timeout;
 159         wdt->wdt_dev.max_timeout = max_timeout;
 160         wdt->wdt_dev.timeout = max_timeout;
 161         wdt->wdt_dev.parent = dev;
 162 
 163         watchdog_set_drvdata(&wdt->wdt_dev, wdt);
 164         watchdog_init_timeout(&wdt->wdt_dev, timeout, dev);
 165         watchdog_set_nowayout(&wdt->wdt_dev, nowayout);
 166 
 167         platform_set_drvdata(pdev, wdt);
 168 
 169         return watchdog_register_device(&wdt->wdt_dev);
 170 }
 171 
 172 static int rn5t618_wdt_remove(struct platform_device *pdev)
 173 {
 174         struct rn5t618_wdt *wdt = platform_get_drvdata(pdev);
 175 
 176         watchdog_unregister_device(&wdt->wdt_dev);
 177 
 178         return 0;
 179 }
 180 
 181 static struct platform_driver rn5t618_wdt_driver = {
 182         .probe = rn5t618_wdt_probe,
 183         .remove = rn5t618_wdt_remove,
 184         .driver = {
 185                 .name   = DRIVER_NAME,
 186         },
 187 };
 188 
 189 module_platform_driver(rn5t618_wdt_driver);
 190 
 191 MODULE_ALIAS("platform:rn5t618-wdt");
 192 MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
 193 MODULE_DESCRIPTION("RN5T618 watchdog driver");
 194 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */