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> 14bb44aa09SEugen Hristev #include <linux/of_device.h> 1576534860SWenyou Yang #include <linux/of_irq.h> 1676534860SWenyou Yang #include <linux/platform_device.h> 1776534860SWenyou Yang #include <linux/reboot.h> 1876534860SWenyou Yang #include <linux/watchdog.h> 1976534860SWenyou Yang 2076534860SWenyou Yang #include "at91sam9_wdt.h" 2176534860SWenyou Yang 2276534860SWenyou Yang /* minimum and maximum watchdog timeout, in seconds */ 2376534860SWenyou Yang #define MIN_WDT_TIMEOUT 1 2476534860SWenyou Yang #define MAX_WDT_TIMEOUT 16 2576534860SWenyou Yang #define WDT_DEFAULT_TIMEOUT MAX_WDT_TIMEOUT 2676534860SWenyou Yang 2776534860SWenyou Yang #define WDT_SEC2TICKS(s) ((s) ? (((s) << 8) - 1) : 0) 2876534860SWenyou Yang 2976534860SWenyou Yang struct sama5d4_wdt { 3076534860SWenyou Yang struct watchdog_device wdd; 3176534860SWenyou Yang void __iomem *reg_base; 32722ce635SAlexandre Belloni u32 mr; 33bb44aa09SEugen Hristev u32 ir; 34ddd6d240SAlexandre Belloni unsigned long last_ping; 35bb44aa09SEugen Hristev bool need_irq; 36bb44aa09SEugen Hristev bool sam9x60_support; 3776534860SWenyou Yang }; 3876534860SWenyou Yang 39976932e4SMarcus Folkesson static int wdt_timeout; 4076534860SWenyou Yang static bool nowayout = WATCHDOG_NOWAYOUT; 4176534860SWenyou Yang 4276534860SWenyou Yang module_param(wdt_timeout, int, 0); 4376534860SWenyou Yang MODULE_PARM_DESC(wdt_timeout, 4476534860SWenyou Yang "Watchdog timeout in seconds. (default = " 4576534860SWenyou Yang __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); 4676534860SWenyou Yang 4776534860SWenyou Yang module_param(nowayout, bool, 0); 4876534860SWenyou Yang MODULE_PARM_DESC(nowayout, 4976534860SWenyou Yang "Watchdog cannot be stopped once started (default=" 5076534860SWenyou Yang __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 5176534860SWenyou Yang 52015b5286SAlexandre Belloni #define wdt_enabled (!(wdt->mr & AT91_WDT_WDDIS)) 53015b5286SAlexandre Belloni 5476534860SWenyou Yang #define wdt_read(wdt, field) \ 5576534860SWenyou Yang readl_relaxed((wdt)->reg_base + (field)) 5676534860SWenyou Yang 57ddd6d240SAlexandre Belloni /* 4 slow clock periods is 4/32768 = 122.07µs*/ 58ddd6d240SAlexandre Belloni #define WDT_DELAY usecs_to_jiffies(123) 59ddd6d240SAlexandre Belloni 60ddd6d240SAlexandre Belloni static void wdt_write(struct sama5d4_wdt *wdt, u32 field, u32 val) 61ddd6d240SAlexandre Belloni { 62ddd6d240SAlexandre Belloni /* 63ddd6d240SAlexandre Belloni * WDT_CR and WDT_MR must not be modified within three slow clock 64ddd6d240SAlexandre Belloni * periods following a restart of the watchdog performed by a write 65ddd6d240SAlexandre Belloni * access in WDT_CR. 66ddd6d240SAlexandre Belloni */ 67ddd6d240SAlexandre Belloni while (time_before(jiffies, wdt->last_ping + WDT_DELAY)) 68ddd6d240SAlexandre Belloni usleep_range(30, 125); 69ddd6d240SAlexandre Belloni writel_relaxed(val, wdt->reg_base + field); 70ddd6d240SAlexandre Belloni wdt->last_ping = jiffies; 71ddd6d240SAlexandre Belloni } 72ddd6d240SAlexandre Belloni 73ddd6d240SAlexandre Belloni static void wdt_write_nosleep(struct sama5d4_wdt *wdt, u32 field, u32 val) 74ddd6d240SAlexandre Belloni { 75ddd6d240SAlexandre Belloni if (time_before(jiffies, wdt->last_ping + WDT_DELAY)) 76ddd6d240SAlexandre Belloni udelay(123); 77ddd6d240SAlexandre Belloni writel_relaxed(val, wdt->reg_base + field); 78ddd6d240SAlexandre Belloni wdt->last_ping = jiffies; 79ddd6d240SAlexandre Belloni } 8076534860SWenyou Yang 8176534860SWenyou Yang static int sama5d4_wdt_start(struct watchdog_device *wdd) 8276534860SWenyou Yang { 8376534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 8476534860SWenyou Yang 85bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 86bb44aa09SEugen Hristev writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IER); 87bb44aa09SEugen Hristev wdt->mr &= ~AT91_SAM9X60_WDDIS; 88bb44aa09SEugen Hristev } else { 89722ce635SAlexandre Belloni wdt->mr &= ~AT91_WDT_WDDIS; 90bb44aa09SEugen Hristev } 91722ce635SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr); 9276534860SWenyou Yang 9376534860SWenyou Yang return 0; 9476534860SWenyou Yang } 9576534860SWenyou Yang 9676534860SWenyou Yang static int sama5d4_wdt_stop(struct watchdog_device *wdd) 9776534860SWenyou Yang { 9876534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 9976534860SWenyou Yang 100bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 101bb44aa09SEugen Hristev writel_relaxed(wdt->ir, wdt->reg_base + AT91_SAM9X60_IDR); 102bb44aa09SEugen Hristev wdt->mr |= AT91_SAM9X60_WDDIS; 103bb44aa09SEugen Hristev } else { 104722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDDIS; 105bb44aa09SEugen Hristev } 106722ce635SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr); 10776534860SWenyou Yang 10876534860SWenyou Yang return 0; 10976534860SWenyou Yang } 11076534860SWenyou Yang 11176534860SWenyou Yang static int sama5d4_wdt_ping(struct watchdog_device *wdd) 11276534860SWenyou Yang { 11376534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 11476534860SWenyou Yang 11576534860SWenyou Yang wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); 11676534860SWenyou Yang 11776534860SWenyou Yang return 0; 11876534860SWenyou Yang } 11976534860SWenyou Yang 12076534860SWenyou Yang static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, 12176534860SWenyou Yang unsigned int timeout) 12276534860SWenyou Yang { 12376534860SWenyou Yang struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); 12476534860SWenyou Yang u32 value = WDT_SEC2TICKS(timeout); 12576534860SWenyou Yang 126bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 127bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_WLR, 128bb44aa09SEugen Hristev AT91_SAM9X60_SET_COUNTER(value)); 129bb44aa09SEugen Hristev 130bb44aa09SEugen Hristev wdd->timeout = timeout; 131bb44aa09SEugen Hristev return 0; 132bb44aa09SEugen Hristev } 133bb44aa09SEugen Hristev 134722ce635SAlexandre Belloni wdt->mr &= ~AT91_WDT_WDV; 135722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_SET_WDV(value); 136015b5286SAlexandre Belloni 137015b5286SAlexandre Belloni /* 138015b5286SAlexandre Belloni * WDDIS has to be 0 when updating WDD/WDV. The datasheet states: When 139015b5286SAlexandre Belloni * setting the WDDIS bit, and while it is set, the fields WDV and WDD 140015b5286SAlexandre Belloni * must not be modified. 141015b5286SAlexandre Belloni * If the watchdog is enabled, then the timeout can be updated. Else, 142015b5286SAlexandre Belloni * wait that the user enables it. 143015b5286SAlexandre Belloni */ 144015b5286SAlexandre Belloni if (wdt_enabled) 145015b5286SAlexandre Belloni wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); 14676534860SWenyou Yang 14776534860SWenyou Yang wdd->timeout = timeout; 14876534860SWenyou Yang 14976534860SWenyou Yang return 0; 15076534860SWenyou Yang } 15176534860SWenyou Yang 15276534860SWenyou Yang static const struct watchdog_info sama5d4_wdt_info = { 15376534860SWenyou Yang .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, 15476534860SWenyou Yang .identity = "Atmel SAMA5D4 Watchdog", 15576534860SWenyou Yang }; 15676534860SWenyou Yang 157b893e344SBhumika Goyal static const struct watchdog_ops sama5d4_wdt_ops = { 15876534860SWenyou Yang .owner = THIS_MODULE, 15976534860SWenyou Yang .start = sama5d4_wdt_start, 16076534860SWenyou Yang .stop = sama5d4_wdt_stop, 16176534860SWenyou Yang .ping = sama5d4_wdt_ping, 16276534860SWenyou Yang .set_timeout = sama5d4_wdt_set_timeout, 16376534860SWenyou Yang }; 16476534860SWenyou Yang 16576534860SWenyou Yang static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id) 16676534860SWenyou Yang { 16776534860SWenyou Yang struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id); 168bb44aa09SEugen Hristev u32 reg; 16976534860SWenyou Yang 170bb44aa09SEugen Hristev if (wdt->sam9x60_support) 171bb44aa09SEugen Hristev reg = wdt_read(wdt, AT91_SAM9X60_ISR); 172bb44aa09SEugen Hristev else 173bb44aa09SEugen Hristev reg = wdt_read(wdt, AT91_WDT_SR); 174bb44aa09SEugen Hristev 175bb44aa09SEugen Hristev if (reg) { 17676534860SWenyou Yang pr_crit("Atmel Watchdog Software Reset\n"); 17776534860SWenyou Yang emergency_restart(); 17876534860SWenyou Yang pr_crit("Reboot didn't succeed\n"); 17976534860SWenyou Yang } 18076534860SWenyou Yang 18176534860SWenyou Yang return IRQ_HANDLED; 18276534860SWenyou Yang } 18376534860SWenyou Yang 18476534860SWenyou Yang static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) 18576534860SWenyou Yang { 18676534860SWenyou Yang const char *tmp; 18776534860SWenyou Yang 188bb44aa09SEugen Hristev if (wdt->sam9x60_support) 189bb44aa09SEugen Hristev wdt->mr = AT91_SAM9X60_WDDIS; 190bb44aa09SEugen Hristev else 191722ce635SAlexandre Belloni wdt->mr = AT91_WDT_WDDIS; 19276534860SWenyou Yang 19376534860SWenyou Yang if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && 19476534860SWenyou Yang !strcmp(tmp, "software")) 195bb44aa09SEugen Hristev wdt->need_irq = true; 19676534860SWenyou Yang 19776534860SWenyou Yang if (of_property_read_bool(np, "atmel,idle-halt")) 198722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDIDLEHLT; 19976534860SWenyou Yang 20076534860SWenyou Yang if (of_property_read_bool(np, "atmel,dbg-halt")) 201722ce635SAlexandre Belloni wdt->mr |= AT91_WDT_WDDBGHLT; 20276534860SWenyou Yang 20376534860SWenyou Yang return 0; 20476534860SWenyou Yang } 20576534860SWenyou Yang 20676534860SWenyou Yang static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) 20776534860SWenyou Yang { 208bb44aa09SEugen Hristev u32 reg, val; 209bb44aa09SEugen Hristev 210bb44aa09SEugen Hristev val = WDT_SEC2TICKS(WDT_DEFAULT_TIMEOUT); 21176534860SWenyou Yang /* 212015b5286SAlexandre Belloni * When booting and resuming, the bootloader may have changed the 213015b5286SAlexandre Belloni * watchdog configuration. 214015b5286SAlexandre Belloni * If the watchdog is already running, we can safely update it. 215015b5286SAlexandre Belloni * Else, we have to disable it properly. 21676534860SWenyou Yang */ 217bb44aa09SEugen Hristev if (!wdt_enabled) { 218015b5286SAlexandre Belloni reg = wdt_read(wdt, AT91_WDT_MR); 219bb44aa09SEugen Hristev if (wdt->sam9x60_support && (!(reg & AT91_SAM9X60_WDDIS))) 220bb44aa09SEugen Hristev wdt_write_nosleep(wdt, AT91_WDT_MR, 221bb44aa09SEugen Hristev reg | AT91_SAM9X60_WDDIS); 222bb44aa09SEugen Hristev else if (!wdt->sam9x60_support && 223bb44aa09SEugen Hristev (!(reg & AT91_WDT_WDDIS))) 224ddd6d240SAlexandre Belloni wdt_write_nosleep(wdt, AT91_WDT_MR, 225ddd6d240SAlexandre Belloni reg | AT91_WDT_WDDIS); 226015b5286SAlexandre Belloni } 227bb44aa09SEugen Hristev 228bb44aa09SEugen Hristev if (wdt->sam9x60_support) { 229bb44aa09SEugen Hristev if (wdt->need_irq) 230bb44aa09SEugen Hristev wdt->ir = AT91_SAM9X60_PERINT; 231bb44aa09SEugen Hristev else 232bb44aa09SEugen Hristev wdt->mr |= AT91_SAM9X60_PERIODRST; 233bb44aa09SEugen Hristev 234bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_IER, wdt->ir); 235bb44aa09SEugen Hristev wdt_write(wdt, AT91_SAM9X60_WLR, AT91_SAM9X60_SET_COUNTER(val)); 236bb44aa09SEugen Hristev } else { 237bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_SET_WDD(WDT_SEC2TICKS(MAX_WDT_TIMEOUT)); 238bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_SET_WDV(val); 239bb44aa09SEugen Hristev 240bb44aa09SEugen Hristev if (wdt->need_irq) 241bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_WDFIEN; 242bb44aa09SEugen Hristev else 243bb44aa09SEugen Hristev wdt->mr |= AT91_WDT_WDRSTEN; 244bb44aa09SEugen Hristev } 245bb44aa09SEugen Hristev 246bb44aa09SEugen Hristev wdt_write_nosleep(wdt, AT91_WDT_MR, wdt->mr); 247bb44aa09SEugen Hristev 24876534860SWenyou Yang return 0; 24976534860SWenyou Yang } 25076534860SWenyou Yang 25176534860SWenyou Yang static int sama5d4_wdt_probe(struct platform_device *pdev) 25276534860SWenyou Yang { 253dcc3ce0bSGuenter Roeck struct device *dev = &pdev->dev; 25476534860SWenyou Yang struct watchdog_device *wdd; 25576534860SWenyou Yang struct sama5d4_wdt *wdt; 25676534860SWenyou Yang void __iomem *regs; 25776534860SWenyou Yang u32 irq = 0; 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; 271*5ae233fbSEugen Hristev 272*5ae233fbSEugen Hristev if (of_device_is_compatible(dev->of_node, "microchip,sam9x60-wdt") || 273*5ae233fbSEugen Hristev of_device_is_compatible(dev->of_node, "microchip,sama7g5-wdt")) 274*5ae233fbSEugen 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 30876534860SWenyou Yang ret = sama5d4_wdt_init(wdt); 30976534860SWenyou Yang if (ret) 31076534860SWenyou Yang return ret; 31176534860SWenyou Yang 31276534860SWenyou Yang watchdog_set_nowayout(wdd, nowayout); 31376534860SWenyou Yang 314dcc3ce0bSGuenter Roeck watchdog_stop_on_unregister(wdd); 315dcc3ce0bSGuenter Roeck ret = devm_watchdog_register_device(dev, wdd); 31624b8eb74SWolfram Sang if (ret) 31776534860SWenyou Yang return ret; 31876534860SWenyou Yang 31976534860SWenyou Yang platform_set_drvdata(pdev, wdt); 32076534860SWenyou Yang 321dcc3ce0bSGuenter Roeck dev_info(dev, "initialized (timeout = %d sec, nowayout = %d)\n", 322976932e4SMarcus Folkesson wdd->timeout, nowayout); 32376534860SWenyou Yang 32476534860SWenyou Yang return 0; 32576534860SWenyou Yang } 32676534860SWenyou Yang 32776534860SWenyou Yang static const struct of_device_id sama5d4_wdt_of_match[] = { 328bb44aa09SEugen Hristev { 329bb44aa09SEugen Hristev .compatible = "atmel,sama5d4-wdt", 330bb44aa09SEugen Hristev }, 331bb44aa09SEugen Hristev { 332bb44aa09SEugen Hristev .compatible = "microchip,sam9x60-wdt", 333bb44aa09SEugen Hristev }, 334*5ae233fbSEugen Hristev { 335*5ae233fbSEugen Hristev .compatible = "microchip,sama7g5-wdt", 336*5ae233fbSEugen Hristev }, 337*5ae233fbSEugen Hristev 33876534860SWenyou Yang { } 33976534860SWenyou Yang }; 34076534860SWenyou Yang MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); 34176534860SWenyou Yang 342f2013532SAlexandre Belloni #ifdef CONFIG_PM_SLEEP 3438d209eb0SKen Sloat static int sama5d4_wdt_suspend_late(struct device *dev) 3448d209eb0SKen Sloat { 3458d209eb0SKen Sloat struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 3468d209eb0SKen Sloat 3478d209eb0SKen Sloat if (watchdog_active(&wdt->wdd)) 3488d209eb0SKen Sloat sama5d4_wdt_stop(&wdt->wdd); 3498d209eb0SKen Sloat 3508d209eb0SKen Sloat return 0; 3518d209eb0SKen Sloat } 3528d209eb0SKen Sloat 3538d209eb0SKen Sloat static int sama5d4_wdt_resume_early(struct device *dev) 354f2013532SAlexandre Belloni { 355f2013532SAlexandre Belloni struct sama5d4_wdt *wdt = dev_get_drvdata(dev); 356f2013532SAlexandre Belloni 3575dca80f6SAlexandre Belloni /* 3585dca80f6SAlexandre Belloni * FIXME: writing MR also pings the watchdog which may not be desired. 3595dca80f6SAlexandre Belloni * This should only be done when the registers are lost on suspend but 3605dca80f6SAlexandre Belloni * there is no way to get this information right now. 3615dca80f6SAlexandre Belloni */ 362015b5286SAlexandre Belloni sama5d4_wdt_init(wdt); 363f2013532SAlexandre Belloni 3648d209eb0SKen Sloat if (watchdog_active(&wdt->wdd)) 3658d209eb0SKen Sloat sama5d4_wdt_start(&wdt->wdd); 3668d209eb0SKen Sloat 367f2013532SAlexandre Belloni return 0; 368f2013532SAlexandre Belloni } 369f2013532SAlexandre Belloni #endif 370f2013532SAlexandre Belloni 3718d209eb0SKen Sloat static const struct dev_pm_ops sama5d4_wdt_pm_ops = { 3728d209eb0SKen Sloat SET_LATE_SYSTEM_SLEEP_PM_OPS(sama5d4_wdt_suspend_late, 3738d209eb0SKen Sloat sama5d4_wdt_resume_early) 3748d209eb0SKen Sloat }; 375f2013532SAlexandre Belloni 37676534860SWenyou Yang static struct platform_driver sama5d4_wdt_driver = { 37776534860SWenyou Yang .probe = sama5d4_wdt_probe, 37876534860SWenyou Yang .driver = { 37976534860SWenyou Yang .name = "sama5d4_wdt", 380f2013532SAlexandre Belloni .pm = &sama5d4_wdt_pm_ops, 38176534860SWenyou Yang .of_match_table = sama5d4_wdt_of_match, 38276534860SWenyou Yang } 38376534860SWenyou Yang }; 38476534860SWenyou Yang module_platform_driver(sama5d4_wdt_driver); 38576534860SWenyou Yang 38676534860SWenyou Yang MODULE_AUTHOR("Atmel Corporation"); 38776534860SWenyou Yang MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver"); 38876534860SWenyou Yang MODULE_LICENSE("GPL v2"); 389