root/drivers/watchdog/rave-sp-wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_rave_sp_wdt
  2. rave_sp_wdt_exec
  3. rave_sp_wdt_legacy_configure
  4. rave_sp_wdt_rdu_configure
  5. rave_sp_wdt_configure
  6. rave_sp_wdt_legacy_restart
  7. rave_sp_wdt_rdu_restart
  8. rave_sp_wdt_reboot_notifier
  9. rave_sp_wdt_restart
  10. rave_sp_wdt_start
  11. rave_sp_wdt_stop
  12. rave_sp_wdt_set_timeout
  13. rave_sp_wdt_ping
  14. rave_sp_wdt_probe

   1 // SPDX-License-Identifier: GPL-2.0+
   2 
   3 /*
   4  * Driver for watchdog aspect of for Zodiac Inflight Innovations RAVE
   5  * Supervisory Processor(SP) MCU
   6  *
   7  * Copyright (C) 2017 Zodiac Inflight Innovation
   8  *
   9  */
  10 
  11 #include <linux/delay.h>
  12 #include <linux/kernel.h>
  13 #include <linux/mfd/rave-sp.h>
  14 #include <linux/module.h>
  15 #include <linux/nvmem-consumer.h>
  16 #include <linux/of_device.h>
  17 #include <linux/platform_device.h>
  18 #include <linux/reboot.h>
  19 #include <linux/slab.h>
  20 #include <linux/watchdog.h>
  21 
  22 enum {
  23         RAVE_SP_RESET_BYTE = 1,
  24         RAVE_SP_RESET_REASON_NORMAL = 0,
  25         RAVE_SP_RESET_DELAY_MS = 500,
  26 };
  27 
  28 /**
  29  * struct rave_sp_wdt_variant - RAVE SP watchdog variant
  30  *
  31  * @max_timeout:        Largest possible watchdog timeout setting
  32  * @min_timeout:        Smallest possible watchdog timeout setting
  33  *
  34  * @configure:          Function to send configuration command
  35  * @restart:            Function to send "restart" command
  36  */
  37 struct rave_sp_wdt_variant {
  38         unsigned int max_timeout;
  39         unsigned int min_timeout;
  40 
  41         int (*configure)(struct watchdog_device *, bool);
  42         int (*restart)(struct watchdog_device *);
  43 };
  44 
  45 /**
  46  * struct rave_sp_wdt - RAVE SP watchdog
  47  *
  48  * @wdd:                Underlying watchdog device
  49  * @sp:                 Pointer to parent RAVE SP device
  50  * @variant:            Device specific variant information
  51  * @reboot_notifier:    Reboot notifier implementing machine reset
  52  */
  53 struct rave_sp_wdt {
  54         struct watchdog_device wdd;
  55         struct rave_sp *sp;
  56         const struct rave_sp_wdt_variant *variant;
  57         struct notifier_block reboot_notifier;
  58 };
  59 
  60 static struct rave_sp_wdt *to_rave_sp_wdt(struct watchdog_device *wdd)
  61 {
  62         return container_of(wdd, struct rave_sp_wdt, wdd);
  63 }
  64 
  65 static int rave_sp_wdt_exec(struct watchdog_device *wdd, void *data,
  66                             size_t data_size)
  67 {
  68         return rave_sp_exec(to_rave_sp_wdt(wdd)->sp,
  69                             data, data_size, NULL, 0);
  70 }
  71 
  72 static int rave_sp_wdt_legacy_configure(struct watchdog_device *wdd, bool on)
  73 {
  74         u8 cmd[] = {
  75                 [0] = RAVE_SP_CMD_SW_WDT,
  76                 [1] = 0,
  77                 [2] = 0,
  78                 [3] = on,
  79                 [4] = on ? wdd->timeout : 0,
  80         };
  81 
  82         return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
  83 }
  84 
  85 static int rave_sp_wdt_rdu_configure(struct watchdog_device *wdd, bool on)
  86 {
  87         u8 cmd[] = {
  88                 [0] = RAVE_SP_CMD_SW_WDT,
  89                 [1] = 0,
  90                 [2] = on,
  91                 [3] = (u8)wdd->timeout,
  92                 [4] = (u8)(wdd->timeout >> 8),
  93         };
  94 
  95         return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
  96 }
  97 
  98 /**
  99  * rave_sp_wdt_configure - Configure watchdog device
 100  *
 101  * @wdd:        Device to configure
 102  * @on:         Desired state of the watchdog timer (ON/OFF)
 103  *
 104  * This function configures two aspects of the watchdog timer:
 105  *
 106  *  - Wheither it is ON or OFF
 107  *  - Its timeout duration
 108  *
 109  * with first aspect specified via function argument and second via
 110  * the value of 'wdd->timeout'.
 111  */
 112 static int rave_sp_wdt_configure(struct watchdog_device *wdd, bool on)
 113 {
 114         return to_rave_sp_wdt(wdd)->variant->configure(wdd, on);
 115 }
 116 
 117 static int rave_sp_wdt_legacy_restart(struct watchdog_device *wdd)
 118 {
 119         u8 cmd[] = {
 120                 [0] = RAVE_SP_CMD_RESET,
 121                 [1] = 0,
 122                 [2] = RAVE_SP_RESET_BYTE
 123         };
 124 
 125         return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
 126 }
 127 
 128 static int rave_sp_wdt_rdu_restart(struct watchdog_device *wdd)
 129 {
 130         u8 cmd[] = {
 131                 [0] = RAVE_SP_CMD_RESET,
 132                 [1] = 0,
 133                 [2] = RAVE_SP_RESET_BYTE,
 134                 [3] = RAVE_SP_RESET_REASON_NORMAL
 135         };
 136 
 137         return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
 138 }
 139 
 140 static int rave_sp_wdt_reboot_notifier(struct notifier_block *nb,
 141                                        unsigned long action, void *data)
 142 {
 143         /*
 144          * Restart handler is called in atomic context which means we
 145          * can't communicate to SP via UART. Luckily for use SP will
 146          * wait 500ms before actually resetting us, so we ask it to do
 147          * so here and let the rest of the system go on wrapping
 148          * things up.
 149          */
 150         if (action == SYS_DOWN || action == SYS_HALT) {
 151                 struct rave_sp_wdt *sp_wd =
 152                         container_of(nb, struct rave_sp_wdt, reboot_notifier);
 153 
 154                 const int ret = sp_wd->variant->restart(&sp_wd->wdd);
 155 
 156                 if (ret < 0)
 157                         dev_err(sp_wd->wdd.parent,
 158                                 "Failed to issue restart command (%d)", ret);
 159                 return NOTIFY_OK;
 160         }
 161 
 162         return NOTIFY_DONE;
 163 }
 164 
 165 static int rave_sp_wdt_restart(struct watchdog_device *wdd,
 166                                unsigned long action, void *data)
 167 {
 168         /*
 169          * The actual work was done by reboot notifier above. SP
 170          * firmware waits 500 ms before issuing reset, so let's hang
 171          * here for twice that delay and hopefuly we'd never reach
 172          * the return statement.
 173          */
 174         mdelay(2 * RAVE_SP_RESET_DELAY_MS);
 175 
 176         return -EIO;
 177 }
 178 
 179 static int rave_sp_wdt_start(struct watchdog_device *wdd)
 180 {
 181         int ret;
 182 
 183         ret = rave_sp_wdt_configure(wdd, true);
 184         if (!ret)
 185                 set_bit(WDOG_HW_RUNNING, &wdd->status);
 186 
 187         return ret;
 188 }
 189 
 190 static int rave_sp_wdt_stop(struct watchdog_device *wdd)
 191 {
 192         return rave_sp_wdt_configure(wdd, false);
 193 }
 194 
 195 static int rave_sp_wdt_set_timeout(struct watchdog_device *wdd,
 196                                    unsigned int timeout)
 197 {
 198         wdd->timeout = timeout;
 199 
 200         return rave_sp_wdt_configure(wdd, watchdog_active(wdd));
 201 }
 202 
 203 static int rave_sp_wdt_ping(struct watchdog_device *wdd)
 204 {
 205         u8 cmd[] = {
 206                 [0] = RAVE_SP_CMD_PET_WDT,
 207                 [1] = 0,
 208         };
 209 
 210         return rave_sp_wdt_exec(wdd, cmd, sizeof(cmd));
 211 }
 212 
 213 static const struct watchdog_info rave_sp_wdt_info = {
 214         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 215         .identity = "RAVE SP Watchdog",
 216 };
 217 
 218 static const struct watchdog_ops rave_sp_wdt_ops = {
 219         .owner = THIS_MODULE,
 220         .start = rave_sp_wdt_start,
 221         .stop = rave_sp_wdt_stop,
 222         .ping = rave_sp_wdt_ping,
 223         .set_timeout = rave_sp_wdt_set_timeout,
 224         .restart = rave_sp_wdt_restart,
 225 };
 226 
 227 static const struct rave_sp_wdt_variant rave_sp_wdt_legacy = {
 228         .max_timeout = 255,
 229         .min_timeout = 1,
 230         .configure = rave_sp_wdt_legacy_configure,
 231         .restart   = rave_sp_wdt_legacy_restart,
 232 };
 233 
 234 static const struct rave_sp_wdt_variant rave_sp_wdt_rdu = {
 235         .max_timeout = 180,
 236         .min_timeout = 60,
 237         .configure = rave_sp_wdt_rdu_configure,
 238         .restart   = rave_sp_wdt_rdu_restart,
 239 };
 240 
 241 static const struct of_device_id rave_sp_wdt_of_match[] = {
 242         {
 243                 .compatible = "zii,rave-sp-watchdog-legacy",
 244                 .data = &rave_sp_wdt_legacy,
 245         },
 246         {
 247                 .compatible = "zii,rave-sp-watchdog",
 248                 .data = &rave_sp_wdt_rdu,
 249         },
 250         { /* sentinel */ }
 251 };
 252 
 253 static int rave_sp_wdt_probe(struct platform_device *pdev)
 254 {
 255         struct device *dev = &pdev->dev;
 256         struct watchdog_device *wdd;
 257         struct rave_sp_wdt *sp_wd;
 258         struct nvmem_cell *cell;
 259         __le16 timeout = 0;
 260         int ret;
 261 
 262         sp_wd = devm_kzalloc(dev, sizeof(*sp_wd), GFP_KERNEL);
 263         if (!sp_wd)
 264                 return -ENOMEM;
 265 
 266         sp_wd->variant = of_device_get_match_data(dev);
 267         sp_wd->sp      = dev_get_drvdata(dev->parent);
 268 
 269         wdd              = &sp_wd->wdd;
 270         wdd->parent      = dev;
 271         wdd->info        = &rave_sp_wdt_info;
 272         wdd->ops         = &rave_sp_wdt_ops;
 273         wdd->min_timeout = sp_wd->variant->min_timeout;
 274         wdd->max_timeout = sp_wd->variant->max_timeout;
 275         wdd->status      = WATCHDOG_NOWAYOUT_INIT_STATUS;
 276         wdd->timeout     = 60;
 277 
 278         cell = nvmem_cell_get(dev, "wdt-timeout");
 279         if (!IS_ERR(cell)) {
 280                 size_t len;
 281                 void *value = nvmem_cell_read(cell, &len);
 282 
 283                 if (!IS_ERR(value)) {
 284                         memcpy(&timeout, value, min(len, sizeof(timeout)));
 285                         kfree(value);
 286                 }
 287                 nvmem_cell_put(cell);
 288         }
 289         watchdog_init_timeout(wdd, le16_to_cpu(timeout), dev);
 290         watchdog_set_restart_priority(wdd, 255);
 291         watchdog_stop_on_unregister(wdd);
 292 
 293         sp_wd->reboot_notifier.notifier_call = rave_sp_wdt_reboot_notifier;
 294         ret = devm_register_reboot_notifier(dev, &sp_wd->reboot_notifier);
 295         if (ret) {
 296                 dev_err(dev, "Failed to register reboot notifier\n");
 297                 return ret;
 298         }
 299 
 300         /*
 301          * We don't know if watchdog is running now. To be sure, let's
 302          * start it and depend on watchdog core to ping it
 303          */
 304         wdd->max_hw_heartbeat_ms = wdd->max_timeout * 1000;
 305         ret = rave_sp_wdt_start(wdd);
 306         if (ret) {
 307                 dev_err(dev, "Watchdog didn't start\n");
 308                 return ret;
 309         }
 310 
 311         ret = devm_watchdog_register_device(dev, wdd);
 312         if (ret) {
 313                 rave_sp_wdt_stop(wdd);
 314                 return ret;
 315         }
 316 
 317         return 0;
 318 }
 319 
 320 static struct platform_driver rave_sp_wdt_driver = {
 321         .probe = rave_sp_wdt_probe,
 322         .driver = {
 323                 .name = KBUILD_MODNAME,
 324                 .of_match_table = rave_sp_wdt_of_match,
 325         },
 326 };
 327 
 328 module_platform_driver(rave_sp_wdt_driver);
 329 
 330 MODULE_DEVICE_TABLE(of, rave_sp_wdt_of_match);
 331 MODULE_LICENSE("GPL");
 332 MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
 333 MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
 334 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
 335 MODULE_DESCRIPTION("RAVE SP Watchdog driver");
 336 MODULE_ALIAS("platform:rave-sp-watchdog");

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