of_xilinx_wdt.c revision 4c7fbbc4a57a35ed109f58f52eff1a04660789e9
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; 149e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 *tmptr; 150e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 *pfreq; 151f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek struct resource *res; 1529066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev; 153ffb8eee4f140bbfc333381168d6fe1a7e7dc7af7Michal Simek bool no_timeout = false; 1549066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct watchdog_device *xilinx_wdt_wdd; 1559066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 1569066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL); 1579066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek if (!xdev) 1589066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek return -ENOMEM; 1599066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 1609066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd = &xdev->xilinx_wdt_wdd; 1619066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->info = &xilinx_wdt_ident; 1629066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->ops = &xilinx_wdt_ops; 1639066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->parent = &pdev->dev; 164e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 165f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1669066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base = devm_ioremap_resource(&pdev->dev, res); 1679066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek if (IS_ERR(xdev->base)) 1689066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek return PTR_ERR(xdev->base); 169f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek 17090fe6c608f8d46e5bb3f31c2d5e1c90475253f79Michal Simek pfreq = (u32 *)of_get_property(pdev->dev.of_node, 171e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "clock-frequency", NULL); 172e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 173e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (pfreq == NULL) { 1744c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1754c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "The watchdog clock frequency cannot be obtained\n"); 176ffb8eee4f140bbfc333381168d6fe1a7e7dc7af7Michal Simek no_timeout = true; 177e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 178e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 179e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera tmptr = (u32 *)of_get_property(pdev->dev.of_node, 180e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "xlnx,wdt-interval", NULL); 181e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (tmptr == NULL) { 1824c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1834c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "Parameter \"xlnx,wdt-interval\" not found\n"); 184ffb8eee4f140bbfc333381168d6fe1a7e7dc7af7Michal Simek no_timeout = true; 185e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } else { 1869066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->wdt_interval = *tmptr; 187e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 188e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 189e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera tmptr = (u32 *)of_get_property(pdev->dev.of_node, 190e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "xlnx,wdt-enable-once", NULL); 191e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (tmptr == NULL) { 1924c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_warn(&pdev->dev, 1934c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek "Parameter \"xlnx,wdt-enable-once\" not found\n"); 1949066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek watchdog_set_nowayout(xilinx_wdt_wdd, true); 195e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 196e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 197e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 198e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * Twice of the 2^wdt_interval / freq because the first wdt overflow is 199e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * ignored (interrupt), reset is only generated at second wdt overflow 200e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera */ 201e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (!no_timeout) 2029066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xilinx_wdt_wdd->timeout = 2 * ((1 << xdev->wdt_interval) / 2039066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek *pfreq); 2049066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 2059066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek spin_lock_init(&xdev->spinlock); 2069066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek watchdog_set_drvdata(xilinx_wdt_wdd, xdev); 207e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 2089066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek rc = xwdt_selftest(xdev); 209e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc == XWT_TIMER_FAILED) { 2104c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_err(&pdev->dev, "SelfTest routine error\n"); 211f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek return rc; 212e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 213e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 2149066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek rc = watchdog_register_device(xilinx_wdt_wdd); 215e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc) { 2164c7fbbc4a57a35ed109f58f52eff1a04660789e9Michal Simek dev_err(&pdev->dev, "Cannot register watchdog (err=%d)\n", rc); 217f06cdfd184d845e1f01df7f636c0e3b5c5cc8d18Michal Simek return rc; 218e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 219e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 220d14fd9645501444f06034339118de56686e25dfbMichal Simek dev_info(&pdev->dev, "Xilinx Watchdog Timer at %p with timeout %ds\n", 2219066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek xdev->base, xilinx_wdt_wdd->timeout); 2229066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 2239066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek platform_set_drvdata(pdev, xdev); 224e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 225e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 226e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 227e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 2289066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simekstatic int xwdt_remove(struct platform_device *pdev) 229e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 2309066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek struct xwdt_device *xdev = platform_get_drvdata(pdev); 2319066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek 2329066317178ca87b9d958f801c8fcf784ec31c6c3Michal Simek watchdog_unregister_device(&xdev->xilinx_wdt_wdd); 233e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 234e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 235e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 236e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 237e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Match table for of_platform binding */ 2381d1313686422db3bffb2e7bd8eb2ccd9027d3783Bill Pembertonstatic struct of_device_id xwdt_of_match[] = { 2398fce9b367d672332d2d101175b10737ee5c18b59Michal Simek { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 240e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 241e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera {}, 242e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 243e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DEVICE_TABLE(of, xwdt_of_match); 244e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 245e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct platform_driver xwdt_driver = { 246e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .probe = xwdt_probe, 24782268714bdf06bc06135efb707a9de590ab2d294Bill Pemberton .remove = xwdt_remove, 248e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .driver = { 249e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .owner = THIS_MODULE, 250e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .name = WATCHDOG_NAME, 251e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .of_match_table = xwdt_of_match, 252e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera }, 253e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 254e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 255b8ec61189f3b4cd9d1b2856342f5d7676151d01cAxel Linmodule_platform_driver(xwdt_driver); 256e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 257e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); 258e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DESCRIPTION("Xilinx Watchdog driver"); 2599419c07ccebf6080159b4440dab9b3e484c96d7aMichal SimekMODULE_LICENSE("GPL v2"); 260