1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 276534860SWenyou Yang /* 376534860SWenyou Yang * Driver for Atmel SAMA5D4 Watchdog Timer 476534860SWenyou Yang * 5bb44aa09SEugen Hristev * Copyright (C) 2015-2019 Microchip Technology Inc. and its subsidiaries 676534860SWenyou Yang */ 776534860SWenyou Yang 8ddd6d240SAlexandre Belloni #include <linux/delay.h> 976534860SWenyou Yang #include <linux/interrupt.h> 1076534860SWenyou Yang #include <linux/io.h> 1176534860SWenyou Yang #include <linux/kernel.h> 1276534860SWenyou Yang #include <linux/module.h> 1376534860SWenyou Yang #include <linux/of.h> 1476534860SWenyou Yang #include <linux/of_irq.h> 1576534860SWenyou Yang #include <linux/platform_device.h> 1676534860SWenyou Yang #include <linux/reboot.h> 1776534860SWenyou Yang #include <linux/watchdog.h> 1876534860SWenyou Yang 1976534860SWenyou Yang #include "at91sam9_wdt.h" 2076534860SWenyou Yang 2176534860SWenyou Yang /* minimum and maximum watchdog timeout, in seconds */ 2276534860SWenyou Yang #define MIN_WDT_TIMEOUT 1 2376534860SWenyou Yang #define MAX_WDT_TIMEOUT 16 2476534860SWenyou Yang #define WDT_DEFAULT_TIMEOUT MAX_WDT_TIMEOUT 2576534860SWenyou Yang 2676534860SWenyou Yang #define WDT_SEC2TICKS(s) ((s) ? (((s) << 8) - 1) : 0) 2776534860SWenyou Yang 2876534860SWenyou Yang struct sama5d4_wdt { 2976534860SWenyou Yang struct watchdog_device wdd; 3076534860SWenyou Yang void __iomem *reg_base; 31722ce635SAlexandre Belloni u32 mr; 32bb44aa09SEugen Hristev u32 ir; 33ddd6d240SAlexandre Belloni unsigned long last_ping; 34bb44aa09SEugen Hristev bool need_irq; 35bb44aa09SEugen Hristev bool sam9x60_support; 3676534860SWenyou Yang }; 3776534860SWenyou Yang 38976932e4SMarcus Folkesson static int wdt_timeout; 3976534860SWenyou Yang static bool nowayout = WATCHDOG_NOWAYOUT; 4076534860SWenyou Yang 4176534860SWenyou Yang module_param(wdt_timeout, int, 0); 4276534860SWenyou Yang MODULE_PARM_DESC(wdt_timeout, 4376534860SWenyou Yang "Watchdog timeout in seconds. (default = " 4476534860SWenyou Yang __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); 4576534860SWenyou Yang 4676534860SWenyou Yang module_param(nowayout, bool, 0); 4776534860SWenyou Yang MODULE_PARM_DESC(nowayout, 4876534860SWenyou Yang "Watchdog cannot be stopped once started (default=" 4976534860SWenyou Yang __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 5076534860SWenyou Yang 51015b5286SAlexandre Belloni #define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS)) 52015b5286SAlexandre Belloni 5376534860SWenyou Yang #define wdt_read(wdt, field) \ 5476534860SWenyou Yang readl_relaxed((wdt)->reg_base + (field)) 5576534860SWenyou Yang 56ddd6d240SAlexandre Belloni /* 4 slow clock periods is 4/32768 = 122.07µs*/ 57ddd6d240SAlexandre Belloni #define WDT_DELAY usecs_to_jiffies(123) 58ddd6d240SAlexandre Belloni 59ddd6d240SAlexandre Belloni static void wdt_write(struct sama5d4_wdt *wdt, u32 field, u32 val) 60ddd6d240SAlexandre Belloni { 61ddd6d240SAlexandre Belloni /* 62ddd6d240SAlexandre Belloni * WDT_CR and WDT_MR must not be modified within three slow clock 63ddd6d240SAlexandre Belloni * periods following a restart of the watchdog performed by a write 64ddd6d240SAlexandre Belloni * access in WDT_CR. 65ddd6d240SAlexandre Belloni */ 66ddd6d240SAlexandre Belloni while (time_before(jiffies, wdt->last_ping + WDT_DELAY)) 67ddd6d240SAlexandre Belloni usleep_range(30, 125); 68ddd6d240SAlexandre Belloni writel_relaxed(val, wdt->reg_base + field); 69ddd6d240SAlexandre Belloni wdt->last_ping = jiffies; 70ddd6d240SAlexandre Belloni } 71ddd6d240SAlexandre Belloni 72ddd6d240SAlexandre Belloni static void wdt_write_nosleep(struct sama5d4_wdt *wdt, u32 field, u32 val) 73ddd6d240SAlexandre Belloni { 74ddd6d240SAlexandre Belloni if (time_before(jiffies, wdt->last_ping + WDT_DELAY)) 75ddd6d240SAlexandre Belloni udelay(123); 76ddd6d240SAlexandre Belloni writel_relaxed(val, wdt->reg_base + field); 77ddd6d240SAlexandre Belloni wdt->last_ping = jiffies; 78ddd6d240SAlexandre Belloni } 7976534860SWenyou Yang 8076534860SWenyou Yang static int sama5d4_wdt_start(struct watchdog_device *wdd) 8176534860SWenyou Yang { 8276534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 8376534860SWenyou Yang 84bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 85bb44aa09SEugen Hristev writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER); 86bb44aa09SEugen Hristev wdt->mr &= ~AT91_SAM9X60_WDDIS; 87bb44aa09SEugen Hristev } else { 88722ce635SAlexandre Belloni wdt->mr &= ~AT91_WDT_WDDIS; 89bb44aa09SEugen Hristev } 90722ce635SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr); 9176534860SWenyou Yang 9276534860SWenyou Yang return 0; 9376534860SWenyou Yang } 9476534860SWenyou Yang 9576534860SWenyou Yang static int sama5d4_wdt_stop(struct watchdog_device *wdd) 9676534860SWenyou Yang { 9776534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 9876534860SWenyou Yang 99bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 100bb44aa09SEugen Hristev writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR); 101bb44aa09SEugen Hristev wdt->mr |= AT91_SAM9X60_WDDIS; 102bb44aa09SEugen Hristev } else { 103722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDDIS; 104bb44aa09SEugen Hristev } 105722ce635SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr); 10676534860SWenyou Yang 10776534860SWenyou Yang return 0; 10876534860SWenyou Yang } 10976534860SWenyou Yang 11076534860SWenyou Yang static int sama5d4_wdt_ping(struct watchdog_device *wdd) 11176534860SWenyou Yang { 11276534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 11376534860SWenyou Yang 11476534860SWenyou Yang wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); 11576534860SWenyou Yang 11676534860SWenyou Yang return 0; 11776534860SWenyou Yang } 11876534860SWenyou Yang 11976534860SWenyou Yang static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, 12076534860SWenyou Yang unsigned int timeout) 12176534860SWenyou Yang { 12276534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 12376534860SWenyou Yang u32 value = WDT_SEC2TICKS(timeout); 12476534860SWenyou Yang 125bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 126bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_WLR, 127bb44aa09SEugen Hristev AT91_SAM9X60_SET_COUNTER(value)); 128bb44aa09SEugen Hristev 129bb44aa09SEugen Hristev wdd->timeout = timeout; 130bb44aa09SEugen Hristev return 0; 131bb44aa09SEugen Hristev } 132bb44aa09SEugen Hristev 133722ce635SAlexandre Belloni wdt->mr &= ~AT91_WDT_WDV; 134722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_SET_WDV(value); 135015b5286SAlexandre Belloni 136015b5286SAlexandre Belloni /* 137015b5286SAlexandre Belloni * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When 138015b5286SAlexandre Belloni * setting the WDDIS bit, and while it is set, the fields WDV and WDD 139015b5286SAlexandre Belloni * must not be modified. 140015b5286SAlexandre Belloni * If the watchdog is enabled, then the timeout can be updated. Else, 141015b5286SAlexandre Belloni * wait that the user enables it. 142015b5286SAlexandre Belloni */ 143015b5286SAlexandre Belloni if (wdt_enabled) 144015b5286SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); 14576534860SWenyou Yang 14676534860SWenyou Yang wdd->timeout = timeout; 14776534860SWenyou Yang 14876534860SWenyou Yang return 0; 14976534860SWenyou Yang } 15076534860SWenyou Yang 15176534860SWenyou Yang static const struct watchdog_info sama5d4_wdt_info = { 15276534860SWenyou Yang .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 15376534860SWenyou Yang .identity = "Atmel SAMA5D4 Watchdog", 15476534860SWenyou Yang }; 15576534860SWenyou Yang 156b893e344SBhumika Goyal static const struct watchdog_ops sama5d4_wdt_ops = { 15776534860SWenyou Yang .owner = THIS_MODULE, 15876534860SWenyou Yang .start = sama5d4_wdt_start, 15976534860SWenyou Yang .stop = sama5d4_wdt_stop, 16076534860SWenyou Yang .ping = sama5d4_wdt_ping, 16176534860SWenyou Yang .set_timeout = sama5d4_wdt_set_timeout, 16276534860SWenyou Yang }; 16376534860SWenyou Yang 16476534860SWenyou Yang static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id) 16576534860SWenyou Yang { 16676534860SWenyou Yang struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id); 167bb44aa09SEugen Hristev u32 reg; 16876534860SWenyou Yang 169bb44aa09SEugen Hristev if (wdt->sam9x60_support) 170bb44aa09SEugen Hristev reg = wdt_read(wdt, AT91_SAM9X60_ISR); 171bb44aa09SEugen Hristev else 172bb44aa09SEugen Hristev reg = wdt_read(wdt, AT91_WDT_SR); 173bb44aa09SEugen Hristev 174bb44aa09SEugen Hristev if (reg) { 17576534860SWenyou Yang pr_crit("Atmel Watchdog Software Reset\n"); 17676534860SWenyou Yang emergency_restart(); 17776534860SWenyou Yang pr_crit("Reboot didn't succeed\n"); 17876534860SWenyou Yang } 17976534860SWenyou Yang 18076534860SWenyou Yang return IRQ_HANDLED; 18176534860SWenyou Yang } 18276534860SWenyou Yang 18376534860SWenyou Yang static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) 18476534860SWenyou Yang { 18576534860SWenyou Yang const char *tmp; 18676534860SWenyou Yang 187bb44aa09SEugen Hristev if (wdt->sam9x60_support) 188bb44aa09SEugen Hristev wdt->mr = AT91_SAM9X60_WDDIS; 189bb44aa09SEugen Hristev else 190722ce635SAlexandre Belloni wdt->mr = AT91_WDT_WDDIS; 19176534860SWenyou Yang 19276534860SWenyou Yang if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && 19376534860SWenyou Yang !strcmp(tmp, "software")) 194bb44aa09SEugen Hristev wdt->need_irq = true; 19576534860SWenyou Yang 19676534860SWenyou Yang if (of_property_read_bool(np, "atmel,idle-halt")) 197722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDIDLEHLT; 19876534860SWenyou Yang 19976534860SWenyou Yang if (of_property_read_bool(np, "atmel,dbg-halt")) 200722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDDBGHLT; 20176534860SWenyou Yang 20276534860SWenyou Yang return 0; 20376534860SWenyou Yang } 20476534860SWenyou Yang 20576534860SWenyou Yang static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) 20676534860SWenyou Yang { 207bb44aa09SEugen Hristev u32 reg, val; 208bb44aa09SEugen Hristev 209bb44aa09SEugen Hristev val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT); 21076534860SWenyou Yang /* 211015b5286SAlexandre Belloni * When booting and resuming, the bootloader may have changed the 212015b5286SAlexandre Belloni * watchdog configuration. 213015b5286SAlexandre Belloni * If the watchdog is already running, we can safely update it. 214015b5286SAlexandre Belloni * Else, we have to disable it properly. 21576534860SWenyou Yang */ 216bb44aa09SEugen Hristev if (!wdt_enabled) { 217015b5286SAlexandre Belloni reg = wdt_read(wdt, AT91_WDT_MR); 218bb44aa09SEugen Hristev if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS))) 219bb44aa09SEugen Hristev wdt_write_nosleep(wdt, AT91_WDT_MR, 220bb44aa09SEugen Hristev reg | AT91_SAM9X60_WDDIS); 221bb44aa09SEugen Hristev else if (!wdt->sam9x60_support && 222bb44aa09SEugen Hristev (!(reg & AT91_WDT_WDDIS))) 223ddd6d240SAlexandre Belloni wdt_write_nosleep(wdt, AT91_WDT_MR, 224ddd6d240SAlexandre Belloni reg | AT91_WDT_WDDIS); 225015b5286SAlexandre Belloni } 226bb44aa09SEugen Hristev 227bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 228bb44aa09SEugen Hristev if (wdt->need_irq) 229bb44aa09SEugen Hristev wdt->ir = AT91_SAM9X60_PERINT; 230bb44aa09SEugen Hristev else 231bb44aa09SEugen Hristev wdt->mr |= AT91_SAM9X60_PERIODRST; 232bb44aa09SEugen Hristev 233bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_IER, wdt->ir); 234bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_WLR, AT91_SAM9X60_SET_COUNTER(val)); 235bb44aa09SEugen Hristev } else { 236bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT)); 237bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_SET_WDV(val); 238bb44aa09SEugen Hristev 239bb44aa09SEugen Hristev if (wdt->need_irq) 240bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_WDFIEN; 241bb44aa09SEugen Hristev else 242bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_WDRSTEN; 243bb44aa09SEugen Hristev } 244bb44aa09SEugen Hristev 245bb44aa09SEugen Hristev wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr); 246bb44aa09SEugen Hristev 24776534860SWenyou Yang return 0; 24876534860SWenyou Yang } 24976534860SWenyou Yang 25076534860SWenyou Yang static int sama5d4_wdt_probe(struct platform_device *pdev) 25176534860SWenyou Yang { 252dcc3ce0bSGuenter Roeck struct device *dev = &pdev->dev; 25376534860SWenyou Yang struct watchdog_device *wdd; 25476534860SWenyou Yang struct sama5d4_wdt *wdt; 25576534860SWenyou Yang void __iomem *regs; 25676534860SWenyou Yang u32 irq = 0; 257*266da53cSMathieu Othacehe u32 reg; 25876534860SWenyou Yang int ret; 25976534860SWenyou Yang 260dcc3ce0bSGuenter Roeck wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); 26176534860SWenyou Yang if (!wdt) 26276534860SWenyou Yang return -ENOMEM; 26376534860SWenyou Yang 26476534860SWenyou Yang wdd = &wdt->wdd; 265976932e4SMarcus Folkesson wdd->timeout = WDT_DEFAULT_TIMEOUT; 26676534860SWenyou Yang wdd->info = &sama5d4_wdt_info; 26776534860SWenyou Yang wdd->ops = &sama5d4_wdt_ops; 26876534860SWenyou Yang wdd->min_timeout = MIN_WDT_TIMEOUT; 26976534860SWenyou Yang wdd->max_timeout = MAX_WDT_TIMEOUT; 270ddd6d240SAlexandre Belloni wdt->last_ping = jiffies; 2715ae233fbSEugen Hristev 2725ae233fbSEugen Hristev if (of_device_is_compatible(dev->of_node, "microchip,sam9x60-wdt") || 2735ae233fbSEugen Hristev of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt")) 2745ae233fbSEugen Hristev wdt->sam9x60_support = true; 27576534860SWenyou Yang 27676534860SWenyou Yang watchdog_set_drvdata(wdd, wdt); 27776534860SWenyou Yang 2780f0a6a28SGuenter Roeck regs = devm_platform_ioremap_resource(pdev, 0); 27976534860SWenyou Yang if (IS_ERR(regs)) 28076534860SWenyou Yang return PTR_ERR(regs); 28176534860SWenyou Yang 28276534860SWenyou Yang wdt->reg_base = regs; 28376534860SWenyou Yang 284dcc3ce0bSGuenter Roeck ret = of_sama5d4_wdt_init(dev->of_node, wdt); 28576534860SWenyou Yang if (ret) 28676534860SWenyou Yang return ret; 28776534860SWenyou Yang 288bb44aa09SEugen Hristev if (wdt->need_irq) { 289bb44aa09SEugen Hristev irq = irq_of_parse_and_map(dev->of_node, 0); 290bb44aa09SEugen Hristev if (!irq) { 291bb44aa09SEugen Hristev dev_warn(dev, "failed to get IRQ from DT\n"); 292bb44aa09SEugen Hristev wdt->need_irq = false; 293bb44aa09SEugen Hristev } 294bb44aa09SEugen Hristev } 295bb44aa09SEugen Hristev 296bb44aa09SEugen Hristev if (wdt->need_irq) { 297dcc3ce0bSGuenter Roeck ret = devm_request_irq(dev, irq, sama5d4_wdt_irq_handler, 29876534860SWenyou Yang IRQF_SHARED | IRQF_IRQPOLL | 29976534860SWenyou Yang IRQF_NO_SUSPEND, pdev->name, pdev); 30076534860SWenyou Yang if (ret) { 301dcc3ce0bSGuenter Roeck dev_err(dev, "cannot register interrupt handler\n"); 30276534860SWenyou Yang return ret; 30376534860SWenyou Yang } 30476534860SWenyou Yang } 30576534860SWenyou Yang 306dcc3ce0bSGuenter Roeck watchdog_init_timeout(wdd, wdt_timeout, dev); 30776534860SWenyou Yang 308*266da53cSMathieu Othacehe reg = wdt_read(wdt, AT91_WDT_MR); 309*266da53cSMathieu Othacehe if (!(reg & AT91_WDT_WDDIS)) { 310*266da53cSMathieu Othacehe wdt->mr &= ~AT91_WDT_WDDIS; 311*266da53cSMathieu Othacehe set_bit(WDOG_HW_RUNNING, &wdd->status); 312*266da53cSMathieu Othacehe } 313*266da53cSMathieu Othacehe 31476534860SWenyou Yang ret = sama5d4_wdt_init(wdt); 31576534860SWenyou Yang if (ret) 31676534860SWenyou Yang return ret; 31776534860SWenyou Yang 31876534860SWenyou Yang watchdog_set_nowayout(wdd, nowayout); 31976534860SWenyou Yang 320dcc3ce0bSGuenter Roeck watchdog_stop_on_unregister(wdd); 321dcc3ce0bSGuenter Roeck ret = devm_watchdog_register_device(dev, wdd); 32224b8eb74SWolfram Sang if (ret) 32376534860SWenyou Yang return ret; 32476534860SWenyou Yang 32576534860SWenyou Yang platform_set_drvdata(pdev, wdt); 32676534860SWenyou Yang 327dcc3ce0bSGuenter Roeck dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n", 328976932e4SMarcus Folkesson wdd->timeout, nowayout); 32976534860SWenyou Yang 33076534860SWenyou Yang return 0; 33176534860SWenyou Yang } 33276534860SWenyou Yang 33376534860SWenyou Yang static const struct of_device_id sama5d4_wdt_of_match[] = { 334bb44aa09SEugen Hristev { 335bb44aa09SEugen Hristev .compatible = "atmel,sama5d4-wdt", 336bb44aa09SEugen Hristev }, 337bb44aa09SEugen Hristev { 338bb44aa09SEugen Hristev .compatible = "microchip,sam9x60-wdt", 339bb44aa09SEugen Hristev }, 3405ae233fbSEugen Hristev { 3415ae233fbSEugen Hristev .compatible = "microchip,sama7g5-wdt", 3425ae233fbSEugen Hristev }, 3435ae233fbSEugen Hristev 34476534860SWenyou Yang { } 34576534860SWenyou Yang }; 34676534860SWenyou Yang MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); 34776534860SWenyou Yang 3488d209eb0SKen Sloat static int sama5d4_wdt_suspend_late(struct device *dev) 3498d209eb0SKen Sloat { 3508d209eb0SKen Sloat struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 3518d209eb0SKen Sloat 3528d209eb0SKen Sloat if (watchdog_active(&wdt->wdd)) 3538d209eb0SKen Sloat sama5d4_wdt_stop(&wdt->wdd); 3548d209eb0SKen Sloat 3558d209eb0SKen Sloat return 0; 3568d209eb0SKen Sloat } 3578d209eb0SKen Sloat 3588d209eb0SKen Sloat static int sama5d4_wdt_resume_early(struct device *dev) 359f2013532SAlexandre Belloni { 360f2013532SAlexandre Belloni struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 361f2013532SAlexandre Belloni 3625dca80f6SAlexandre Belloni /* 3635dca80f6SAlexandre Belloni * FIXME: writing MR also pings the watchdog which may not be desired. 3645dca80f6SAlexandre Belloni * This should only be done when the registers are lost on suspend but 3655dca80f6SAlexandre Belloni * there is no way to get this information right now. 3665dca80f6SAlexandre Belloni */ 367015b5286SAlexandre Belloni sama5d4_wdt_init(wdt); 368f2013532SAlexandre Belloni 3698d209eb0SKen Sloat if (watchdog_active(&wdt->wdd)) 3708d209eb0SKen Sloat sama5d4_wdt_start(&wdt->wdd); 3718d209eb0SKen Sloat 372f2013532SAlexandre Belloni return 0; 373f2013532SAlexandre Belloni } 374f2013532SAlexandre Belloni 3758d209eb0SKen Sloat static const struct dev_pm_ops sama5d4_wdt_pm_ops = { 3765c040ea2SPaul Cercueil LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late, 3778d209eb0SKen Sloat sama5d4_wdt_resume_early) 3788d209eb0SKen Sloat }; 379f2013532SAlexandre Belloni 38076534860SWenyou Yang static struct platform_driver sama5d4_wdt_driver = { 38176534860SWenyou Yang .probe = sama5d4_wdt_probe, 38276534860SWenyou Yang .driver = { 38376534860SWenyou Yang .name = "sama5d4_wdt", 3845c040ea2SPaul Cercueil .pm = pm_sleep_ptr(&sama5d4_wdt_pm_ops), 38576534860SWenyou Yang .of_match_table = sama5d4_wdt_of_match, 38676534860SWenyou Yang } 38776534860SWenyou Yang }; 38876534860SWenyou Yang module_platform_driver(sama5d4_wdt_driver); 38976534860SWenyou Yang 39076534860SWenyou Yang MODULE_AUTHOR("Atmel Corporation"); 39176534860SWenyou Yang MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver"); 39276534860SWenyou Yang MODULE_LICENSE("GPL v2"); 393