addi_watchdog.c revision 588ba6dc5fb4bdca47a3da38c2718fbb82d3eee1
1/* 2 * COMEDI driver for the watchdog subdevice found on some addi-data boards 3 * Copyright (c) 2013 H Hartley Sweeten <hsweeten@visionengravers.com> 4 * 5 * Based on implementations in various addi-data COMEDI drivers. 6 * 7 * COMEDI - Linux Control and Measurement Device Interface 8 * Copyright (C) 1998 David A. Schleef <ds@schleef.org> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21#include "../comedidev.h" 22#include "addi_watchdog.h" 23 24/* 25 * Register offsets/defines for the addi-data watchdog 26 */ 27#define ADDI_WDOG_REG 0x00 28#define ADDI_WDOG_RELOAD_REG 0x04 29#define ADDI_WDOG_TIMEBASE 0x08 30#define ADDI_WDOG_CTRL_REG 0x0c 31#define ADDI_WDOG_CTRL_ENABLE (1 << 0) 32#define ADDI_WDOG_CTRL_SW_TRIG (1 << 9) 33#define ADDI_WDOG_STATUS_REG 0x10 34#define ADDI_WDOG_STATUS_ENABLED (1 << 0) 35#define ADDI_WDOG_STATUS_SW_TRIG (1 << 1) 36 37struct addi_watchdog_private { 38 unsigned long iobase; 39 unsigned int wdog_ctrl; 40}; 41 42/* 43 * The watchdog subdevice is configured with two INSN_CONFIG instructions: 44 * 45 * Enable the watchdog and set the reload timeout: 46 * data[0] = INSN_CONFIG_ARM 47 * data[1] = timeout reload value 48 * 49 * Disable the watchdog: 50 * data[0] = INSN_CONFIG_DISARM 51 */ 52static int addi_watchdog_insn_config(struct comedi_device *dev, 53 struct comedi_subdevice *s, 54 struct comedi_insn *insn, 55 unsigned int *data) 56{ 57 struct addi_watchdog_private *spriv = s->private; 58 unsigned int reload; 59 60 switch (data[0]) { 61 case INSN_CONFIG_ARM: 62 spriv->wdog_ctrl = ADDI_WDOG_CTRL_ENABLE; 63 reload = data[1] & s->maxdata; 64 outl(reload, spriv->iobase + ADDI_WDOG_RELOAD_REG); 65 66 /* Time base is 20ms, let the user know the timeout */ 67 dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", 68 20 * reload + 20); 69 break; 70 case INSN_CONFIG_DISARM: 71 spriv->wdog_ctrl = 0; 72 break; 73 default: 74 return -EINVAL; 75 } 76 77 outl(spriv->wdog_ctrl, spriv->iobase + ADDI_WDOG_CTRL_REG); 78 79 return insn->n; 80} 81 82static int addi_watchdog_insn_read(struct comedi_device *dev, 83 struct comedi_subdevice *s, 84 struct comedi_insn *insn, 85 unsigned int *data) 86{ 87 struct addi_watchdog_private *spriv = s->private; 88 int i; 89 90 for (i = 0; i < insn->n; i++) 91 data[i] = inl(spriv->iobase + ADDI_WDOG_STATUS_REG); 92 93 return insn->n; 94} 95 96static int addi_watchdog_insn_write(struct comedi_device *dev, 97 struct comedi_subdevice *s, 98 struct comedi_insn *insn, 99 unsigned int *data) 100{ 101 struct addi_watchdog_private *spriv = s->private; 102 int i; 103 104 if (spriv->wdog_ctrl == 0) { 105 dev_warn(dev->class_dev, "watchdog is disabled\n"); 106 return -EINVAL; 107 } 108 109 /* "ping" the watchdog */ 110 for (i = 0; i < insn->n; i++) { 111 outl(spriv->wdog_ctrl | ADDI_WDOG_CTRL_SW_TRIG, 112 spriv->iobase + ADDI_WDOG_CTRL_REG); 113 } 114 115 return insn->n; 116} 117 118void addi_watchdog_reset(unsigned long iobase) 119{ 120 outl(0x0, iobase + ADDI_WDOG_CTRL_REG); 121 outl(0x0, iobase + ADDI_WDOG_RELOAD_REG); 122} 123EXPORT_SYMBOL_GPL(addi_watchdog_reset); 124 125int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase) 126{ 127 struct addi_watchdog_private *spriv; 128 129 spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); 130 if (!spriv) 131 return -ENOMEM; 132 comedi_set_spriv(s, spriv); 133 134 spriv->iobase = iobase; 135 136 s->type = COMEDI_SUBD_TIMER; 137 s->subdev_flags = SDF_WRITEABLE; 138 s->n_chan = 1; 139 s->maxdata = 0xff; 140 s->insn_config = addi_watchdog_insn_config; 141 s->insn_read = addi_watchdog_insn_read; 142 s->insn_write = addi_watchdog_insn_write; 143 144 return 0; 145} 146EXPORT_SYMBOL_GPL(addi_watchdog_init); 147 148static int __init addi_watchdog_module_init(void) 149{ 150 return 0; 151} 152module_init(addi_watchdog_module_init); 153 154static void __exit addi_watchdog_module_exit(void) 155{ 156} 157module_exit(addi_watchdog_module_exit); 158 159MODULE_DESCRIPTION("ADDI-DATA Watchdog subdevice"); 160MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); 161MODULE_LICENSE("GPL"); 162