root/drivers/watchdog/npcm_wdt.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_npcm_wdt
  2. npcm_wdt_ping
  3. npcm_wdt_start
  4. npcm_wdt_stop
  5. npcm_wdt_set_timeout
  6. npcm_wdt_interrupt
  7. npcm_wdt_restart
  8. npcm_is_running
  9. npcm_wdt_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 // Copyright (c) 2018 Nuvoton Technology corporation.
   3 // Copyright (c) 2018 IBM Corp.
   4 
   5 #include <linux/bitops.h>
   6 #include <linux/delay.h>
   7 #include <linux/interrupt.h>
   8 #include <linux/kernel.h>
   9 #include <linux/module.h>
  10 #include <linux/of_irq.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/slab.h>
  13 #include <linux/watchdog.h>
  14 
  15 #define NPCM_WTCR       0x1C
  16 
  17 #define NPCM_WTCLK      (BIT(10) | BIT(11))     /* Clock divider */
  18 #define NPCM_WTE        BIT(7)                  /* Enable */
  19 #define NPCM_WTIE       BIT(6)                  /* Enable irq */
  20 #define NPCM_WTIS       (BIT(4) | BIT(5))       /* Interval selection */
  21 #define NPCM_WTIF       BIT(3)                  /* Interrupt flag*/
  22 #define NPCM_WTRF       BIT(2)                  /* Reset flag */
  23 #define NPCM_WTRE       BIT(1)                  /* Reset enable */
  24 #define NPCM_WTR        BIT(0)                  /* Reset counter */
  25 
  26 /*
  27  * Watchdog timeouts
  28  *
  29  * 170     msec:    WTCLK=01 WTIS=00     VAL= 0x400
  30  * 670     msec:    WTCLK=01 WTIS=01     VAL= 0x410
  31  * 1360    msec:    WTCLK=10 WTIS=00     VAL= 0x800
  32  * 2700    msec:    WTCLK=01 WTIS=10     VAL= 0x420
  33  * 5360    msec:    WTCLK=10 WTIS=01     VAL= 0x810
  34  * 10700   msec:    WTCLK=01 WTIS=11     VAL= 0x430
  35  * 21600   msec:    WTCLK=10 WTIS=10     VAL= 0x820
  36  * 43000   msec:    WTCLK=11 WTIS=00     VAL= 0xC00
  37  * 85600   msec:    WTCLK=10 WTIS=11     VAL= 0x830
  38  * 172000  msec:    WTCLK=11 WTIS=01     VAL= 0xC10
  39  * 687000  msec:    WTCLK=11 WTIS=10     VAL= 0xC20
  40  * 2750000 msec:    WTCLK=11 WTIS=11     VAL= 0xC30
  41  */
  42 
  43 struct npcm_wdt {
  44         struct watchdog_device  wdd;
  45         void __iomem            *reg;
  46 };
  47 
  48 static inline struct npcm_wdt *to_npcm_wdt(struct watchdog_device *wdd)
  49 {
  50         return container_of(wdd, struct npcm_wdt, wdd);
  51 }
  52 
  53 static int npcm_wdt_ping(struct watchdog_device *wdd)
  54 {
  55         struct npcm_wdt *wdt = to_npcm_wdt(wdd);
  56         u32 val;
  57 
  58         val = readl(wdt->reg);
  59         writel(val | NPCM_WTR, wdt->reg);
  60 
  61         return 0;
  62 }
  63 
  64 static int npcm_wdt_start(struct watchdog_device *wdd)
  65 {
  66         struct npcm_wdt *wdt = to_npcm_wdt(wdd);
  67         u32 val;
  68 
  69         if (wdd->timeout < 2)
  70                 val = 0x800;
  71         else if (wdd->timeout < 3)
  72                 val = 0x420;
  73         else if (wdd->timeout < 6)
  74                 val = 0x810;
  75         else if (wdd->timeout < 11)
  76                 val = 0x430;
  77         else if (wdd->timeout < 22)
  78                 val = 0x820;
  79         else if (wdd->timeout < 44)
  80                 val = 0xC00;
  81         else if (wdd->timeout < 87)
  82                 val = 0x830;
  83         else if (wdd->timeout < 173)
  84                 val = 0xC10;
  85         else if (wdd->timeout < 688)
  86                 val = 0xC20;
  87         else
  88                 val = 0xC30;
  89 
  90         val |= NPCM_WTRE | NPCM_WTE | NPCM_WTR | NPCM_WTIE;
  91 
  92         writel(val, wdt->reg);
  93 
  94         return 0;
  95 }
  96 
  97 static int npcm_wdt_stop(struct watchdog_device *wdd)
  98 {
  99         struct npcm_wdt *wdt = to_npcm_wdt(wdd);
 100 
 101         writel(0, wdt->reg);
 102 
 103         return 0;
 104 }
 105 
 106 
 107 static int npcm_wdt_set_timeout(struct watchdog_device *wdd,
 108                                 unsigned int timeout)
 109 {
 110         if (timeout < 2)
 111                 wdd->timeout = 1;
 112         else if (timeout < 3)
 113               wdd->timeout = 2;
 114         else if (timeout < 6)
 115               wdd->timeout = 5;
 116         else if (timeout < 11)
 117               wdd->timeout = 10;
 118         else if (timeout < 22)
 119               wdd->timeout = 21;
 120         else if (timeout < 44)
 121               wdd->timeout = 43;
 122         else if (timeout < 87)
 123               wdd->timeout = 86;
 124         else if (timeout < 173)
 125               wdd->timeout = 172;
 126         else if (timeout < 688)
 127               wdd->timeout = 687;
 128         else
 129               wdd->timeout = 2750;
 130 
 131         if (watchdog_active(wdd))
 132                 npcm_wdt_start(wdd);
 133 
 134         return 0;
 135 }
 136 
 137 static irqreturn_t npcm_wdt_interrupt(int irq, void *data)
 138 {
 139         struct npcm_wdt *wdt = data;
 140 
 141         watchdog_notify_pretimeout(&wdt->wdd);
 142 
 143         return IRQ_HANDLED;
 144 }
 145 
 146 static int npcm_wdt_restart(struct watchdog_device *wdd,
 147                             unsigned long action, void *data)
 148 {
 149         struct npcm_wdt *wdt = to_npcm_wdt(wdd);
 150 
 151         writel(NPCM_WTR | NPCM_WTRE | NPCM_WTE, wdt->reg);
 152         udelay(1000);
 153 
 154         return 0;
 155 }
 156 
 157 static bool npcm_is_running(struct watchdog_device *wdd)
 158 {
 159         struct npcm_wdt *wdt = to_npcm_wdt(wdd);
 160 
 161         return readl(wdt->reg) & NPCM_WTE;
 162 }
 163 
 164 static const struct watchdog_info npcm_wdt_info = {
 165         .identity       = KBUILD_MODNAME,
 166         .options        = WDIOF_SETTIMEOUT
 167                         | WDIOF_KEEPALIVEPING
 168                         | WDIOF_MAGICCLOSE,
 169 };
 170 
 171 static const struct watchdog_ops npcm_wdt_ops = {
 172         .owner = THIS_MODULE,
 173         .start = npcm_wdt_start,
 174         .stop = npcm_wdt_stop,
 175         .ping = npcm_wdt_ping,
 176         .set_timeout = npcm_wdt_set_timeout,
 177         .restart = npcm_wdt_restart,
 178 };
 179 
 180 static int npcm_wdt_probe(struct platform_device *pdev)
 181 {
 182         struct device *dev = &pdev->dev;
 183         struct npcm_wdt *wdt;
 184         int irq;
 185         int ret;
 186 
 187         wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
 188         if (!wdt)
 189                 return -ENOMEM;
 190 
 191         wdt->reg = devm_platform_ioremap_resource(pdev, 0);
 192         if (IS_ERR(wdt->reg))
 193                 return PTR_ERR(wdt->reg);
 194 
 195         irq = platform_get_irq(pdev, 0);
 196         if (irq < 0)
 197                 return irq;
 198 
 199         wdt->wdd.info = &npcm_wdt_info;
 200         wdt->wdd.ops = &npcm_wdt_ops;
 201         wdt->wdd.min_timeout = 1;
 202         wdt->wdd.max_timeout = 2750;
 203         wdt->wdd.parent = dev;
 204 
 205         wdt->wdd.timeout = 86;
 206         watchdog_init_timeout(&wdt->wdd, 0, dev);
 207 
 208         /* Ensure timeout is able to be represented by the hardware */
 209         npcm_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
 210 
 211         if (npcm_is_running(&wdt->wdd)) {
 212                 /* Restart with the default or device-tree specified timeout */
 213                 npcm_wdt_start(&wdt->wdd);
 214                 set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
 215         }
 216 
 217         ret = devm_request_irq(dev, irq, npcm_wdt_interrupt, 0, "watchdog",
 218                                wdt);
 219         if (ret)
 220                 return ret;
 221 
 222         ret = devm_watchdog_register_device(dev, &wdt->wdd);
 223         if (ret)
 224                 return ret;
 225 
 226         dev_info(dev, "NPCM watchdog driver enabled\n");
 227 
 228         return 0;
 229 }
 230 
 231 #ifdef CONFIG_OF
 232 static const struct of_device_id npcm_wdt_match[] = {
 233         {.compatible = "nuvoton,npcm750-wdt"},
 234         {},
 235 };
 236 MODULE_DEVICE_TABLE(of, npcm_wdt_match);
 237 #endif
 238 
 239 static struct platform_driver npcm_wdt_driver = {
 240         .probe          = npcm_wdt_probe,
 241         .driver         = {
 242                 .name   = "npcm-wdt",
 243                 .of_match_table = of_match_ptr(npcm_wdt_match),
 244         },
 245 };
 246 module_platform_driver(npcm_wdt_driver);
 247 
 248 MODULE_AUTHOR("Joel Stanley");
 249 MODULE_DESCRIPTION("Watchdog driver for NPCM");
 250 MODULE_LICENSE("GPL v2");

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