1e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 29419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt 39419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * 4d14fd9645501444f06034339118de56686e25dfbMichal Simek * (C) Copyright 2013 - 2014 Xilinx, Inc. 59419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) 69419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * 79419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * This program is free software; you can redistribute it and/or 89419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * modify it under the terms of the GNU General Public License 99419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * as published by the Free Software Foundation; either version 109419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek * 2 of the License, or (at your option) any later version. 119419c07ccebf6080159b4440dab9b3e484c96d7aMichal Simek */ 12e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 13f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek#include <linux/err.h> 14e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/module.h> 15e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/types.h> 16e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/kernel.h> 17e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/ioport.h> 18e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/watchdog.h> 19e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/io.h> 20e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of.h> 21e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_device.h> 22e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_address.h> 23e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 24e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Register offsets for the Wdt device */ 25e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */ 26e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */ 27e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */ 28e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 29e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register Masks */ 30e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */ 31e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */ 32e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */ 33e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 34e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register 0/1 bits */ 35e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */ 36e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 37e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* SelfTest constants */ 38e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000 39e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TIMER_FAILED 0xFFFFFFFF 40e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 41e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define WATCHDOG_NAME "Xilinx Watchdog" 42e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 43e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastruct xwdt_device { 44e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera void __iomem *base; 45e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 wdt_interval; 469066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spinlock_t spinlock; 479066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct watchdog_device xilinx_wdt_wdd; 48e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 49e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 50d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_start(struct watchdog_device *wdd) 51e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 525cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek u32 control_status_reg; 539066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 545cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek 559066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock(&xdev->spinlock); 56e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 57e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera /* Clean previous status and enable the watchdog timer */ 589066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 59e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 60e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 61e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), 629066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base + XWT_TWCSR0_OFFSET); 63e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 649066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek iowrite32(XWT_CSRX_EWDT2_MASK, xdev->base + XWT_TWCSR1_OFFSET); 65e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 669066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_unlock(&xdev->spinlock); 67d14fd9645501444f06034339118de56686e25dfbMichal Simek 68d14fd9645501444f06034339118de56686e25dfbMichal Simek return 0; 69e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 70e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 71d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_stop(struct watchdog_device *wdd) 72e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 735cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek u32 control_status_reg; 749066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 755cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek 769066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock(&xdev->spinlock); 77e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 789066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 79e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 80e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), 819066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base + XWT_TWCSR0_OFFSET); 82e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 839066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek iowrite32(0, xdev->base + XWT_TWCSR1_OFFSET); 84e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 859066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_unlock(&xdev->spinlock); 8627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches pr_info("Stopped!\n"); 87d14fd9645501444f06034339118de56686e25dfbMichal Simek 88d14fd9645501444f06034339118de56686e25dfbMichal Simek return 0; 89e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 90e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 91d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic int xilinx_wdt_keepalive(struct watchdog_device *wdd) 92e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 935cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek u32 control_status_reg; 949066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev = watchdog_get_drvdata(wdd); 955cf4e69d39f6a31a5305d01690c1607356b1483bMichal Simek 969066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock(&xdev->spinlock); 97e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 989066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek control_status_reg = ioread32(xdev->base + XWT_TWCSR0_OFFSET); 99e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 1009066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek iowrite32(control_status_reg, xdev->base + XWT_TWCSR0_OFFSET); 101e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1029066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_unlock(&xdev->spinlock); 103e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 104d14fd9645501444f06034339118de56686e25dfbMichal Simek return 0; 105d14fd9645501444f06034339118de56686e25dfbMichal Simek} 106e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 107d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic const struct watchdog_info xilinx_wdt_ident = { 108d14fd9645501444f06034339118de56686e25dfbMichal Simek .options = WDIOF_MAGICCLOSE | 109d14fd9645501444f06034339118de56686e25dfbMichal Simek WDIOF_KEEPALIVEPING, 110d14fd9645501444f06034339118de56686e25dfbMichal Simek .firmware_version = 1, 111d14fd9645501444f06034339118de56686e25dfbMichal Simek .identity = WATCHDOG_NAME, 112d14fd9645501444f06034339118de56686e25dfbMichal Simek}; 113e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 114d14fd9645501444f06034339118de56686e25dfbMichal Simekstatic const struct watchdog_ops xilinx_wdt_ops = { 115d14fd9645501444f06034339118de56686e25dfbMichal Simek .owner = THIS_MODULE, 116d14fd9645501444f06034339118de56686e25dfbMichal Simek .start = xilinx_wdt_start, 117d14fd9645501444f06034339118de56686e25dfbMichal Simek .stop = xilinx_wdt_stop, 118d14fd9645501444f06034339118de56686e25dfbMichal Simek .ping = xilinx_wdt_keepalive, 119d14fd9645501444f06034339118de56686e25dfbMichal Simek}; 120e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1219066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simekstatic u32 xwdt_selftest(struct xwdt_device *xdev) 122e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 123e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int i; 124e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 timer_value1; 125e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 timer_value2; 126e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1279066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock(&xdev->spinlock); 128e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1299066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek timer_value1 = ioread32(xdev->base + XWT_TBR_OFFSET); 1309066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 131e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 132e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera for (i = 0; 133e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && 134e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera (timer_value2 == timer_value1)); i++) { 1359066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek timer_value2 = ioread32(xdev->base + XWT_TBR_OFFSET); 136e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 137e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1389066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_unlock(&xdev->spinlock); 139e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 140e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (timer_value2 != timer_value1) 141e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return ~XWT_TIMER_FAILED; 142e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera else 143e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return XWT_TIMER_FAILED; 144e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 145e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1462d991a164a61858012651e13c59521975504e260Bill Pembertonstatic int xwdt_probe(struct platform_device *pdev) 147e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 148e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int rc; 1498d6a140b5f0def8c34d803474780b7b11fe0fab4Michal Simek u32 pfreq = 0, enable_once = 0; 150f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek struct resource *res; 1519066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev; 1529066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct watchdog_device *xilinx_wdt_wdd; 1539066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 1549066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); 1559066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek if (!xdev) 1569066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek return -ENOMEM; 1579066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 1589066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd; 1599066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->info = &xilinx_wdt_ident; 1609066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->ops = &xilinx_wdt_ops; 1619066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->parent = &pdev->dev; 162e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 163f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1649066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base = devm_ioremap_resource(&pdev->dev, res); 1659066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek if (IS_ERR(xdev->base)) 1669066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek return PTR_ERR(xdev->base); 167f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek 1682e79a368473d55db3237120dea0f561660dac5bdMichal Simek rc = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &pfreq); 1698d6a140b5f0def8c34d803474780b7b11fe0fab4Michal Simek if (rc) 1704c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1714c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "The watchdog clock frequency cannot be obtained\n"); 172e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1732e79a368473d55db3237120dea0f561660dac5bdMichal Simek rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-interval", 1742e79a368473d55db3237120dea0f561660dac5bdMichal Simek &xdev->wdt_interval); 1758d6a140b5f0def8c34d803474780b7b11fe0fab4Michal Simek if (rc) 1764c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1774c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "Parameter \"xlnx,wdt-interval\" not found\n"); 178e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1792e79a368473d55db3237120dea0f561660dac5bdMichal Simek rc = of_property_read_u32(pdev->dev.of_node, "xlnx,wdt-enable-once", 1802e79a368473d55db3237120dea0f561660dac5bdMichal Simek &enable_once); 1812e79a368473d55db3237120dea0f561660dac5bdMichal Simek if (rc) 1824c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1834c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "Parameter \"xlnx,wdt-enable-once\" not found\n"); 1842e79a368473d55db3237120dea0f561660dac5bdMichal Simek 1852e79a368473d55db3237120dea0f561660dac5bdMichal Simek watchdog_set_nowayout(xilinx_wdt_wdd, enable_once); 186e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 18775b3c5a827de11620f9bf7cbd6c3e4208bd3ddf5Michal Simek /* 18875b3c5a827de11620f9bf7cbd6c3e4208bd3ddf5Michal Simek * Twice of the 2^wdt_interval / freq because the first wdt overflow is 18975b3c5a827de11620f9bf7cbd6c3e4208bd3ddf5Michal Simek * ignored (interrupt), reset is only generated at second wdt overflow 19075b3c5a827de11620f9bf7cbd6c3e4208bd3ddf5Michal Simek */ 1918d6a140b5f0def8c34d803474780b7b11fe0fab4Michal Simek if (pfreq && xdev->wdt_interval) 1929066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) / 1932e79a368473d55db3237120dea0f561660dac5bdMichal Simek pfreq); 1949066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 1959066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock_init(&xdev->spinlock); 1969066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek watchdog_set_drvdata(xilinx_wdt_wdd, xdev); 197e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 1989066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek rc = xwdt_selftest(xdev); 199e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc == XWT_TIMER_FAILED) { 2004c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_err(&pdev->dev, "SelfTest routine error\n"); 201f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek return rc; 202e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 203e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 2049066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek rc = watchdog_register_device(xilinx_wdt_wdd); 205e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc) { 2064c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); 207f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek return rc; 208e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 209e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 210d14fd9645501444f06034339118de56686e25dfbMichal Simek dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", 2119066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base, xilinx_wdt_wdd->timeout); 2129066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 2139066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek platform_set_drvdata(pdev, xdev); 214e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 215e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 216e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 217e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 2189066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simekstatic int xwdt_remove(struct platform_device *pdev) 219e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 2209066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev = platform_get_drvdata(pdev); 2219066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 2229066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek watchdog_unregister_device(&xdev->xilinx_wdt_wdd); 223e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 224e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 225e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 226e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 227e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Match table for of_platform binding */ 2289ebf1855dbe0a170e45a2000d6f8e16d88b5fd7cJingoo Hanstatic const struct of_device_id xwdt_of_match[] = { 2298fce9b367d672332d2d101175b10737ee5c18b59Michal Simek { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 230e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 231e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera {}, 232e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 233e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DEVICE_TABLE(of, xwdt_of_match); 234e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 235e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct platform_driver xwdt_driver = { 236e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .probe = xwdt_probe, 23782268714bdf06bc06135efb707a9de590ab2d294Bill Pemberton .remove = xwdt_remove, 238e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .driver = { 239e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .name = WATCHDOG_NAME, 240e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .of_match_table = xwdt_of_match, 241e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera }, 242e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 243e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 244b8ec61189f3b4cd9d1b2856342f5d7676151d01cAxel Linmodule_platform_driver(xwdt_driver); 245e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 246e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); 247e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DESCRIPTION("Xilinx Watchdog driver"); 2489419c07ccebf6080159b4440dab9b3e484c96d7aMichal SimekMODULE_LICENSE("GPL v2"); 249