Merge branch 'samsung/pinctrl' into next/drivers
[deliverable/linux.git] / drivers / staging / comedi / drivers / dt3000.c
1 /*
2 comedi/drivers/dt3000.c
3 Data Translation DT3000 series driver
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1999 David A. Schleef <ds@schleef.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: dt3000
25 Description: Data Translation DT3000 series
26 Author: ds
27 Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003,
28 DT3003-PGL, DT3004, DT3005, DT3004-200
29 Updated: Mon, 14 Apr 2008 15:41:24 +0100
30 Status: works
31
32 Configuration Options:
33 [0] - PCI bus of device (optional)
34 [1] - PCI slot of device (optional)
35 If bus/slot is not specified, the first supported
36 PCI device found will be used.
37
38 There is code to support AI commands, but it may not work.
39
40 AO commands are not supported.
41 */
42
43 /*
44 The DT3000 series is Data Translation's attempt to make a PCI
45 data acquisition board. The design of this series is very nice,
46 since each board has an on-board DSP (Texas Instruments TMS320C52).
47 However, a few details are a little annoying. The boards lack
48 bus-mastering DMA, which eliminates them from serious work.
49 They also are not capable of autocalibration, which is a common
50 feature in modern hardware. The default firmware is pretty bad,
51 making it nearly impossible to write an RT compatible driver.
52 It would make an interesting project to write a decent firmware
53 for these boards.
54
55 Data Translation originally wanted an NDA for the documentation
56 for the 3k series. However, if you ask nicely, they might send
57 you the docs without one, also.
58 */
59
60 #define DEBUG 1
61
62 #include <linux/interrupt.h>
63 #include "../comedidev.h"
64 #include <linux/delay.h>
65
66 #define PCI_VENDOR_ID_DT 0x1116
67
68 static const struct comedi_lrange range_dt3000_ai = { 4, {
69 RANGE(-10, 10),
70 RANGE(-5, 5),
71 RANGE(-2.5, 2.5),
72 RANGE(-1.25, 1.25)
73 }
74 };
75
76 static const struct comedi_lrange range_dt3000_ai_pgl = { 4, {
77 RANGE(-10, 10),
78 RANGE(-1, 1),
79 RANGE(-0.1, 0.1),
80 RANGE(-0.02, 0.02)
81 }
82 };
83
84 struct dt3k_boardtype {
85
86 const char *name;
87 unsigned int device_id;
88 int adchan;
89 int adbits;
90 int ai_speed;
91 const struct comedi_lrange *adrange;
92 int dachan;
93 int dabits;
94 };
95
96 static const struct dt3k_boardtype dt3k_boardtypes[] = {
97 {.name = "dt3001",
98 .device_id = 0x22,
99 .adchan = 16,
100 .adbits = 12,
101 .adrange = &range_dt3000_ai,
102 .ai_speed = 3000,
103 .dachan = 2,
104 .dabits = 12,
105 },
106 {.name = "dt3001-pgl",
107 .device_id = 0x27,
108 .adchan = 16,
109 .adbits = 12,
110 .adrange = &range_dt3000_ai_pgl,
111 .ai_speed = 3000,
112 .dachan = 2,
113 .dabits = 12,
114 },
115 {.name = "dt3002",
116 .device_id = 0x23,
117 .adchan = 32,
118 .adbits = 12,
119 .adrange = &range_dt3000_ai,
120 .ai_speed = 3000,
121 .dachan = 0,
122 .dabits = 0,
123 },
124 {.name = "dt3003",
125 .device_id = 0x24,
126 .adchan = 64,
127 .adbits = 12,
128 .adrange = &range_dt3000_ai,
129 .ai_speed = 3000,
130 .dachan = 2,
131 .dabits = 12,
132 },
133 {.name = "dt3003-pgl",
134 .device_id = 0x28,
135 .adchan = 64,
136 .adbits = 12,
137 .adrange = &range_dt3000_ai_pgl,
138 .ai_speed = 3000,
139 .dachan = 2,
140 .dabits = 12,
141 },
142 {.name = "dt3004",
143 .device_id = 0x25,
144 .adchan = 16,
145 .adbits = 16,
146 .adrange = &range_dt3000_ai,
147 .ai_speed = 10000,
148 .dachan = 2,
149 .dabits = 12,
150 },
151 {.name = "dt3005", /* a.k.a. 3004-200 */
152 .device_id = 0x26,
153 .adchan = 16,
154 .adbits = 16,
155 .adrange = &range_dt3000_ai,
156 .ai_speed = 5000,
157 .dachan = 2,
158 .dabits = 12,
159 },
160 };
161
162 #define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
163
164 #define DT3000_SIZE (4*0x1000)
165
166 /* dual-ported RAM location definitions */
167
168 #define DPR_DAC_buffer (4*0x000)
169 #define DPR_ADC_buffer (4*0x800)
170 #define DPR_Command (4*0xfd3)
171 #define DPR_SubSys (4*0xfd3)
172 #define DPR_Encode (4*0xfd4)
173 #define DPR_Params(a) (4*(0xfd5+(a)))
174 #define DPR_Tick_Reg_Lo (4*0xff5)
175 #define DPR_Tick_Reg_Hi (4*0xff6)
176 #define DPR_DA_Buf_Front (4*0xff7)
177 #define DPR_DA_Buf_Rear (4*0xff8)
178 #define DPR_AD_Buf_Front (4*0xff9)
179 #define DPR_AD_Buf_Rear (4*0xffa)
180 #define DPR_Int_Mask (4*0xffb)
181 #define DPR_Intr_Flag (4*0xffc)
182 #define DPR_Response_Mbx (4*0xffe)
183 #define DPR_Command_Mbx (4*0xfff)
184
185 #define AI_FIFO_DEPTH 2003
186 #define AO_FIFO_DEPTH 2048
187
188 /* command list */
189
190 #define CMD_GETBRDINFO 0
191 #define CMD_CONFIG 1
192 #define CMD_GETCONFIG 2
193 #define CMD_START 3
194 #define CMD_STOP 4
195 #define CMD_READSINGLE 5
196 #define CMD_WRITESINGLE 6
197 #define CMD_CALCCLOCK 7
198 #define CMD_READEVENTS 8
199 #define CMD_WRITECTCTRL 16
200 #define CMD_READCTCTRL 17
201 #define CMD_WRITECT 18
202 #define CMD_READCT 19
203 #define CMD_WRITEDATA 32
204 #define CMD_READDATA 33
205 #define CMD_WRITEIO 34
206 #define CMD_READIO 35
207 #define CMD_WRITECODE 36
208 #define CMD_READCODE 37
209 #define CMD_EXECUTE 38
210 #define CMD_HALT 48
211
212 #define SUBS_AI 0
213 #define SUBS_AO 1
214 #define SUBS_DIN 2
215 #define SUBS_DOUT 3
216 #define SUBS_MEM 4
217 #define SUBS_CT 5
218
219 /* interrupt flags */
220 #define DT3000_CMDONE 0x80
221 #define DT3000_CTDONE 0x40
222 #define DT3000_DAHWERR 0x20
223 #define DT3000_DASWERR 0x10
224 #define DT3000_DAEMPTY 0x08
225 #define DT3000_ADHWERR 0x04
226 #define DT3000_ADSWERR 0x02
227 #define DT3000_ADFULL 0x01
228
229 #define DT3000_COMPLETION_MASK 0xff00
230 #define DT3000_COMMAND_MASK 0x00ff
231 #define DT3000_NOTPROCESSED 0x0000
232 #define DT3000_NOERROR 0x5500
233 #define DT3000_ERROR 0xaa00
234 #define DT3000_NOTSUPPORTED 0xff00
235
236 #define DT3000_EXTERNAL_CLOCK 1
237 #define DT3000_RISING_EDGE 2
238
239 #define TMODE_MASK 0x1c
240
241 #define DT3000_AD_TRIG_INTERNAL (0<<2)
242 #define DT3000_AD_TRIG_EXTERNAL (1<<2)
243 #define DT3000_AD_RETRIG_INTERNAL (2<<2)
244 #define DT3000_AD_RETRIG_EXTERNAL (3<<2)
245 #define DT3000_AD_EXTRETRIG (4<<2)
246
247 #define DT3000_CHANNEL_MODE_SE 0
248 #define DT3000_CHANNEL_MODE_DI 1
249
250 struct dt3k_private {
251 void __iomem *io_addr;
252 unsigned int lock;
253 unsigned int ao_readback[2];
254 unsigned int ai_front;
255 unsigned int ai_rear;
256 };
257
258 #define devpriv ((struct dt3k_private *)dev->private)
259
260 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
261 struct comedi_subdevice *s);
262 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
263 unsigned int round_mode);
264 static int dt3k_ai_cancel(struct comedi_device *dev,
265 struct comedi_subdevice *s);
266 #ifdef DEBUG
267 static void debug_intr_flags(unsigned int flags);
268 #endif
269
270 #define TIMEOUT 100
271
272 static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd)
273 {
274 int i;
275 unsigned int status = 0;
276
277 writew(cmd, devpriv->io_addr + DPR_Command_Mbx);
278
279 for (i = 0; i < TIMEOUT; i++) {
280 status = readw(devpriv->io_addr + DPR_Command_Mbx);
281 if ((status & DT3000_COMPLETION_MASK) != DT3000_NOTPROCESSED)
282 break;
283 udelay(1);
284 }
285 if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR)
286 return 0;
287
288 dev_dbg(dev->class_dev, "dt3k_send_cmd() timeout/error status=0x%04x\n",
289 status);
290
291 return -ETIME;
292 }
293
294 static unsigned int dt3k_readsingle(struct comedi_device *dev,
295 unsigned int subsys, unsigned int chan,
296 unsigned int gain)
297 {
298 writew(subsys, devpriv->io_addr + DPR_SubSys);
299
300 writew(chan, devpriv->io_addr + DPR_Params(0));
301 writew(gain, devpriv->io_addr + DPR_Params(1));
302
303 dt3k_send_cmd(dev, CMD_READSINGLE);
304
305 return readw(devpriv->io_addr + DPR_Params(2));
306 }
307
308 static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys,
309 unsigned int chan, unsigned int data)
310 {
311 writew(subsys, devpriv->io_addr + DPR_SubSys);
312
313 writew(chan, devpriv->io_addr + DPR_Params(0));
314 writew(0, devpriv->io_addr + DPR_Params(1));
315 writew(data, devpriv->io_addr + DPR_Params(2));
316
317 dt3k_send_cmd(dev, CMD_WRITESINGLE);
318 }
319
320 static int debug_n_ints;
321
322 /* FIXME! Assumes shared interrupt is for this card. */
323 /* What's this debug_n_ints stuff? Obviously needs some work... */
324 static irqreturn_t dt3k_interrupt(int irq, void *d)
325 {
326 struct comedi_device *dev = d;
327 struct comedi_subdevice *s;
328 unsigned int status;
329
330 if (!dev->attached)
331 return IRQ_NONE;
332
333 s = dev->subdevices + 0;
334 status = readw(devpriv->io_addr + DPR_Intr_Flag);
335 #ifdef DEBUG
336 debug_intr_flags(status);
337 #endif
338
339 if (status & DT3000_ADFULL) {
340 dt3k_ai_empty_fifo(dev, s);
341 s->async->events |= COMEDI_CB_BLOCK;
342 }
343
344 if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
345 s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
346
347 debug_n_ints++;
348 if (debug_n_ints >= 10) {
349 dt3k_ai_cancel(dev, s);
350 s->async->events |= COMEDI_CB_EOA;
351 }
352
353 comedi_event(dev, s);
354 return IRQ_HANDLED;
355 }
356
357 #ifdef DEBUG
358 static char *intr_flags[] = {
359 "AdFull", "AdSwError", "AdHwError", "DaEmpty",
360 "DaSwError", "DaHwError", "CtDone", "CmDone",
361 };
362
363 static void debug_intr_flags(unsigned int flags)
364 {
365 int i;
366 printk(KERN_DEBUG "dt3k: intr_flags:");
367 for (i = 0; i < 8; i++) {
368 if (flags & (1 << i))
369 printk(KERN_CONT " %s", intr_flags[i]);
370 }
371 printk(KERN_CONT "\n");
372 }
373 #endif
374
375 static void dt3k_ai_empty_fifo(struct comedi_device *dev,
376 struct comedi_subdevice *s)
377 {
378 int front;
379 int rear;
380 int count;
381 int i;
382 short data;
383
384 front = readw(devpriv->io_addr + DPR_AD_Buf_Front);
385 count = front - devpriv->ai_front;
386 if (count < 0)
387 count += AI_FIFO_DEPTH;
388
389 dev_dbg(dev->class_dev, "reading %d samples\n", count);
390
391 rear = devpriv->ai_rear;
392
393 for (i = 0; i < count; i++) {
394 data = readw(devpriv->io_addr + DPR_ADC_buffer + rear);
395 comedi_buf_put(s->async, data);
396 rear++;
397 if (rear >= AI_FIFO_DEPTH)
398 rear = 0;
399 }
400
401 devpriv->ai_rear = rear;
402 writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear);
403 }
404
405 static int dt3k_ai_cmdtest(struct comedi_device *dev,
406 struct comedi_subdevice *s, struct comedi_cmd *cmd)
407 {
408 int err = 0;
409 int tmp;
410
411 /* step 1: make sure trigger sources are trivially valid */
412
413 tmp = cmd->start_src;
414 cmd->start_src &= TRIG_NOW;
415 if (!cmd->start_src || tmp != cmd->start_src)
416 err++;
417
418 tmp = cmd->scan_begin_src;
419 cmd->scan_begin_src &= TRIG_TIMER;
420 if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
421 err++;
422
423 tmp = cmd->convert_src;
424 cmd->convert_src &= TRIG_TIMER;
425 if (!cmd->convert_src || tmp != cmd->convert_src)
426 err++;
427
428 tmp = cmd->scan_end_src;
429 cmd->scan_end_src &= TRIG_COUNT;
430 if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
431 err++;
432
433 tmp = cmd->stop_src;
434 cmd->stop_src &= TRIG_COUNT;
435 if (!cmd->stop_src || tmp != cmd->stop_src)
436 err++;
437
438 if (err)
439 return 1;
440
441 /* step 2: make sure trigger sources are unique and mutually compatible */
442
443 if (err)
444 return 2;
445
446 /* step 3: make sure arguments are trivially compatible */
447
448 if (cmd->start_arg != 0) {
449 cmd->start_arg = 0;
450 err++;
451 }
452
453 if (cmd->scan_begin_src == TRIG_TIMER) {
454 if (cmd->scan_begin_arg < this_board->ai_speed) {
455 cmd->scan_begin_arg = this_board->ai_speed;
456 err++;
457 }
458 if (cmd->scan_begin_arg > 100 * 16 * 65535) {
459 cmd->scan_begin_arg = 100 * 16 * 65535;
460 err++;
461 }
462 } else {
463 /* not supported */
464 }
465 if (cmd->convert_src == TRIG_TIMER) {
466 if (cmd->convert_arg < this_board->ai_speed) {
467 cmd->convert_arg = this_board->ai_speed;
468 err++;
469 }
470 if (cmd->convert_arg > 50 * 16 * 65535) {
471 cmd->convert_arg = 50 * 16 * 65535;
472 err++;
473 }
474 } else {
475 /* not supported */
476 }
477
478 if (cmd->scan_end_arg != cmd->chanlist_len) {
479 cmd->scan_end_arg = cmd->chanlist_len;
480 err++;
481 }
482 if (cmd->stop_src == TRIG_COUNT) {
483 if (cmd->stop_arg > 0x00ffffff) {
484 cmd->stop_arg = 0x00ffffff;
485 err++;
486 }
487 } else {
488 /* TRIG_NONE */
489 if (cmd->stop_arg != 0) {
490 cmd->stop_arg = 0;
491 err++;
492 }
493 }
494
495 if (err)
496 return 3;
497
498 /* step 4: fix up any arguments */
499
500 if (cmd->scan_begin_src == TRIG_TIMER) {
501 tmp = cmd->scan_begin_arg;
502 dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
503 cmd->flags & TRIG_ROUND_MASK);
504 if (tmp != cmd->scan_begin_arg)
505 err++;
506 } else {
507 /* not supported */
508 }
509 if (cmd->convert_src == TRIG_TIMER) {
510 tmp = cmd->convert_arg;
511 dt3k_ns_to_timer(50, &cmd->convert_arg,
512 cmd->flags & TRIG_ROUND_MASK);
513 if (tmp != cmd->convert_arg)
514 err++;
515 if (cmd->scan_begin_src == TRIG_TIMER &&
516 cmd->scan_begin_arg <
517 cmd->convert_arg * cmd->scan_end_arg) {
518 cmd->scan_begin_arg =
519 cmd->convert_arg * cmd->scan_end_arg;
520 err++;
521 }
522 } else {
523 /* not supported */
524 }
525
526 if (err)
527 return 4;
528
529 return 0;
530 }
531
532 static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec,
533 unsigned int round_mode)
534 {
535 int divider, base, prescale;
536
537 /* This function needs improvment */
538 /* Don't know if divider==0 works. */
539
540 for (prescale = 0; prescale < 16; prescale++) {
541 base = timer_base * (prescale + 1);
542 switch (round_mode) {
543 case TRIG_ROUND_NEAREST:
544 default:
545 divider = (*nanosec + base / 2) / base;
546 break;
547 case TRIG_ROUND_DOWN:
548 divider = (*nanosec) / base;
549 break;
550 case TRIG_ROUND_UP:
551 divider = (*nanosec) / base;
552 break;
553 }
554 if (divider < 65536) {
555 *nanosec = divider * base;
556 return (prescale << 16) | (divider);
557 }
558 }
559
560 prescale = 15;
561 base = timer_base * (1 << prescale);
562 divider = 65535;
563 *nanosec = divider * base;
564 return (prescale << 16) | (divider);
565 }
566
567 static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
568 {
569 struct comedi_cmd *cmd = &s->async->cmd;
570 int i;
571 unsigned int chan, range, aref;
572 unsigned int divider;
573 unsigned int tscandiv;
574 int ret;
575 unsigned int mode;
576
577 dev_dbg(dev->class_dev, "dt3k_ai_cmd:\n");
578 for (i = 0; i < cmd->chanlist_len; i++) {
579 chan = CR_CHAN(cmd->chanlist[i]);
580 range = CR_RANGE(cmd->chanlist[i]);
581
582 writew((range << 6) | chan,
583 devpriv->io_addr + DPR_ADC_buffer + i);
584 }
585 aref = CR_AREF(cmd->chanlist[0]);
586
587 writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0));
588 dev_dbg(dev->class_dev, "param[0]=0x%04x\n", cmd->scan_end_arg);
589
590 if (cmd->convert_src == TRIG_TIMER) {
591 divider = dt3k_ns_to_timer(50, &cmd->convert_arg,
592 cmd->flags & TRIG_ROUND_MASK);
593 writew((divider >> 16), devpriv->io_addr + DPR_Params(1));
594 dev_dbg(dev->class_dev, "param[1]=0x%04x\n", divider >> 16);
595 writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2));
596 dev_dbg(dev->class_dev, "param[2]=0x%04x\n", divider & 0xffff);
597 } else {
598 /* not supported */
599 }
600
601 if (cmd->scan_begin_src == TRIG_TIMER) {
602 tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg,
603 cmd->flags & TRIG_ROUND_MASK);
604 writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3));
605 dev_dbg(dev->class_dev, "param[3]=0x%04x\n", tscandiv >> 16);
606 writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4));
607 dev_dbg(dev->class_dev, "param[4]=0x%04x\n", tscandiv & 0xffff);
608 } else {
609 /* not supported */
610 }
611
612 mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0;
613 writew(mode, devpriv->io_addr + DPR_Params(5));
614 dev_dbg(dev->class_dev, "param[5]=0x%04x\n", mode);
615 writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6));
616 dev_dbg(dev->class_dev, "param[6]=0x%04x\n", aref == AREF_DIFF);
617
618 writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7));
619 dev_dbg(dev->class_dev, "param[7]=0x%04x\n", AI_FIFO_DEPTH / 2);
620
621 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
622 ret = dt3k_send_cmd(dev, CMD_CONFIG);
623
624 writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR,
625 devpriv->io_addr + DPR_Int_Mask);
626
627 debug_n_ints = 0;
628
629 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
630 ret = dt3k_send_cmd(dev, CMD_START);
631
632 return 0;
633 }
634
635 static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
636 {
637 int ret;
638
639 writew(SUBS_AI, devpriv->io_addr + DPR_SubSys);
640 ret = dt3k_send_cmd(dev, CMD_STOP);
641
642 writew(0, devpriv->io_addr + DPR_Int_Mask);
643
644 return 0;
645 }
646
647 static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
648 struct comedi_insn *insn, unsigned int *data)
649 {
650 int i;
651 unsigned int chan, gain, aref;
652
653 chan = CR_CHAN(insn->chanspec);
654 gain = CR_RANGE(insn->chanspec);
655 /* XXX docs don't explain how to select aref */
656 aref = CR_AREF(insn->chanspec);
657
658 for (i = 0; i < insn->n; i++)
659 data[i] = dt3k_readsingle(dev, SUBS_AI, chan, gain);
660
661 return i;
662 }
663
664 static int dt3k_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
665 struct comedi_insn *insn, unsigned int *data)
666 {
667 int i;
668 unsigned int chan;
669
670 chan = CR_CHAN(insn->chanspec);
671 for (i = 0; i < insn->n; i++) {
672 dt3k_writesingle(dev, SUBS_AO, chan, data[i]);
673 devpriv->ao_readback[chan] = data[i];
674 }
675
676 return i;
677 }
678
679 static int dt3k_ao_insn_read(struct comedi_device *dev,
680 struct comedi_subdevice *s,
681 struct comedi_insn *insn, unsigned int *data)
682 {
683 int i;
684 unsigned int chan;
685
686 chan = CR_CHAN(insn->chanspec);
687 for (i = 0; i < insn->n; i++)
688 data[i] = devpriv->ao_readback[chan];
689
690 return i;
691 }
692
693 static void dt3k_dio_config(struct comedi_device *dev, int bits)
694 {
695 /* XXX */
696 writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys);
697
698 writew(bits, devpriv->io_addr + DPR_Params(0));
699 #if 0
700 /* don't know */
701 writew(0, devpriv->io_addr + DPR_Params(1));
702 writew(0, devpriv->io_addr + DPR_Params(2));
703 #endif
704
705 dt3k_send_cmd(dev, CMD_CONFIG);
706 }
707
708 static int dt3k_dio_insn_config(struct comedi_device *dev,
709 struct comedi_subdevice *s,
710 struct comedi_insn *insn, unsigned int *data)
711 {
712 int mask;
713
714 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
715
716 switch (data[0]) {
717 case INSN_CONFIG_DIO_OUTPUT:
718 s->io_bits |= mask;
719 break;
720 case INSN_CONFIG_DIO_INPUT:
721 s->io_bits &= ~mask;
722 break;
723 case INSN_CONFIG_DIO_QUERY:
724 data[1] =
725 (s->
726 io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT :
727 COMEDI_INPUT;
728 return insn->n;
729 break;
730 default:
731 return -EINVAL;
732 break;
733 }
734 mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3);
735 dt3k_dio_config(dev, mask);
736
737 return insn->n;
738 }
739
740 static int dt3k_dio_insn_bits(struct comedi_device *dev,
741 struct comedi_subdevice *s,
742 struct comedi_insn *insn, unsigned int *data)
743 {
744 if (data[0]) {
745 s->state &= ~data[0];
746 s->state |= data[1] & data[0];
747 dt3k_writesingle(dev, SUBS_DOUT, 0, s->state);
748 }
749 data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0);
750
751 return insn->n;
752 }
753
754 static int dt3k_mem_insn_read(struct comedi_device *dev,
755 struct comedi_subdevice *s,
756 struct comedi_insn *insn, unsigned int *data)
757 {
758 unsigned int addr = CR_CHAN(insn->chanspec);
759 int i;
760
761 for (i = 0; i < insn->n; i++) {
762 writew(SUBS_MEM, devpriv->io_addr + DPR_SubSys);
763 writew(addr, devpriv->io_addr + DPR_Params(0));
764 writew(1, devpriv->io_addr + DPR_Params(1));
765
766 dt3k_send_cmd(dev, CMD_READCODE);
767
768 data[i] = readw(devpriv->io_addr + DPR_Params(2));
769 }
770
771 return i;
772 }
773
774 static struct pci_dev *dt3000_find_pci_dev(struct comedi_device *dev,
775 struct comedi_devconfig *it)
776 {
777 struct pci_dev *pcidev = NULL;
778 int bus = it->options[0];
779 int slot = it->options[1];
780 int i;
781
782 for_each_pci_dev(pcidev) {
783 if (bus || slot) {
784 if (bus != pcidev->bus->number ||
785 slot != PCI_SLOT(pcidev->devfn))
786 continue;
787 }
788 if (pcidev->vendor != PCI_VENDOR_ID_DT)
789 continue;
790 for (i = 0; i < ARRAY_SIZE(dt3k_boardtypes); i++) {
791 if (dt3k_boardtypes[i].device_id != pcidev->device)
792 continue;
793 dev->board_ptr = dt3k_boardtypes + i;
794 return pcidev;
795 }
796 }
797 dev_err(dev->class_dev,
798 "No supported board found! (req. bus %d, slot %d)\n",
799 bus, slot);
800 return NULL;
801 }
802
803 static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
804 {
805 struct pci_dev *pcidev;
806 struct comedi_subdevice *s;
807 resource_size_t pci_base;
808 int ret = 0;
809
810 dev_dbg(dev->class_dev, "dt3000:\n");
811
812 ret = alloc_private(dev, sizeof(struct dt3k_private));
813 if (ret < 0)
814 return ret;
815
816 pcidev = dt3000_find_pci_dev(dev, it);
817 if (!pcidev)
818 return -EIO;
819 comedi_set_hw_dev(dev, &pcidev->dev);
820
821 ret = comedi_pci_enable(pcidev, "dt3000");
822 if (ret < 0)
823 return ret;
824 dev->iobase = 1; /* the "detach" needs this */
825
826 pci_base = pci_resource_start(pcidev, 0);
827 devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
828 if (!devpriv->io_addr)
829 return -ENOMEM;
830
831 dev->board_name = this_board->name;
832
833 if (request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED,
834 "dt3000", dev)) {
835 dev_err(dev->class_dev, "unable to allocate IRQ %u\n",
836 pcidev->irq);
837 return -EINVAL;
838 }
839 dev->irq = pcidev->irq;
840
841 ret = comedi_alloc_subdevices(dev, 4);
842 if (ret)
843 return ret;
844
845 s = dev->subdevices;
846 dev->read_subdev = s;
847
848 /* ai subdevice */
849 s->type = COMEDI_SUBD_AI;
850 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
851 s->n_chan = this_board->adchan;
852 s->insn_read = dt3k_ai_insn;
853 s->maxdata = (1 << this_board->adbits) - 1;
854 s->len_chanlist = 512;
855 s->range_table = &range_dt3000_ai; /* XXX */
856 s->do_cmd = dt3k_ai_cmd;
857 s->do_cmdtest = dt3k_ai_cmdtest;
858 s->cancel = dt3k_ai_cancel;
859
860 s++;
861 /* ao subsystem */
862 s->type = COMEDI_SUBD_AO;
863 s->subdev_flags = SDF_WRITABLE;
864 s->n_chan = 2;
865 s->insn_read = dt3k_ao_insn_read;
866 s->insn_write = dt3k_ao_insn;
867 s->maxdata = (1 << this_board->dabits) - 1;
868 s->len_chanlist = 1;
869 s->range_table = &range_bipolar10;
870
871 s++;
872 /* dio subsystem */
873 s->type = COMEDI_SUBD_DIO;
874 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
875 s->n_chan = 8;
876 s->insn_config = dt3k_dio_insn_config;
877 s->insn_bits = dt3k_dio_insn_bits;
878 s->maxdata = 1;
879 s->len_chanlist = 8;
880 s->range_table = &range_digital;
881
882 s++;
883 /* mem subsystem */
884 s->type = COMEDI_SUBD_MEMORY;
885 s->subdev_flags = SDF_READABLE;
886 s->n_chan = 0x1000;
887 s->insn_read = dt3k_mem_insn_read;
888 s->maxdata = 0xff;
889 s->len_chanlist = 1;
890 s->range_table = &range_unknown;
891
892 #if 0
893 s++;
894 /* proc subsystem */
895 s->type = COMEDI_SUBD_PROC;
896 #endif
897
898 return 0;
899 }
900
901 static void dt3000_detach(struct comedi_device *dev)
902 {
903 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
904
905 if (dev->irq)
906 free_irq(dev->irq, dev);
907 if (devpriv) {
908 if (devpriv->io_addr)
909 iounmap(devpriv->io_addr);
910 }
911 if (pcidev) {
912 if (dev->iobase)
913 comedi_pci_disable(pcidev);
914 pci_dev_put(pcidev);
915 }
916 }
917
918 static struct comedi_driver dt3000_driver = {
919 .driver_name = "dt3000",
920 .module = THIS_MODULE,
921 .attach = dt3000_attach,
922 .detach = dt3000_detach,
923 };
924
925 static int __devinit dt3000_pci_probe(struct pci_dev *dev,
926 const struct pci_device_id *ent)
927 {
928 return comedi_pci_auto_config(dev, &dt3000_driver);
929 }
930
931 static void __devexit dt3000_pci_remove(struct pci_dev *dev)
932 {
933 comedi_pci_auto_unconfig(dev);
934 }
935
936 static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
937 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
938 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
939 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
940 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
941 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
942 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
943 { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
944 { 0 }
945 };
946 MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
947
948 static struct pci_driver dt3000_pci_driver = {
949 .name = "dt3000",
950 .id_table = dt3000_pci_table,
951 .probe = dt3000_pci_probe,
952 .remove = __devexit_p(dt3000_pci_remove),
953 };
954 module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
955
956 MODULE_AUTHOR("Comedi http://www.comedi.org");
957 MODULE_DESCRIPTION("Comedi low-level driver");
958 MODULE_LICENSE("GPL");
This page took 0.071304 seconds and 5 git commands to generate.