root/drivers/watchdog/da9063_wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. da9063_wdt_timeout_to_sel
  2. da9063_wdt_is_running
  3. da9063_wdt_disable_timer
  4. da9063_wdt_update_timeout
  5. da9063_wdt_start
  6. da9063_wdt_stop
  7. da9063_wdt_ping
  8. da9063_wdt_set_timeout
  9. da9063_wdt_restart
  10. da9063_wdt_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Watchdog driver for DA9063 PMICs.
   4  *
   5  * Copyright(c) 2012 Dialog Semiconductor Ltd.
   6  *
   7  * Author: Mariusz Wojtasik <mariusz.wojtasik@diasemi.com>
   8  *
   9  */
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/watchdog.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/uaccess.h>
  16 #include <linux/slab.h>
  17 #include <linux/delay.h>
  18 #include <linux/mfd/da9063/registers.h>
  19 #include <linux/mfd/da9063/core.h>
  20 #include <linux/regmap.h>
  21 
  22 /*
  23  * Watchdog selector to timeout in seconds.
  24  *   0: WDT disabled;
  25  *   others: timeout = 2048 ms * 2^(TWDSCALE-1).
  26  */
  27 static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
  28 #define DA9063_TWDSCALE_DISABLE         0
  29 #define DA9063_TWDSCALE_MIN             1
  30 #define DA9063_TWDSCALE_MAX             (ARRAY_SIZE(wdt_timeout) - 1)
  31 #define DA9063_WDT_MIN_TIMEOUT          wdt_timeout[DA9063_TWDSCALE_MIN]
  32 #define DA9063_WDT_MAX_TIMEOUT          wdt_timeout[DA9063_TWDSCALE_MAX]
  33 #define DA9063_WDG_TIMEOUT              wdt_timeout[3]
  34 #define DA9063_RESET_PROTECTION_MS      256
  35 
  36 static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
  37 {
  38         unsigned int i;
  39 
  40         for (i = DA9063_TWDSCALE_MIN; i <= DA9063_TWDSCALE_MAX; i++) {
  41                 if (wdt_timeout[i] >= secs)
  42                         return i;
  43         }
  44 
  45         return DA9063_TWDSCALE_MAX;
  46 }
  47 
  48 /*
  49  * Return 0 if watchdog is disabled, else non zero.
  50  */
  51 static unsigned int da9063_wdt_is_running(struct da9063 *da9063)
  52 {
  53         unsigned int val;
  54 
  55         regmap_read(da9063->regmap, DA9063_REG_CONTROL_D, &val);
  56 
  57         return val & DA9063_TWDSCALE_MASK;
  58 }
  59 
  60 static int da9063_wdt_disable_timer(struct da9063 *da9063)
  61 {
  62         return regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D,
  63                                   DA9063_TWDSCALE_MASK,
  64                                   DA9063_TWDSCALE_DISABLE);
  65 }
  66 
  67 static int
  68 da9063_wdt_update_timeout(struct da9063 *da9063, unsigned int timeout)
  69 {
  70         unsigned int regval;
  71         int ret;
  72 
  73         /*
  74          * The watchdog triggers a reboot if a timeout value is already
  75          * programmed because the timeout value combines two functions
  76          * in one: indicating the counter limit and starting the watchdog.
  77          * The watchdog must be disabled to be able to change the timeout
  78          * value if the watchdog is already running. Then we can set the
  79          * new timeout value which enables the watchdog again.
  80          */
  81         ret = da9063_wdt_disable_timer(da9063);
  82         if (ret)
  83                 return ret;
  84 
  85         usleep_range(150, 300);
  86         regval = da9063_wdt_timeout_to_sel(timeout);
  87 
  88         return regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_D,
  89                                   DA9063_TWDSCALE_MASK, regval);
  90 }
  91 
  92 static int da9063_wdt_start(struct watchdog_device *wdd)
  93 {
  94         struct da9063 *da9063 = watchdog_get_drvdata(wdd);
  95         int ret;
  96 
  97         ret = da9063_wdt_update_timeout(da9063, wdd->timeout);
  98         if (ret)
  99                 dev_err(da9063->dev, "Watchdog failed to start (err = %d)\n",
 100                         ret);
 101 
 102         return ret;
 103 }
 104 
 105 static int da9063_wdt_stop(struct watchdog_device *wdd)
 106 {
 107         struct da9063 *da9063 = watchdog_get_drvdata(wdd);
 108         int ret;
 109 
 110         ret = da9063_wdt_disable_timer(da9063);
 111         if (ret)
 112                 dev_alert(da9063->dev, "Watchdog failed to stop (err = %d)\n",
 113                           ret);
 114 
 115         return ret;
 116 }
 117 
 118 static int da9063_wdt_ping(struct watchdog_device *wdd)
 119 {
 120         struct da9063 *da9063 = watchdog_get_drvdata(wdd);
 121         int ret;
 122 
 123         ret = regmap_write(da9063->regmap, DA9063_REG_CONTROL_F,
 124                            DA9063_WATCHDOG);
 125         if (ret)
 126                 dev_alert(da9063->dev, "Failed to ping the watchdog (err = %d)\n",
 127                           ret);
 128 
 129         return ret;
 130 }
 131 
 132 static int da9063_wdt_set_timeout(struct watchdog_device *wdd,
 133                                   unsigned int timeout)
 134 {
 135         struct da9063 *da9063 = watchdog_get_drvdata(wdd);
 136         int ret = 0;
 137 
 138         /*
 139          * There are two cases when a set_timeout() will be called:
 140          * 1. The watchdog is off and someone wants to set the timeout for the
 141          *    further use.
 142          * 2. The watchdog is already running and a new timeout value should be
 143          *    set.
 144          *
 145          * The watchdog can't store a timeout value not equal zero without
 146          * enabling the watchdog, so the timeout must be buffered by the driver.
 147          */
 148         if (watchdog_active(wdd))
 149                 ret = da9063_wdt_update_timeout(da9063, timeout);
 150 
 151         if (ret)
 152                 dev_err(da9063->dev, "Failed to set watchdog timeout (err = %d)\n",
 153                         ret);
 154         else
 155                 wdd->timeout = wdt_timeout[da9063_wdt_timeout_to_sel(timeout)];
 156 
 157         return ret;
 158 }
 159 
 160 static int da9063_wdt_restart(struct watchdog_device *wdd, unsigned long action,
 161                               void *data)
 162 {
 163         struct da9063 *da9063 = watchdog_get_drvdata(wdd);
 164         int ret;
 165 
 166         ret = regmap_write(da9063->regmap, DA9063_REG_CONTROL_F,
 167                            DA9063_SHUTDOWN);
 168         if (ret)
 169                 dev_alert(da9063->dev, "Failed to shutdown (err = %d)\n",
 170                           ret);
 171 
 172         return ret;
 173 }
 174 
 175 static const struct watchdog_info da9063_watchdog_info = {
 176         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
 177         .identity = "DA9063 Watchdog",
 178 };
 179 
 180 static const struct watchdog_ops da9063_watchdog_ops = {
 181         .owner = THIS_MODULE,
 182         .start = da9063_wdt_start,
 183         .stop = da9063_wdt_stop,
 184         .ping = da9063_wdt_ping,
 185         .set_timeout = da9063_wdt_set_timeout,
 186         .restart = da9063_wdt_restart,
 187 };
 188 
 189 static int da9063_wdt_probe(struct platform_device *pdev)
 190 {
 191         struct device *dev = &pdev->dev;
 192         struct da9063 *da9063;
 193         struct watchdog_device *wdd;
 194 
 195         if (!dev->parent)
 196                 return -EINVAL;
 197 
 198         da9063 = dev_get_drvdata(dev->parent);
 199         if (!da9063)
 200                 return -EINVAL;
 201 
 202         wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL);
 203         if (!wdd)
 204                 return -ENOMEM;
 205 
 206         wdd->info = &da9063_watchdog_info;
 207         wdd->ops = &da9063_watchdog_ops;
 208         wdd->min_timeout = DA9063_WDT_MIN_TIMEOUT;
 209         wdd->max_timeout = DA9063_WDT_MAX_TIMEOUT;
 210         wdd->min_hw_heartbeat_ms = DA9063_RESET_PROTECTION_MS;
 211         wdd->parent = dev;
 212         wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS;
 213 
 214         watchdog_set_restart_priority(wdd, 128);
 215         watchdog_set_drvdata(wdd, da9063);
 216 
 217         /* Set default timeout, maybe override it with DT value, scale it */
 218         wdd->timeout = DA9063_WDG_TIMEOUT;
 219         watchdog_init_timeout(wdd, 0, dev);
 220         da9063_wdt_set_timeout(wdd, wdd->timeout);
 221 
 222         /* Change the timeout to the default value if the watchdog is running */
 223         if (da9063_wdt_is_running(da9063)) {
 224                 da9063_wdt_update_timeout(da9063, wdd->timeout);
 225                 set_bit(WDOG_HW_RUNNING, &wdd->status);
 226         }
 227 
 228         return devm_watchdog_register_device(dev, wdd);
 229 }
 230 
 231 static struct platform_driver da9063_wdt_driver = {
 232         .probe = da9063_wdt_probe,
 233         .driver = {
 234                 .name = DA9063_DRVNAME_WATCHDOG,
 235         },
 236 };
 237 module_platform_driver(da9063_wdt_driver);
 238 
 239 MODULE_AUTHOR("Mariusz Wojtasik <mariusz.wojtasik@diasemi.com>");
 240 MODULE_DESCRIPTION("Watchdog driver for Dialog DA9063");
 241 MODULE_LICENSE("GPL");
 242 MODULE_ALIAS("platform:" DA9063_DRVNAME_WATCHDOG);

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