]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/staging/comedi/drivers/addi_apci_2032.c
staging: comedi: addi_apci_2032: remove the timer s->range_table
[mirror_ubuntu-bionic-kernel.git] / drivers / staging / comedi / drivers / addi_apci_2032.c
CommitLineData
d02178b7
HS
1/*
2 * addi_apci_2032.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 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 * You should also find the complete GPL in the COPYING file accompanying
29 * this source code.
30 */
31
3d41c443
HS
32#include "../comedidev.h"
33#include "comedi_fc.h"
34
d02178b7
HS
35/*
36 * PCI bar 1 I/O Register map
37 */
7180eb30
HS
38#define APCI2032_DO_REG 0x00
39#define APCI2032_INT_CTRL_REG 0x04
40#define APCI2032_INT_CTRL_VCC_ENA (1 << 0)
41#define APCI2032_INT_CTRL_CC_ENA (1 << 1)
42#define APCI2032_INT_STATUS_REG 0x08
43#define APCI2032_INT_STATUS_VCC (1 << 0)
44#define APCI2032_INT_STATUS_CC (1 << 1)
45#define APCI2032_STATUS_REG 0x0c
46#define APCI2032_STATUS_IRQ (1 << 0)
47#define APCI2032_WDOG_REG 0x10
48#define APCI2032_WDOG_RELOAD_REG 0x14
49#define APCI2032_WDOG_TIMEBASE 0x18
50#define APCI2032_WDOG_CTRL_REG 0x1c
51#define APCI2032_WDOG_CTRL_ENABLE (1 << 0)
52#define APCI2032_WDOG_CTRL_SW_TRIG (1 << 9)
53#define APCI2032_WDOG_STATUS_REG 0x20
54#define APCI2032_WDOG_STATUS_ENABLED (1 << 0)
55#define APCI2032_WDOG_STATUS_SW_TRIG (1 << 1)
d02178b7
HS
56
57static unsigned int ui_InterruptData, ui_Type;
58
23fb1747
HS
59struct apci2032_private {
60 unsigned int wdog_ctrl;
61};
62
d02178b7
HS
63static int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev,
64 struct comedi_subdevice *s,
65 struct comedi_insn *insn,
66 unsigned int *data)
67{
d02178b7
HS
68 unsigned int ul_Command = 0;
69
d02178b7
HS
70 if ((data[0] != 0) && (data[0] != 1)) {
71 comedi_error(dev,
72 "Not a valid Data !!! ,Data should be 1 or 0\n");
73 return -EINVAL;
7180eb30
HS
74 }
75
f82a6613 76 if (data[1] == 1)
7180eb30
HS
77 ul_Command |= APCI2032_INT_CTRL_VCC_ENA;
78 else
79 ul_Command &= ~APCI2032_INT_CTRL_VCC_ENA;
80
f82a6613 81 if (data[2] == 1)
7180eb30
HS
82 ul_Command |= APCI2032_INT_CTRL_CC_ENA;
83 else
84 ul_Command &= ~APCI2032_INT_CTRL_CC_ENA;
85
86 outl(ul_Command, dev->iobase + APCI2032_INT_CTRL_REG);
87 ui_InterruptData = inl(dev->iobase + APCI2032_INT_CTRL_REG);
88
d02178b7
HS
89 return insn->n;
90}
91
92static int apci2032_do_insn_bits(struct comedi_device *dev,
93 struct comedi_subdevice *s,
94 struct comedi_insn *insn,
95 unsigned int *data)
96{
97 unsigned int mask = data[0];
98 unsigned int bits = data[1];
99
7180eb30 100 s->state = inl(dev->iobase + APCI2032_DO_REG);
d02178b7
HS
101 if (mask) {
102 s->state &= ~mask;
103 s->state |= (bits & mask);
104
7180eb30 105 outl(s->state, dev->iobase + APCI2032_DO_REG);
d02178b7
HS
106 }
107
108 data[1] = s->state;
109
110 return insn->n;
111}
112
23fb1747
HS
113/*
114 * The watchdog subdevice is configured with two INSN_CONFIG instructions:
115 *
116 * Enable the watchdog and set the reload timeout:
117 * data[0] = INSN_CONFIG_ARM
118 * data[1] = timeout reload value
119 *
120 * Disable the watchdog:
121 * data[0] = INSN_CONFIG_DISARM
122 */
123static int apci2032_wdog_insn_config(struct comedi_device *dev,
d02178b7
HS
124 struct comedi_subdevice *s,
125 struct comedi_insn *insn,
126 unsigned int *data)
127{
23fb1747
HS
128 struct apci2032_private *devpriv = dev->private;
129 unsigned int reload;
130
131 switch (data[0]) {
132 case INSN_CONFIG_ARM:
133 devpriv->wdog_ctrl = APCI2032_WDOG_CTRL_ENABLE;
134 reload = data[1] & s->maxdata;
135 outw(reload, dev->iobase + APCI2032_WDOG_RELOAD_REG);
136
137 /* Time base is 20ms, let the user know the timeout */
138 dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n",
139 20 * reload + 20);
140 break;
141 case INSN_CONFIG_DISARM:
142 devpriv->wdog_ctrl = 0;
143 break;
144 default:
d02178b7
HS
145 return -EINVAL;
146 }
147
23fb1747
HS
148 outw(devpriv->wdog_ctrl, dev->iobase + APCI2032_WDOG_CTRL_REG);
149
d02178b7
HS
150 return insn->n;
151}
152
23fb1747
HS
153static int apci2032_wdog_insn_write(struct comedi_device *dev,
154 struct comedi_subdevice *s,
155 struct comedi_insn *insn,
156 unsigned int *data)
d02178b7 157{
23fb1747
HS
158 struct apci2032_private *devpriv = dev->private;
159 int i;
160
161 if (devpriv->wdog_ctrl == 0) {
162 dev_warn(dev->class_dev, "watchdog is disabled\n");
d02178b7
HS
163 return -EINVAL;
164 }
23fb1747
HS
165
166 /* "ping" the watchdog */
167 for (i = 0; i < insn->n; i++) {
168 outw(devpriv->wdog_ctrl | APCI2032_WDOG_CTRL_SW_TRIG,
169 dev->iobase + APCI2032_WDOG_CTRL_REG);
170 }
171
d02178b7
HS
172 return insn->n;
173}
174
23fb1747 175static int apci2032_wdog_insn_read(struct comedi_device *dev,
d02178b7
HS
176 struct comedi_subdevice *s,
177 struct comedi_insn *insn,
178 unsigned int *data)
179{
7b5dd1cc
HS
180 int i;
181
182 for (i = 0; i < insn->n; i++)
183 data[i] = inl(dev->iobase + APCI2032_WDOG_STATUS_REG);
184
d02178b7
HS
185 return insn->n;
186}
187
188static int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev,
189 struct comedi_subdevice *s,
190 struct comedi_insn *insn,
191 unsigned int *data)
192{
193 *data = ui_Type;
194 return insn->n;
195}
7180eb30 196
d02178b7
HS
197static void v_APCI2032_Interrupt(int irq, void *d)
198{
199 struct comedi_device *dev = d;
d02178b7
HS
200 unsigned int ui_DO;
201
7180eb30
HS
202 /* Check if VCC OR CC interrupt has occurred */
203 ui_DO = inl(dev->iobase + APCI2032_STATUS_REG) & APCI2032_STATUS_IRQ;
d02178b7
HS
204
205 if (ui_DO == 0) {
206 printk("\nInterrupt from unKnown source\n");
207 } /* if(ui_DO==0) */
208 if (ui_DO) {
209 /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */
7180eb30
HS
210 ui_Type = inl(dev->iobase + APCI2032_INT_STATUS_REG);
211 ui_Type &= (APCI2032_INT_STATUS_VCC | APCI2032_INT_STATUS_CC);
212 outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG);
d02178b7 213
7180eb30 214 if (ui_Type)
dce10abc 215 ; /* send an event to indicate the interrupt */
7180eb30 216 }
d02178b7 217}
317285d7 218
25adf2cc
HS
219static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
220{
c0c3c7df 221 v_APCI2032_Interrupt(irq, d);
25adf2cc
HS
222 return IRQ_RETVAL(1);
223}
224
791c9792 225static int apci2032_reset(struct comedi_device *dev)
25adf2cc 226{
791c9792 227 ui_Type = 0;
7180eb30
HS
228 outl(0x0, dev->iobase + APCI2032_DO_REG);
229 outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG);
230 outl(0x0, dev->iobase + APCI2032_WDOG_CTRL_REG);
231 outl(0x0, dev->iobase + APCI2032_WDOG_RELOAD_REG);
25adf2cc 232
25adf2cc
HS
233 return 0;
234}
235
25adf2cc
HS
236static int apci2032_auto_attach(struct comedi_device *dev,
237 unsigned long context_unused)
238{
239 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
23fb1747 240 struct apci2032_private *devpriv;
25adf2cc 241 struct comedi_subdevice *s;
0c33bdd0 242 int ret;
25adf2cc 243
c0c3c7df 244 dev->board_name = dev->driver->driver_name;
25adf2cc 245
23fb1747
HS
246 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
247 if (!devpriv)
248 return -ENOMEM;
249 dev->private = devpriv;
250
25adf2cc
HS
251 ret = comedi_pci_enable(pcidev, dev->board_name);
252 if (ret)
253 return ret;
70ff4065 254 dev->iobase = pci_resource_start(pcidev, 1);
25adf2cc 255
25adf2cc
HS
256 if (pcidev->irq > 0) {
257 ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED,
258 dev->board_name, dev);
259 if (ret == 0)
260 dev->irq = pcidev->irq;
261 }
262
0c33bdd0 263 ret = comedi_alloc_subdevices(dev, 2);
25adf2cc
HS
264 if (ret)
265 return ret;
266
0c33bdd0 267 /* Initialize the digital output subdevice */
25adf2cc 268 s = &dev->subdevices[0];
cf110882
HS
269 s->type = COMEDI_SUBD_DO;
270 s->subdev_flags = SDF_WRITEABLE;
271 s->n_chan = 32;
272 s->maxdata = 1;
273 s->range_table = &range_digital;
274 s->insn_config = i_APCI2032_ConfigDigitalOutput;
275 s->insn_bits = apci2032_do_insn_bits;
276 s->insn_read = i_APCI2032_ReadInterruptStatus;
25adf2cc 277
0c33bdd0
HS
278 /* Initialize the watchdog subdevice */
279 s = &dev->subdevices[1];
cf110882
HS
280 s->type = COMEDI_SUBD_TIMER;
281 s->subdev_flags = SDF_WRITEABLE;
282 s->n_chan = 1;
283 s->maxdata = 0xff;
cf110882
HS
284 s->insn_write = apci2032_wdog_insn_write;
285 s->insn_read = apci2032_wdog_insn_read;
286 s->insn_config = apci2032_wdog_insn_config;
25adf2cc 287
791c9792 288 apci2032_reset(dev);
25adf2cc
HS
289 return 0;
290}
291
292static void apci2032_detach(struct comedi_device *dev)
293{
294 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
25adf2cc 295
dce10abc
HS
296 if (dev->iobase)
297 apci2032_reset(dev);
298 if (dev->irq)
299 free_irq(dev->irq, dev);
25adf2cc
HS
300 if (pcidev) {
301 if (dev->iobase)
302 comedi_pci_disable(pcidev);
303 }
304}
305
20a22b70
HS
306static struct comedi_driver apci2032_driver = {
307 .driver_name = "addi_apci_2032",
308 .module = THIS_MODULE,
25adf2cc
HS
309 .auto_attach = apci2032_auto_attach,
310 .detach = apci2032_detach,
20a22b70
HS
311};
312
a690b7e5 313static int apci2032_pci_probe(struct pci_dev *dev,
20a22b70
HS
314 const struct pci_device_id *ent)
315{
316 return comedi_pci_auto_config(dev, &apci2032_driver);
317}
318
53b80019 319static void apci2032_pci_remove(struct pci_dev *dev)
20a22b70
HS
320{
321 comedi_pci_auto_unconfig(dev);
322}
323
324static DEFINE_PCI_DEVICE_TABLE(apci2032_pci_table) = {
317285d7
HS
325 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1004) },
326 { 0 }
327};
20a22b70 328MODULE_DEVICE_TABLE(pci, apci2032_pci_table);
317285d7 329
20a22b70
HS
330static struct pci_driver apci2032_pci_driver = {
331 .name = "addi_apci_2032",
332 .id_table = apci2032_pci_table,
333 .probe = apci2032_pci_probe,
a471eace 334 .remove = apci2032_pci_remove,
20a22b70
HS
335};
336module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver);
90f703d3
AT
337
338MODULE_AUTHOR("Comedi http://www.comedi.org");
339MODULE_DESCRIPTION("Comedi low-level driver");
340MODULE_LICENSE("GPL");