1/* 2 * addi_apci_1032.c 3 * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. 4 * Project manager: Eric Stolz 5 * 6 * ADDI-DATA GmbH 7 * Dieselstrasse 3 8 * D-77833 Ottersweier 9 * Tel: +19(0)7223/9493-0 10 * Fax: +49(0)7223/9493-92 11 * http://www.addi-data.com 12 * info@addi-data.com 13 * 14 * This program is free software; you can redistribute it and/or modify it 15 * under the terms of the GNU General Public License as published by the 16 * Free Software Foundation; either version 2 of the License, or (at your 17 * option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, but WITHOUT 20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 22 * more details. 23 */ 24 25#include <linux/module.h> 26#include <linux/pci.h> 27#include <linux/interrupt.h> 28 29#include "../comedidev.h" 30#include "comedi_fc.h" 31#include "amcc_s5933.h" 32 33/* 34 * I/O Register Map 35 */ 36#define APCI1032_DI_REG 0x00 37#define APCI1032_MODE1_REG 0x04 38#define APCI1032_MODE2_REG 0x08 39#define APCI1032_STATUS_REG 0x0c 40#define APCI1032_CTRL_REG 0x10 41#define APCI1032_CTRL_INT_OR (0 << 1) 42#define APCI1032_CTRL_INT_AND (1 << 1) 43#define APCI1032_CTRL_INT_ENA (1 << 2) 44 45struct apci1032_private { 46 unsigned long amcc_iobase; /* base of AMCC I/O registers */ 47 unsigned int mode1; /* rising-edge/high level channels */ 48 unsigned int mode2; /* falling-edge/low level channels */ 49 unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ 50}; 51 52static int apci1032_reset(struct comedi_device *dev) 53{ 54 /* disable the interrupts */ 55 outl(0x0, dev->iobase + APCI1032_CTRL_REG); 56 /* Reset the interrupt status register */ 57 inl(dev->iobase + APCI1032_STATUS_REG); 58 /* Disable the and/or interrupt */ 59 outl(0x0, dev->iobase + APCI1032_MODE1_REG); 60 outl(0x0, dev->iobase + APCI1032_MODE2_REG); 61 62 return 0; 63} 64 65/* 66 * Change-Of-State (COS) interrupt configuration 67 * 68 * Channels 0 to 15 are interruptible. These channels can be configured 69 * to generate interrupts based on AND/OR logic for the desired channels. 70 * 71 * OR logic 72 * - reacts to rising or falling edges 73 * - interrupt is generated when any enabled channel 74 * meet the desired interrupt condition 75 * 76 * AND logic 77 * - reacts to changes in level of the selected inputs 78 * - interrupt is generated when all enabled channels 79 * meet the desired interrupt condition 80 * - after an interrupt, a change in level must occur on 81 * the selected inputs to release the IRQ logic 82 * 83 * The COS interrupt must be configured before it can be enabled. 84 * 85 * data[0] : INSN_CONFIG_DIGITAL_TRIG 86 * data[1] : trigger number (= 0) 87 * data[2] : configuration operation: 88 * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts 89 * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts 90 * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts 91 * data[3] : left-shift for data[4] and data[5] 92 * data[4] : rising-edge/high level channels 93 * data[5] : falling-edge/low level channels 94 */ 95static int apci1032_cos_insn_config(struct comedi_device *dev, 96 struct comedi_subdevice *s, 97 struct comedi_insn *insn, 98 unsigned int *data) 99{ 100 struct apci1032_private *devpriv = dev->private; 101 unsigned int shift, oldmask; 102 103 switch (data[0]) { 104 case INSN_CONFIG_DIGITAL_TRIG: 105 if (data[1] != 0) 106 return -EINVAL; 107 shift = data[3]; 108 oldmask = (1U << shift) - 1; 109 switch (data[2]) { 110 case COMEDI_DIGITAL_TRIG_DISABLE: 111 devpriv->ctrl = 0; 112 devpriv->mode1 = 0; 113 devpriv->mode2 = 0; 114 apci1032_reset(dev); 115 break; 116 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: 117 if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | 118 APCI1032_CTRL_INT_OR)) { 119 /* switching to 'OR' mode */ 120 devpriv->ctrl = APCI1032_CTRL_INT_ENA | 121 APCI1032_CTRL_INT_OR; 122 /* wipe old channels */ 123 devpriv->mode1 = 0; 124 devpriv->mode2 = 0; 125 } else { 126 /* preserve unspecified channels */ 127 devpriv->mode1 &= oldmask; 128 devpriv->mode2 &= oldmask; 129 } 130 /* configure specified channels */ 131 devpriv->mode1 |= data[4] << shift; 132 devpriv->mode2 |= data[5] << shift; 133 break; 134 case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: 135 if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | 136 APCI1032_CTRL_INT_AND)) { 137 /* switching to 'AND' mode */ 138 devpriv->ctrl = APCI1032_CTRL_INT_ENA | 139 APCI1032_CTRL_INT_AND; 140 /* wipe old channels */ 141 devpriv->mode1 = 0; 142 devpriv->mode2 = 0; 143 } else { 144 /* preserve unspecified channels */ 145 devpriv->mode1 &= oldmask; 146 devpriv->mode2 &= oldmask; 147 } 148 /* configure specified channels */ 149 devpriv->mode1 |= data[4] << shift; 150 devpriv->mode2 |= data[5] << shift; 151 break; 152 default: 153 return -EINVAL; 154 } 155 break; 156 default: 157 return -EINVAL; 158 } 159 160 return insn->n; 161} 162 163static int apci1032_cos_insn_bits(struct comedi_device *dev, 164 struct comedi_subdevice *s, 165 struct comedi_insn *insn, 166 unsigned int *data) 167{ 168 data[1] = s->state; 169 170 return 0; 171} 172 173static int apci1032_cos_cmdtest(struct comedi_device *dev, 174 struct comedi_subdevice *s, 175 struct comedi_cmd *cmd) 176{ 177 int err = 0; 178 179 /* Step 1 : check if triggers are trivially valid */ 180 181 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 182 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); 183 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); 184 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 185 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); 186 187 if (err) 188 return 1; 189 190 /* Step 2a : make sure trigger sources are unique */ 191 /* Step 2b : and mutually compatible */ 192 193 /* Step 3: check if arguments are trivially valid */ 194 195 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 196 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 197 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); 198 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 199 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 200 201 if (err) 202 return 3; 203 204 /* Step 4: fix up any arguments */ 205 206 /* Step 5: check channel list if it exists */ 207 208 return 0; 209} 210 211/* 212 * Change-Of-State (COS) 'do_cmd' operation 213 * 214 * Enable the COS interrupt as configured by apci1032_cos_insn_config(). 215 */ 216static int apci1032_cos_cmd(struct comedi_device *dev, 217 struct comedi_subdevice *s) 218{ 219 struct apci1032_private *devpriv = dev->private; 220 221 if (!devpriv->ctrl) { 222 dev_warn(dev->class_dev, 223 "Interrupts disabled due to mode configuration!\n"); 224 return -EINVAL; 225 } 226 227 outl(devpriv->mode1, dev->iobase + APCI1032_MODE1_REG); 228 outl(devpriv->mode2, dev->iobase + APCI1032_MODE2_REG); 229 outl(devpriv->ctrl, dev->iobase + APCI1032_CTRL_REG); 230 231 return 0; 232} 233 234static int apci1032_cos_cancel(struct comedi_device *dev, 235 struct comedi_subdevice *s) 236{ 237 return apci1032_reset(dev); 238} 239 240static irqreturn_t apci1032_interrupt(int irq, void *d) 241{ 242 struct comedi_device *dev = d; 243 struct apci1032_private *devpriv = dev->private; 244 struct comedi_subdevice *s = dev->read_subdev; 245 unsigned int ctrl; 246 247 /* check interrupt is from this device */ 248 if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) & 249 INTCSR_INTR_ASSERTED) == 0) 250 return IRQ_NONE; 251 252 /* check interrupt is enabled */ 253 ctrl = inl(dev->iobase + APCI1032_CTRL_REG); 254 if ((ctrl & APCI1032_CTRL_INT_ENA) == 0) 255 return IRQ_HANDLED; 256 257 /* disable the interrupt */ 258 outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG); 259 260 s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff; 261 comedi_buf_put(s, s->state); 262 s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; 263 comedi_event(dev, s); 264 265 /* enable the interrupt */ 266 outl(ctrl, dev->iobase + APCI1032_CTRL_REG); 267 268 return IRQ_HANDLED; 269} 270 271static int apci1032_di_insn_bits(struct comedi_device *dev, 272 struct comedi_subdevice *s, 273 struct comedi_insn *insn, 274 unsigned int *data) 275{ 276 data[1] = inl(dev->iobase + APCI1032_DI_REG); 277 278 return insn->n; 279} 280 281static int apci1032_auto_attach(struct comedi_device *dev, 282 unsigned long context_unused) 283{ 284 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 285 struct apci1032_private *devpriv; 286 struct comedi_subdevice *s; 287 int ret; 288 289 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 290 if (!devpriv) 291 return -ENOMEM; 292 293 ret = comedi_pci_enable(dev); 294 if (ret) 295 return ret; 296 297 devpriv->amcc_iobase = pci_resource_start(pcidev, 0); 298 dev->iobase = pci_resource_start(pcidev, 1); 299 apci1032_reset(dev); 300 if (pcidev->irq > 0) { 301 ret = request_irq(pcidev->irq, apci1032_interrupt, IRQF_SHARED, 302 dev->board_name, dev); 303 if (ret == 0) 304 dev->irq = pcidev->irq; 305 } 306 307 ret = comedi_alloc_subdevices(dev, 2); 308 if (ret) 309 return ret; 310 311 /* Allocate and Initialise DI Subdevice Structures */ 312 s = &dev->subdevices[0]; 313 s->type = COMEDI_SUBD_DI; 314 s->subdev_flags = SDF_READABLE; 315 s->n_chan = 32; 316 s->maxdata = 1; 317 s->range_table = &range_digital; 318 s->insn_bits = apci1032_di_insn_bits; 319 320 /* Change-Of-State (COS) interrupt subdevice */ 321 s = &dev->subdevices[1]; 322 if (dev->irq) { 323 dev->read_subdev = s; 324 s->type = COMEDI_SUBD_DI; 325 s->subdev_flags = SDF_READABLE | SDF_CMD_READ; 326 s->n_chan = 1; 327 s->maxdata = 1; 328 s->range_table = &range_digital; 329 s->insn_config = apci1032_cos_insn_config; 330 s->insn_bits = apci1032_cos_insn_bits; 331 s->len_chanlist = 1; 332 s->do_cmdtest = apci1032_cos_cmdtest; 333 s->do_cmd = apci1032_cos_cmd; 334 s->cancel = apci1032_cos_cancel; 335 } else { 336 s->type = COMEDI_SUBD_UNUSED; 337 } 338 339 return 0; 340} 341 342static void apci1032_detach(struct comedi_device *dev) 343{ 344 if (dev->iobase) 345 apci1032_reset(dev); 346 comedi_pci_detach(dev); 347} 348 349static struct comedi_driver apci1032_driver = { 350 .driver_name = "addi_apci_1032", 351 .module = THIS_MODULE, 352 .auto_attach = apci1032_auto_attach, 353 .detach = apci1032_detach, 354}; 355 356static int apci1032_pci_probe(struct pci_dev *dev, 357 const struct pci_device_id *id) 358{ 359 return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data); 360} 361 362static const struct pci_device_id apci1032_pci_table[] = { 363 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) }, 364 { 0 } 365}; 366MODULE_DEVICE_TABLE(pci, apci1032_pci_table); 367 368static struct pci_driver apci1032_pci_driver = { 369 .name = "addi_apci_1032", 370 .id_table = apci1032_pci_table, 371 .probe = apci1032_pci_probe, 372 .remove = comedi_pci_auto_unconfig, 373}; 374module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); 375 376MODULE_AUTHOR("Comedi http://www.comedi.org"); 377MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards"); 378MODULE_LICENSE("GPL"); 379