]> Pileus Git - ~andy/linux/blob - drivers/staging/comedi/drivers/cb_pcidda.c
0e5b85d9bb9edc7b91418aa32d808f76698ae74f
[~andy/linux] / drivers / staging / comedi / drivers / cb_pcidda.c
1 /*
2     comedi/drivers/cb_pcidda.c
3     This intends to be a driver for the ComputerBoards / MeasurementComputing
4     PCI-DDA series.
5
6          Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>
7     Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
8
9     COMEDI - Linux Control and Measurement Device Interface
10     Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
11
12     This program is free software; you can redistribute it and/or modify
13     it under the terms of the GNU General Public License as published by
14     the Free Software Foundation; either version 2 of the License, or
15     (at your option) any later version.
16
17     This program is distributed in the hope that it will be useful,
18     but WITHOUT ANY WARRANTY; without even the implied warranty of
19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20     GNU General Public License for more details.
21
22     You should have received a copy of the GNU General Public License
23     along with this program; if not, write to the Free Software
24     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25
26 */
27 /*
28 Driver: cb_pcidda
29 Description: MeasurementComputing PCI-DDA series
30 Author: Ivan Martinez <ivanmr@altavista.com>, Frank Mori Hess <fmhess@users.sourceforge.net>
31 Status: Supports 08/16, 04/16, 02/16, 08/12, 04/12, and 02/12
32 Devices: [Measurement Computing] PCI-DDA08/12 (cb_pcidda), PCI-DDA04/12,
33   PCI-DDA02/12, PCI-DDA08/16, PCI-DDA04/16, PCI-DDA02/16
34
35 Configuration options:
36   [0] - PCI bus of device (optional)
37   [1] - PCI slot of device (optional)
38   If bus/slot is not specified, the first available PCI
39   device will be used.
40
41 Only simple analog output writing is supported.
42
43 So far it has only been tested with:
44   - PCI-DDA08/12
45 Please report success/failure with other different cards to
46 <comedi@comedi.org>.
47 */
48
49 #include "../comedidev.h"
50
51 #include "comedi_fc.h"
52 #include "8255.h"
53
54 /*
55  * ComputerBoards PCI Device ID's supported by this driver
56  */
57 #define PCI_DEVICE_ID_DDA02_12          0x0020
58 #define PCI_DEVICE_ID_DDA04_12          0x0021
59 #define PCI_DEVICE_ID_DDA08_12          0x0022
60 #define PCI_DEVICE_ID_DDA02_16          0x0023
61 #define PCI_DEVICE_ID_DDA04_16          0x0024
62 #define PCI_DEVICE_ID_DDA08_16          0x0025
63
64 #define EEPROM_SIZE     128     /*  number of entries in eeprom */
65 /* maximum number of ao channels for supported boards */
66 #define MAX_AO_CHANNELS 8
67
68 /* Digital I/O registers */
69 #define PORT1A 0                /*  PORT 1A DATA */
70
71 #define PORT1B 1                /*  PORT 1B DATA */
72
73 #define PORT1C 2                /*  PORT 1C DATA */
74
75 #define CONTROL1 3              /*  CONTROL REGISTER 1 */
76
77 #define PORT2A 4                /*  PORT 2A DATA */
78
79 #define PORT2B 5                /*  PORT 2B DATA */
80
81 #define PORT2C 6                /*  PORT 2C DATA */
82
83 #define CONTROL2 7              /*  CONTROL REGISTER 2 */
84
85 /* DAC registers */
86 #define DACONTROL       0       /*  D/A CONTROL REGISTER */
87 #define SU      0000001         /*  Simultaneous update enabled */
88 #define NOSU    0000000         /*  Simultaneous update disabled */
89 #define ENABLEDAC       0000002 /*  Enable specified DAC */
90 #define DISABLEDAC      0000000 /*  Disable specified DAC */
91 #define RANGE2V5        0000000 /*  2.5V */
92 #define RANGE5V 0000200         /*  5V */
93 #define RANGE10V        0000300 /*  10V */
94 #define UNIP    0000400         /*  Unipolar outputs */
95 #define BIP     0000000         /*  Bipolar outputs */
96
97 #define DACALIBRATION1  4       /*  D/A CALIBRATION REGISTER 1 */
98 /* write bits */
99 /* serial data input for eeprom, caldacs, reference dac */
100 #define SERIAL_IN_BIT   0x1
101 #define CAL_CHANNEL_MASK        (0x7 << 1)
102 #define CAL_CHANNEL_BITS(channel)       (((channel) << 1) & CAL_CHANNEL_MASK)
103 /* read bits */
104 #define CAL_COUNTER_MASK        0x1f
105 /* calibration counter overflow status bit */
106 #define CAL_COUNTER_OVERFLOW_BIT        0x20
107 /* analog output is less than reference dac voltage */
108 #define AO_BELOW_REF_BIT        0x40
109 #define SERIAL_OUT_BIT  0x80    /*  serial data out, for reading from eeprom */
110
111 #define DACALIBRATION2  6       /*  D/A CALIBRATION REGISTER 2 */
112 #define SELECT_EEPROM_BIT       0x1     /*  send serial data in to eeprom */
113 /* don't send serial data to MAX542 reference dac */
114 #define DESELECT_REF_DAC_BIT    0x2
115 /* don't send serial data to caldac n */
116 #define DESELECT_CALDAC_BIT(n)  (0x4 << (n))
117 /* manual says to set this bit with no explanation */
118 #define DUMMY_BIT       0x40
119
120 #define DADATA  8               /*  FIRST D/A DATA REGISTER (0) */
121
122 static const struct comedi_lrange cb_pcidda_ranges = {
123         6,
124         {
125          BIP_RANGE(10),
126          BIP_RANGE(5),
127          BIP_RANGE(2.5),
128          UNI_RANGE(10),
129          UNI_RANGE(5),
130          UNI_RANGE(2.5),
131          }
132 };
133
134 /*
135  * Board descriptions for two imaginary boards.  Describing the
136  * boards in this way is optional, and completely driver-dependent.
137  * Some drivers use arrays such as this, other do not.
138  */
139 struct cb_pcidda_board {
140         const char *name;
141         char status;            /*  Driver status: */
142
143         /*
144          * 0 - tested
145          * 1 - manual read, not tested
146          * 2 - manual not read
147          */
148
149         unsigned short device_id;
150         int ao_chans;
151         int ao_bits;
152         const struct comedi_lrange *ranges;
153 };
154
155 static const struct cb_pcidda_board cb_pcidda_boards[] = {
156         {
157          .name = "pci-dda02/12",
158          .status = 1,
159          .device_id = PCI_DEVICE_ID_DDA02_12,
160          .ao_chans = 2,
161          .ao_bits = 12,
162          .ranges = &cb_pcidda_ranges,
163          },
164         {
165          .name = "pci-dda04/12",
166          .status = 1,
167          .device_id = PCI_DEVICE_ID_DDA04_12,
168          .ao_chans = 4,
169          .ao_bits = 12,
170          .ranges = &cb_pcidda_ranges,
171          },
172         {
173          .name = "pci-dda08/12",
174          .status = 0,
175          .device_id = PCI_DEVICE_ID_DDA08_12,
176          .ao_chans = 8,
177          .ao_bits = 12,
178          .ranges = &cb_pcidda_ranges,
179          },
180         {
181          .name = "pci-dda02/16",
182          .status = 2,
183          .device_id = PCI_DEVICE_ID_DDA02_16,
184          .ao_chans = 2,
185          .ao_bits = 16,
186          .ranges = &cb_pcidda_ranges,
187          },
188         {
189          .name = "pci-dda04/16",
190          .status = 2,
191          .device_id = PCI_DEVICE_ID_DDA04_16,
192          .ao_chans = 4,
193          .ao_bits = 16,
194          .ranges = &cb_pcidda_ranges,
195          },
196         {
197          .name = "pci-dda08/16",
198          .status = 0,
199          .device_id = PCI_DEVICE_ID_DDA08_16,
200          .ao_chans = 8,
201          .ao_bits = 16,
202          .ranges = &cb_pcidda_ranges,
203          },
204 };
205
206 struct cb_pcidda_private {
207         /* bits last written to da calibration register 1 */
208         unsigned int dac_cal1_bits;
209         /* current range settings for output channels */
210         unsigned int ao_range[MAX_AO_CHANNELS];
211         u16 eeprom_data[EEPROM_SIZE];   /*  software copy of board's eeprom */
212 };
213
214 /* lowlevel read from eeprom */
215 static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
216 {
217         unsigned int value = 0;
218         int i;
219         const int value_width = 16;     /*  number of bits wide values are */
220
221         for (i = 1; i <= value_width; i++) {
222                 /*  read bits most significant bit first */
223                 if (inw_p(dev->iobase + DACALIBRATION1) & SERIAL_OUT_BIT)
224                         value |= 1 << (value_width - i);
225         }
226
227         return value;
228 }
229
230 /* lowlevel write to eeprom/dac */
231 static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
232                                  unsigned int num_bits)
233 {
234         struct cb_pcidda_private *devpriv = dev->private;
235         int i;
236
237         for (i = 1; i <= num_bits; i++) {
238                 /*  send bits most significant bit first */
239                 if (value & (1 << (num_bits - i)))
240                         devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
241                 else
242                         devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
243                 outw_p(devpriv->dac_cal1_bits, dev->iobase + DACALIBRATION1);
244         }
245 }
246
247 /* reads a 16 bit value from board's eeprom */
248 static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
249                                           unsigned int address)
250 {
251         unsigned int i;
252         unsigned int cal2_bits;
253         unsigned int value;
254         /* one caldac for every two dac channels */
255         const int max_num_caldacs = 4;
256         /* bits to send to tell eeprom we want to read */
257         const int read_instruction = 0x6;
258         const int instruction_length = 3;
259         const int address_length = 8;
260
261         /*  send serial output stream to eeprom */
262         cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
263         /*  deactivate caldacs (one caldac for every two channels) */
264         for (i = 0; i < max_num_caldacs; i++)
265                 cal2_bits |= DESELECT_CALDAC_BIT(i);
266         outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
267
268         /*  tell eeprom we want to read */
269         cb_pcidda_serial_out(dev, read_instruction, instruction_length);
270         /*  send address we want to read from */
271         cb_pcidda_serial_out(dev, address, address_length);
272
273         value = cb_pcidda_serial_in(dev);
274
275         /*  deactivate eeprom */
276         cal2_bits &= ~SELECT_EEPROM_BIT;
277         outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
278
279         return value;
280 }
281
282 /* writes to 8 bit calibration dacs */
283 static void cb_pcidda_write_caldac(struct comedi_device *dev,
284                                    unsigned int caldac, unsigned int channel,
285                                    unsigned int value)
286 {
287         unsigned int cal2_bits;
288         unsigned int i;
289         /* caldacs use 3 bit channel specification */
290         const int num_channel_bits = 3;
291         const int num_caldac_bits = 8;  /*  8 bit calibration dacs */
292         /* one caldac for every two dac channels */
293         const int max_num_caldacs = 4;
294
295         /* write 3 bit channel */
296         cb_pcidda_serial_out(dev, channel, num_channel_bits);
297         /*  write 8 bit caldac value */
298         cb_pcidda_serial_out(dev, value, num_caldac_bits);
299
300 /*
301 * latch stream into appropriate caldac deselect reference dac
302 */
303         cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
304         /*  deactivate caldacs (one caldac for every two channels) */
305         for (i = 0; i < max_num_caldacs; i++)
306                 cal2_bits |= DESELECT_CALDAC_BIT(i);
307         /*  activate the caldac we want */
308         cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
309         outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
310         /*  deactivate caldac */
311         cal2_bits |= DESELECT_CALDAC_BIT(caldac);
312         outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
313 }
314
315 /* returns caldac that calibrates given analog out channel */
316 static unsigned int caldac_number(unsigned int channel)
317 {
318         return channel / 2;
319 }
320
321 /* returns caldac channel that provides fine gain for given ao channel */
322 static unsigned int fine_gain_channel(unsigned int ao_channel)
323 {
324         return 4 * (ao_channel % 2);
325 }
326
327 /* returns caldac channel that provides coarse gain for given ao channel */
328 static unsigned int coarse_gain_channel(unsigned int ao_channel)
329 {
330         return 1 + 4 * (ao_channel % 2);
331 }
332
333 /* returns caldac channel that provides coarse offset for given ao channel */
334 static unsigned int coarse_offset_channel(unsigned int ao_channel)
335 {
336         return 2 + 4 * (ao_channel % 2);
337 }
338
339 /* returns caldac channel that provides fine offset for given ao channel */
340 static unsigned int fine_offset_channel(unsigned int ao_channel)
341 {
342         return 3 + 4 * (ao_channel % 2);
343 }
344
345 /* returns eeprom address that provides offset for given ao channel and range */
346 static unsigned int offset_eeprom_address(unsigned int ao_channel,
347                                           unsigned int range)
348 {
349         return 0x7 + 2 * range + 12 * ao_channel;
350 }
351
352 /*
353  * returns eeprom address that provides gain calibration for given ao
354  * channel and range
355  */
356 static unsigned int gain_eeprom_address(unsigned int ao_channel,
357                                         unsigned int range)
358 {
359         return 0x8 + 2 * range + 12 * ao_channel;
360 }
361
362 /*
363  * returns upper byte of eeprom entry, which gives the coarse adjustment
364  * values
365  */
366 static unsigned int eeprom_coarse_byte(unsigned int word)
367 {
368         return (word >> 8) & 0xff;
369 }
370
371 /* returns lower byte of eeprom entry, which gives the fine adjustment values */
372 static unsigned int eeprom_fine_byte(unsigned int word)
373 {
374         return word & 0xff;
375 }
376
377 /* set caldacs to eeprom values for given channel and range */
378 static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
379                                 unsigned int range)
380 {
381         struct cb_pcidda_private *devpriv = dev->private;
382         unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
383
384         /* remember range so we can tell when we need to readjust calibration */
385         devpriv->ao_range[channel] = range;
386
387         /*  get values from eeprom data */
388         coarse_offset =
389             eeprom_coarse_byte(devpriv->eeprom_data
390                                [offset_eeprom_address(channel, range)]);
391         fine_offset =
392             eeprom_fine_byte(devpriv->eeprom_data
393                              [offset_eeprom_address(channel, range)]);
394         coarse_gain =
395             eeprom_coarse_byte(devpriv->eeprom_data
396                                [gain_eeprom_address(channel, range)]);
397         fine_gain =
398             eeprom_fine_byte(devpriv->eeprom_data
399                              [gain_eeprom_address(channel, range)]);
400
401         /*  set caldacs */
402         cb_pcidda_write_caldac(dev, caldac_number(channel),
403                                coarse_offset_channel(channel), coarse_offset);
404         cb_pcidda_write_caldac(dev, caldac_number(channel),
405                                fine_offset_channel(channel), fine_offset);
406         cb_pcidda_write_caldac(dev, caldac_number(channel),
407                                coarse_gain_channel(channel), coarse_gain);
408         cb_pcidda_write_caldac(dev, caldac_number(channel),
409                                fine_gain_channel(channel), fine_gain);
410 }
411
412 static int cb_pcidda_ao_winsn(struct comedi_device *dev,
413                               struct comedi_subdevice *s,
414                               struct comedi_insn *insn, unsigned int *data)
415 {
416         struct cb_pcidda_private *devpriv = dev->private;
417         unsigned int command;
418         unsigned int channel, range;
419
420         channel = CR_CHAN(insn->chanspec);
421         range = CR_RANGE(insn->chanspec);
422
423         /*  adjust calibration dacs if range has changed */
424         if (range != devpriv->ao_range[channel])
425                 cb_pcidda_calibrate(dev, channel, range);
426
427         /* output channel configuration */
428         command = NOSU | ENABLEDAC;
429
430         /* output channel range */
431         switch (range) {
432         case 0:
433                 command |= BIP | RANGE10V;
434                 break;
435         case 1:
436                 command |= BIP | RANGE5V;
437                 break;
438         case 2:
439                 command |= BIP | RANGE2V5;
440                 break;
441         case 3:
442                 command |= UNIP | RANGE10V;
443                 break;
444         case 4:
445                 command |= UNIP | RANGE5V;
446                 break;
447         case 5:
448                 command |= UNIP | RANGE2V5;
449                 break;
450         }
451
452         /* output channel specification */
453         command |= channel << 2;
454         outw(command, dev->iobase + DACONTROL);
455
456         /* write data */
457         outw(data[0], dev->iobase + DADATA + channel * 2);
458
459         /* return the number of samples read/written */
460         return 1;
461 }
462
463 static const void *cb_pcidda_find_boardinfo(struct comedi_device *dev,
464                                             struct pci_dev *pcidev)
465 {
466         const struct cb_pcidda_board *thisboard;
467         int i;
468
469         for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) {
470                 thisboard = &cb_pcidda_boards[i];
471                 if (thisboard->device_id != pcidev->device)
472                         return thisboard;
473         }
474         return NULL;
475 }
476
477 static int cb_pcidda_attach_pci(struct comedi_device *dev,
478                                 struct pci_dev *pcidev)
479 {
480         const struct cb_pcidda_board *thisboard;
481         struct cb_pcidda_private *devpriv;
482         struct comedi_subdevice *s;
483         unsigned long iobase_8255;
484         int index;
485         int ret;
486
487         thisboard = cb_pcidda_find_boardinfo(dev, pcidev);
488         if (!thisboard)
489                 return -ENODEV;
490         dev->board_ptr = thisboard;
491         dev->board_name = thisboard->name;
492
493         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
494         if (!devpriv)
495                 return -ENOMEM;
496         dev->private = devpriv;
497
498         ret = comedi_pci_enable(pcidev, dev->board_name);
499         if (ret)
500                 return ret;
501         dev->iobase = pci_resource_start(pcidev, 3);
502         iobase_8255 = pci_resource_start(pcidev, 2);
503
504         if (thisboard->status == 2)
505                 printk
506                     ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. "
507                      "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. "
508                      "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n");
509
510         ret = comedi_alloc_subdevices(dev, 3);
511         if (ret)
512                 return ret;
513
514         s = &dev->subdevices[0];
515         /* analog output subdevice */
516         s->type = COMEDI_SUBD_AO;
517         s->subdev_flags = SDF_WRITABLE;
518         s->n_chan = thisboard->ao_chans;
519         s->maxdata = (1 << thisboard->ao_bits) - 1;
520         s->range_table = thisboard->ranges;
521         s->insn_write = cb_pcidda_ao_winsn;
522
523         /*  two 8255 digital io subdevices */
524         s = &dev->subdevices[1];
525         subdev_8255_init(dev, s, NULL, iobase_8255);
526         s = &dev->subdevices[2];
527         subdev_8255_init(dev, s, NULL, iobase_8255 + PORT2A);
528
529         /* Read the caldac eeprom data */
530         for (index = 0; index < EEPROM_SIZE; index++)
531                 devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
532
533         /*  set calibrations dacs */
534         for (index = 0; index < thisboard->ao_chans; index++)
535                 cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]);
536
537         dev_info(dev->class_dev, "%s attached\n", dev->board_name);
538
539         return 0;
540 }
541
542 static void cb_pcidda_detach(struct comedi_device *dev)
543 {
544         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
545
546         if (dev->subdevices) {
547                 subdev_8255_cleanup(dev, &dev->subdevices[1]);
548                 subdev_8255_cleanup(dev, &dev->subdevices[2]);
549         }
550         if (pcidev) {
551                 if (dev->iobase)
552                         comedi_pci_disable(pcidev);
553         }
554 }
555
556 static struct comedi_driver cb_pcidda_driver = {
557         .driver_name    = "cb_pcidda",
558         .module         = THIS_MODULE,
559         .attach_pci     = cb_pcidda_attach_pci,
560         .detach         = cb_pcidda_detach,
561 };
562
563 static int __devinit cb_pcidda_pci_probe(struct pci_dev *dev,
564                                          const struct pci_device_id *ent)
565 {
566         return comedi_pci_auto_config(dev, &cb_pcidda_driver);
567 }
568
569 static void __devexit cb_pcidda_pci_remove(struct pci_dev *dev)
570 {
571         comedi_pci_auto_unconfig(dev);
572 }
573
574 static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
575         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA02_12) },
576         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA04_12) },
577         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA08_12) },
578         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA02_16) },
579         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA04_16) },
580         { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_DDA08_16) },
581         { 0 }
582 };
583 MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
584
585 static struct pci_driver cb_pcidda_pci_driver = {
586         .name           = "cb_pcidda",
587         .id_table       = cb_pcidda_pci_table,
588         .probe          = cb_pcidda_pci_probe,
589         .remove         = __devexit_p(cb_pcidda_pci_remove),
590 };
591 module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
592
593 MODULE_AUTHOR("Comedi http://www.comedi.org");
594 MODULE_DESCRIPTION("Comedi low-level driver");
595 MODULE_LICENSE("GPL");