1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44#include <linux/pci.h>
45
46#include "../comedidev.h"
47
48#include "comedi_fc.h"
49#include "8255.h"
50
51#define EEPROM_SIZE 128
52
53#define MAX_AO_CHANNELS 8
54
55
56#define CB_DDA_DIO0_8255_BASE 0x00
57#define CB_DDA_DIO1_8255_BASE 0x04
58
59
60#define CB_DDA_DA_CTRL_REG 0x00
61#define CB_DDA_DA_CTRL_SU (1 << 0)
62#define CB_DDA_DA_CTRL_EN (1 << 1)
63#define CB_DDA_DA_CTRL_DAC(x) ((x) << 2)
64#define CB_DDA_DA_CTRL_RANGE2V5 (0 << 6)
65#define CB_DDA_DA_CTRL_RANGE5V (2 << 6)
66#define CB_DDA_DA_CTRL_RANGE10V (3 << 6)
67#define CB_DDA_DA_CTRL_UNIP (1 << 8)
68
69#define DACALIBRATION1 4
70
71
72#define SERIAL_IN_BIT 0x1
73#define CAL_CHANNEL_MASK (0x7 << 1)
74#define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK)
75
76#define CAL_COUNTER_MASK 0x1f
77
78#define CAL_COUNTER_OVERFLOW_BIT 0x20
79
80#define AO_BELOW_REF_BIT 0x40
81#define SERIAL_OUT_BIT 0x80
82
83#define DACALIBRATION2 6
84#define SELECT_EEPROM_BIT 0x1
85
86#define DESELECT_REF_DAC_BIT 0x2
87
88#define DESELECT_CALDAC_BIT(n) (0x4 << (n))
89
90#define DUMMY_BIT 0x40
91
92#define CB_DDA_DA_DATA_REG(x) (0x08 + ((x) * 2))
93
94
95#define CB_DDA_CALDAC_FINE_GAIN 0
96#define CB_DDA_CALDAC_COURSE_GAIN 1
97#define CB_DDA_CALDAC_COURSE_OFFSET 2
98#define CB_DDA_CALDAC_FINE_OFFSET 3
99
100static const struct comedi_lrange cb_pcidda_ranges = {
101 6, {
102 BIP_RANGE(10),
103 BIP_RANGE(5),
104 BIP_RANGE(2.5),
105 UNI_RANGE(10),
106 UNI_RANGE(5),
107 UNI_RANGE(2.5)
108 }
109};
110
111enum cb_pcidda_boardid {
112 BOARD_DDA02_12,
113 BOARD_DDA04_12,
114 BOARD_DDA08_12,
115 BOARD_DDA02_16,
116 BOARD_DDA04_16,
117 BOARD_DDA08_16,
118};
119
120struct cb_pcidda_board {
121 const char *name;
122 int ao_chans;
123 int ao_bits;
124};
125
126static const struct cb_pcidda_board cb_pcidda_boards[] = {
127 [BOARD_DDA02_12] = {
128 .name = "pci-dda02/12",
129 .ao_chans = 2,
130 .ao_bits = 12,
131 },
132 [BOARD_DDA04_12] = {
133 .name = "pci-dda04/12",
134 .ao_chans = 4,
135 .ao_bits = 12,
136 },
137 [BOARD_DDA08_12] = {
138 .name = "pci-dda08/12",
139 .ao_chans = 8,
140 .ao_bits = 12,
141 },
142 [BOARD_DDA02_16] = {
143 .name = "pci-dda02/16",
144 .ao_chans = 2,
145 .ao_bits = 16,
146 },
147 [BOARD_DDA04_16] = {
148 .name = "pci-dda04/16",
149 .ao_chans = 4,
150 .ao_bits = 16,
151 },
152 [BOARD_DDA08_16] = {
153 .name = "pci-dda08/16",
154 .ao_chans = 8,
155 .ao_bits = 16,
156 },
157};
158
159struct cb_pcidda_private {
160
161 unsigned int dac_cal1_bits;
162
163 unsigned int ao_range[MAX_AO_CHANNELS];
164 u16 eeprom_data[EEPROM_SIZE];
165};
166
167
168static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
169{
170 unsigned int value = 0;
171 int i;
172 const int value_width = 16;
173
174 for (i = 1; i <= value_width; i++) {
175
176 if (inw_p(dev->iobase + DACALIBRATION1) & SERIAL_OUT_BIT)
177 value |= 1 << (value_width - i);
178 }
179
180 return value;
181}
182
183
184static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
185 unsigned int num_bits)
186{
187 struct cb_pcidda_private *devpriv = dev->private;
188 int i;
189
190 for (i = 1; i <= num_bits; i++) {
191
192 if (value & (1 << (num_bits - i)))
193 devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
194 else
195 devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
196 outw_p(devpriv->dac_cal1_bits, dev->iobase + DACALIBRATION1);
197 }
198}
199
200
201static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
202 unsigned int address)
203{
204 unsigned int i;
205 unsigned int cal2_bits;
206 unsigned int value;
207
208 const int max_num_caldacs = 4;
209
210 const int read_instruction = 0x6;
211 const int instruction_length = 3;
212 const int address_length = 8;
213
214
215 cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
216
217 for (i = 0; i < max_num_caldacs; i++)
218 cal2_bits |= DESELECT_CALDAC_BIT(i);
219 outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
220
221
222 cb_pcidda_serial_out(dev, read_instruction, instruction_length);
223
224 cb_pcidda_serial_out(dev, address, address_length);
225
226 value = cb_pcidda_serial_in(dev);
227
228
229 cal2_bits &= ~SELECT_EEPROM_BIT;
230 outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
231
232 return value;
233}
234
235
236static void cb_pcidda_write_caldac(struct comedi_device *dev,
237 unsigned int caldac, unsigned int channel,
238 unsigned int value)
239{
240 unsigned int cal2_bits;
241 unsigned int i;
242
243 const int num_channel_bits = 3;
244 const int num_caldac_bits = 8;
245
246 const int max_num_caldacs = 4;
247
248
249 cb_pcidda_serial_out(dev, channel, num_channel_bits);
250
251 cb_pcidda_serial_out(dev, value, num_caldac_bits);
252
253
254
255
256 cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
257
258 for (i = 0; i < max_num_caldacs; i++)
259 cal2_bits |= DESELECT_CALDAC_BIT(i);
260
261 cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
262 outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
263
264 cal2_bits |= DESELECT_CALDAC_BIT(caldac);
265 outw_p(cal2_bits, dev->iobase + DACALIBRATION2);
266}
267
268
269static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
270 unsigned int range)
271{
272 struct cb_pcidda_private *devpriv = dev->private;
273 unsigned int caldac = channel / 2;
274 unsigned int chan = 4 * (channel % 2);
275 unsigned int index = 2 * range + 12 * channel;
276 unsigned int offset;
277 unsigned int gain;
278
279
280 devpriv->ao_range[channel] = range;
281
282
283 offset = devpriv->eeprom_data[0x7 + index];
284 gain = devpriv->eeprom_data[0x8 + index];
285
286
287 cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_OFFSET,
288 (offset >> 8) & 0xff);
289 cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_OFFSET,
290 offset & 0xff);
291 cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_GAIN,
292 (gain >> 8) & 0xff);
293 cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_GAIN,
294 gain & 0xff);
295}
296
297static int cb_pcidda_ao_insn_write(struct comedi_device *dev,
298 struct comedi_subdevice *s,
299 struct comedi_insn *insn,
300 unsigned int *data)
301{
302 struct cb_pcidda_private *devpriv = dev->private;
303 unsigned int channel = CR_CHAN(insn->chanspec);
304 unsigned int range = CR_RANGE(insn->chanspec);
305 unsigned int ctrl;
306
307 if (range != devpriv->ao_range[channel])
308 cb_pcidda_calibrate(dev, channel, range);
309
310 ctrl = CB_DDA_DA_CTRL_EN | CB_DDA_DA_CTRL_DAC(channel);
311
312 switch (range) {
313 case 0:
314 case 3:
315 ctrl |= CB_DDA_DA_CTRL_RANGE10V;
316 break;
317 case 1:
318 case 4:
319 ctrl |= CB_DDA_DA_CTRL_RANGE5V;
320 break;
321 case 2:
322 case 5:
323 ctrl |= CB_DDA_DA_CTRL_RANGE2V5;
324 break;
325 }
326
327 if (range > 2)
328 ctrl |= CB_DDA_DA_CTRL_UNIP;
329
330 outw(ctrl, dev->iobase + CB_DDA_DA_CTRL_REG);
331
332 outw(data[0], dev->iobase + CB_DDA_DA_DATA_REG(channel));
333
334 return insn->n;
335}
336
337static int cb_pcidda_auto_attach(struct comedi_device *dev,
338 unsigned long context)
339{
340 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
341 const struct cb_pcidda_board *thisboard = NULL;
342 struct cb_pcidda_private *devpriv;
343 struct comedi_subdevice *s;
344 unsigned long iobase_8255;
345 int i;
346 int ret;
347
348 if (context < ARRAY_SIZE(cb_pcidda_boards))
349 thisboard = &cb_pcidda_boards[context];
350 if (!thisboard)
351 return -ENODEV;
352 dev->board_ptr = thisboard;
353 dev->board_name = thisboard->name;
354
355 devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
356 if (!devpriv)
357 return -ENOMEM;
358 dev->private = devpriv;
359
360 ret = comedi_pci_enable(dev);
361 if (ret)
362 return ret;
363 dev->iobase = pci_resource_start(pcidev, 3);
364 iobase_8255 = pci_resource_start(pcidev, 2);
365
366 ret = comedi_alloc_subdevices(dev, 3);
367 if (ret)
368 return ret;
369
370 s = &dev->subdevices[0];
371
372 s->type = COMEDI_SUBD_AO;
373 s->subdev_flags = SDF_WRITABLE;
374 s->n_chan = thisboard->ao_chans;
375 s->maxdata = (1 << thisboard->ao_bits) - 1;
376 s->range_table = &cb_pcidda_ranges;
377 s->insn_write = cb_pcidda_ao_insn_write;
378
379
380 for (i = 0; i < 2; i++) {
381 s = &dev->subdevices[1 + i];
382 ret = subdev_8255_init(dev, s, NULL, iobase_8255 + (i * 4));
383 if (ret)
384 return ret;
385 }
386
387
388 for (i = 0; i < EEPROM_SIZE; i++)
389 devpriv->eeprom_data[i] = cb_pcidda_read_eeprom(dev, i);
390
391
392 for (i = 0; i < thisboard->ao_chans; i++)
393 cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]);
394
395 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
396
397 return 0;
398}
399
400static void cb_pcidda_detach(struct comedi_device *dev)
401{
402 comedi_spriv_free(dev, 1);
403 comedi_spriv_free(dev, 2);
404 comedi_pci_disable(dev);
405}
406
407static struct comedi_driver cb_pcidda_driver = {
408 .driver_name = "cb_pcidda",
409 .module = THIS_MODULE,
410 .auto_attach = cb_pcidda_auto_attach,
411 .detach = cb_pcidda_detach,
412};
413
414static int cb_pcidda_pci_probe(struct pci_dev *dev,
415 const struct pci_device_id *id)
416{
417 return comedi_pci_auto_config(dev, &cb_pcidda_driver,
418 id->driver_data);
419}
420
421static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
422 { PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 },
423 { PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 },
424 { PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 },
425 { PCI_VDEVICE(CB, 0x0023), BOARD_DDA02_16 },
426 { PCI_VDEVICE(CB, 0x0024), BOARD_DDA04_16 },
427 { PCI_VDEVICE(CB, 0x0025), BOARD_DDA08_16 },
428 { 0 }
429};
430MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
431
432static struct pci_driver cb_pcidda_pci_driver = {
433 .name = "cb_pcidda",
434 .id_table = cb_pcidda_pci_table,
435 .probe = cb_pcidda_pci_probe,
436 .remove = comedi_pci_auto_unconfig,
437};
438module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
439
440MODULE_AUTHOR("Comedi http://www.comedi.org");
441MODULE_DESCRIPTION("Comedi low-level driver");
442MODULE_LICENSE("GPL");
443