of_xilinx_wdt.c revision b8ec61189f3b4cd9d1b2856342f5d7676151d01c
1e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 2e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* of_xilinx_wdt.c 1.01 A Watchdog Device Driver for Xilinx xps_timebase_wdt 3e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 4e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) 5e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 6e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* ----------------------- 7e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 8e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* This program is free software; you can redistribute it and/or 9e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* modify it under the terms of the GNU General Public License 10e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* as published by the Free Software Foundation; either version 11e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 2 of the License, or (at your option) any later version. 12e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 13e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* ----------------------- 14e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* 30-May-2011 Alejandro Cabrera <aldaya@gmail.com> 15e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* - If "xlnx,wdt-enable-once" wasn't found on device tree the 16e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* module will use CONFIG_WATCHDOG_NOWAYOUT 17e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* - If the device tree parameters ("clock-frequency" and 18e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* "xlnx,wdt-interval") wasn't found the driver won't 19e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera* know the wdt reset interval 20e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera*/ 21e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 22e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/module.h> 23e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/types.h> 24e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/kernel.h> 25e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/fs.h> 26e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/miscdevice.h> 27e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/init.h> 28e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/ioport.h> 29e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/watchdog.h> 30e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/io.h> 31e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/uaccess.h> 32e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of.h> 33e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_device.h> 34e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#include <linux/of_address.h> 35e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 36e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Register offsets for the Wdt device */ 37e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */ 38e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */ 39e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */ 40e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 41e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register Masks */ 42e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */ 43e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */ 44e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */ 45e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 46e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Control/Status Register 0/1 bits */ 47e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */ 48e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 49e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* SelfTest constants */ 50e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000 51e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define XWT_TIMER_FAILED 0xFFFFFFFF 52e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 53e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define WATCHDOG_NAME "Xilinx Watchdog" 54e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera#define PFX WATCHDOG_NAME ": " 55e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 56e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastruct xwdt_device { 57e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera struct resource res; 58e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera void __iomem *base; 59e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 nowayout; 60e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 wdt_interval; 61e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 boot_status; 62e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 63e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 64e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct xwdt_device xdev; 65e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 66e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u32 timeout; 67e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u32 control_status_reg; 68e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u8 expect_close; 69e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u8 no_timeout; 70e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic unsigned long driver_open; 71e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 72e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic DEFINE_SPINLOCK(spinlock); 73e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 74e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic void xwdt_start(void) 75e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 76e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_lock(&spinlock); 77e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 78e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera /* Clean previous status and enable the watchdog timer */ 79e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); 80e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 81e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 82e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK), 83e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.base + XWT_TWCSR0_OFFSET); 84e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 85e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET); 86e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 87e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_unlock(&spinlock); 88e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 89e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 90e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic void xwdt_stop(void) 91e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 92e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_lock(&spinlock); 93e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 94e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); 95e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 96e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK), 97e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.base + XWT_TWCSR0_OFFSET); 98e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 99e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET); 100e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 101e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_unlock(&spinlock); 102e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_INFO PFX "Stopped!\n"); 103e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 104e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 105e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic void xwdt_keepalive(void) 106e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 107e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_lock(&spinlock); 108e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 109e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); 110e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK); 111e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET); 112e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 113e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_unlock(&spinlock); 114e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 115e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 116e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic void xwdt_get_status(int *status) 117e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 118e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int new_status; 119e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 120e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_lock(&spinlock); 121e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 122e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET); 123e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera new_status = ((control_status_reg & 124e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0); 125e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_unlock(&spinlock); 126e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 127e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera *status = 0; 128e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (new_status & 1) 129e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera *status |= WDIOF_CARDRESET; 130e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 131e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 132e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic u32 xwdt_selftest(void) 133e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 134e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int i; 135e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 timer_value1; 136e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 timer_value2; 137e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 138e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_lock(&spinlock); 139e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 140e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET); 141e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); 142e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 143e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera for (i = 0; 144e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) && 145e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera (timer_value2 == timer_value1)); i++) { 146e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET); 147e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 148e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 149e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera spin_unlock(&spinlock); 150e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 151e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (timer_value2 != timer_value1) 152e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return ~XWT_TIMER_FAILED; 153e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera else 154e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return XWT_TIMER_FAILED; 155e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 156e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 157e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic int xwdt_open(struct inode *inode, struct file *file) 158e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 159e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera /* Only one process can handle the wdt at a time */ 160e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (test_and_set_bit(0, &driver_open)) 161e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return -EBUSY; 162e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 163e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera /* Make sure that the module are always loaded...*/ 164e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (xdev.nowayout) 165e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera __module_get(THIS_MODULE); 166e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 167e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_start(); 168e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_INFO PFX "Started...\n"); 169e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 170e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return nonseekable_open(inode, file); 171e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 172e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 173e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic int xwdt_release(struct inode *inode, struct file *file) 174e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 175e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (expect_close == 42) { 176e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_stop(); 177e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } else { 178e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_CRIT PFX 179e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "Unexpected close, not stopping watchdog!\n"); 180e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_keepalive(); 181e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 182e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 183e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera clear_bit(0, &driver_open); 184e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera expect_close = 0; 185e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 186e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 187e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 188e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 189e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * xwdt_write: 190e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @file: file handle to the watchdog 191e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @buf: buffer to write (unused as data does not matter here 192e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @count: count of bytes 193e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @ppos: pointer to the position to write. No seeks allowed 194e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * 195e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * A write to a watchdog device is defined as a keepalive signal. Any 196e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * write of data will do, as we don't define content meaning. 197e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera */ 198e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic ssize_t xwdt_write(struct file *file, const char __user *buf, 199e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera size_t len, loff_t *ppos) 200e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 201e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (len) { 202e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (!xdev.nowayout) { 203e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera size_t i; 204e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 205e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera /* In case it was set long ago */ 206e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera expect_close = 0; 207e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 208e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera for (i = 0; i != len; i++) { 209e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera char c; 210e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 211e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (get_user(c, buf + i)) 212e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return -EFAULT; 213e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (c == 'V') 214e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera expect_close = 42; 215e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 216e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 217e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_keepalive(); 218e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 219e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return len; 220e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 221e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 222e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic const struct watchdog_info ident = { 223e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .options = WDIOF_MAGICCLOSE | 224e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera WDIOF_KEEPALIVEPING, 225e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .firmware_version = 1, 226e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .identity = WATCHDOG_NAME, 227e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 228e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 229e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 230e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * xwdt_ioctl: 231e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @file: file handle to the device 232e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @cmd: watchdog command 233e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * @arg: argument pointer 234e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * 235e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * The watchdog API defines a common set of functions for all watchdogs 236e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * according to their available features. 237e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera */ 238e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 239e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 240e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int status; 241e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 242e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera union { 243e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera struct watchdog_info __user *ident; 244e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int __user *i; 245e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } uarg; 246e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 247e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera uarg.i = (int __user *)arg; 248e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 249e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera switch (cmd) { 250e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera case WDIOC_GETSUPPORT: 251e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return copy_to_user(uarg.ident, &ident, 252e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera sizeof(ident)) ? -EFAULT : 0; 253e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 254e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera case WDIOC_GETBOOTSTATUS: 255e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return put_user(xdev.boot_status, uarg.i); 256e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 257e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera case WDIOC_GETSTATUS: 258e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_get_status(&status); 259e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return put_user(status, uarg.i); 260e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 261e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera case WDIOC_KEEPALIVE: 262e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_keepalive(); 263e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 264e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 265e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera case WDIOC_GETTIMEOUT: 266e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (no_timeout) 267e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return -ENOTTY; 268e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera else 269e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return put_user(timeout, uarg.i); 270e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 271e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera default: 272e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return -ENOTTY; 273e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 274e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 275e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 276e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic const struct file_operations xwdt_fops = { 277e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .owner = THIS_MODULE, 278e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .llseek = no_llseek, 279e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .write = xwdt_write, 280e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .open = xwdt_open, 281e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .release = xwdt_release, 282e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .unlocked_ioctl = xwdt_ioctl, 283e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 284e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 285e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct miscdevice xwdt_miscdev = { 286e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .minor = WATCHDOG_MINOR, 287e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .name = "watchdog", 288e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .fops = &xwdt_fops, 289e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 290e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 291e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic int __devinit xwdt_probe(struct platform_device *pdev) 292e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 293e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera int rc; 294e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 *tmptr; 295e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera u32 *pfreq; 296e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 297e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera no_timeout = 0; 298e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 299e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent, 300e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "clock-frequency", NULL); 301e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 302e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (pfreq == NULL) { 303e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_WARNING PFX 304e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "The watchdog clock frequency cannot be obtained!\n"); 305e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera no_timeout = 1; 306e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 307e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 308e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res); 309e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc) { 310e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_WARNING PFX "invalid address!\n"); 311e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return rc; 312e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 313e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 314e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera tmptr = (u32 *)of_get_property(pdev->dev.of_node, 315e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "xlnx,wdt-interval", NULL); 316e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (tmptr == NULL) { 317e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\"" 318e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera " not found in device tree!\n"); 319e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera no_timeout = 1; 320e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } else { 321e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.wdt_interval = *tmptr; 322e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 323e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 324e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera tmptr = (u32 *)of_get_property(pdev->dev.of_node, 325e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "xlnx,wdt-enable-once", NULL); 326e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (tmptr == NULL) { 327e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\"" 328e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera " not found in device tree!\n"); 329e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.nowayout = WATCHDOG_NOWAYOUT; 330e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 331e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 332e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* 333e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * Twice of the 2^wdt_interval / freq because the first wdt overflow is 334e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera * ignored (interrupt), reset is only generated at second wdt overflow 335e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera */ 336e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (!no_timeout) 337e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq); 338e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 339e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (!request_mem_region(xdev.res.start, 340e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) { 341e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera rc = -ENXIO; 342e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_ERR PFX "memory request failure!\n"); 343e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera goto err_out; 344e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 345e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 346e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1); 347e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (xdev.base == NULL) { 348e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera rc = -ENOMEM; 349e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_ERR PFX "ioremap failure!\n"); 350e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera goto release_mem; 351e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 352e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 353e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera rc = xwdt_selftest(); 354e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc == XWT_TIMER_FAILED) { 355e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_ERR PFX "SelfTest routine error!\n"); 356e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera goto unmap_io; 357e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 358e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 359e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_get_status(&xdev.boot_status); 360e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 361e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera rc = misc_register(&xwdt_miscdev); 362e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (rc) { 363e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_ERR PFX 364e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "cannot register miscdev on minor=%d (err=%d)\n", 365e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xwdt_miscdev.minor, rc); 366e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera goto unmap_io; 367e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera } 368e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 369e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera if (no_timeout) 370e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_INFO PFX 371e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "driver loaded (timeout=? sec, nowayout=%d)\n", 372e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera xdev.nowayout); 373e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera else 374e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera printk(KERN_INFO PFX 375e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera "driver loaded (timeout=%d sec, nowayout=%d)\n", 376e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera timeout, xdev.nowayout); 377e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 378e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera expect_close = 0; 379e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera clear_bit(0, &driver_open); 380e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 381e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 382e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 383e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabreraunmap_io: 384e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iounmap(xdev.base); 385e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerarelease_mem: 386e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera release_mem_region(xdev.res.start, resource_size(&xdev.res)); 387e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabreraerr_out: 388e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return rc; 389e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 390e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 391e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic int __devexit xwdt_remove(struct platform_device *dev) 392e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera{ 393e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera misc_deregister(&xwdt_miscdev); 394e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera iounmap(xdev.base); 395e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera release_mem_region(xdev.res.start, resource_size(&xdev.res)); 396e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 397e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera return 0; 398e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera} 399e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 400e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera/* Match table for of_platform binding */ 401e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct of_device_id __devinitdata xwdt_of_match[] = { 402e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 403e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera {}, 404e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 405e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DEVICE_TABLE(of, xwdt_of_match); 406e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 407e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrerastatic struct platform_driver xwdt_driver = { 408e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .probe = xwdt_probe, 409e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .remove = __devexit_p(xwdt_remove), 410e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .driver = { 411e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .owner = THIS_MODULE, 412e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .name = WATCHDOG_NAME, 413e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera .of_match_table = xwdt_of_match, 414e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera }, 415e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera}; 416e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 417b8ec61189f3b4cd9d1b2856342f5d7676151d01cAxel Linmodule_platform_driver(xwdt_driver); 418e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro Cabrera 419e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); 420e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_DESCRIPTION("Xilinx Watchdog driver"); 421e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_LICENSE("GPL"); 422e9659e69b0094ea2cc92716e2b1cd6a7db9caf2eAlejandro CabreraMODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 423