1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * comedi/drivers/cb_pcidas64.c |
4 | * This is a driver for the ComputerBoards/MeasurementComputing PCI-DAS |
5 | * 64xx, 60xx, and 4020 cards. |
6 | * |
7 | * Author: Frank Mori Hess <fmhess@users.sourceforge.net> |
8 | * Copyright (C) 2001, 2002 Frank Mori Hess |
9 | * |
10 | * Thanks also go to the following people: |
11 | * |
12 | * Steve Rosenbluth, for providing the source code for |
13 | * his pci-das6402 driver, and source code for working QNX pci-6402 |
14 | * drivers by Greg Laird and Mariusz Bogacz. None of the code was |
15 | * used directly here, but it was useful as an additional source of |
16 | * documentation on how to program the boards. |
17 | * |
18 | * John Sims, for much testing and feedback on pcidas-4020 support. |
19 | * |
20 | * COMEDI - Linux Control and Measurement Device Interface |
21 | * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> |
22 | */ |
23 | |
24 | /* |
25 | * Driver: cb_pcidas64 |
26 | * Description: MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series |
27 | * with the PLX 9080 PCI controller |
28 | * Author: Frank Mori Hess <fmhess@users.sourceforge.net> |
29 | * Status: works |
30 | * Updated: Fri, 02 Nov 2012 18:58:55 +0000 |
31 | * Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64), |
32 | * PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16, |
33 | * PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR, |
34 | * PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14, |
35 | * PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6013, PCI-DAS6014, |
36 | * PCI-DAS6023, PCI-DAS6025, PCI-DAS6030, |
37 | * PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034, |
38 | * PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052, |
39 | * PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12 |
40 | * |
41 | * Configuration options: |
42 | * None. |
43 | * |
44 | * Manual attachment of PCI cards with the comedi_config utility is not |
45 | * supported by this driver; they are attached automatically. |
46 | * |
47 | * These boards may be autocalibrated with the comedi_calibrate utility. |
48 | * |
49 | * To select the bnc trigger input on the 4020 (instead of the dio input), |
50 | * specify a nonzero channel in the chanspec. If you wish to use an external |
51 | * master clock on the 4020, you may do so by setting the scan_begin_src |
52 | * to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn |
53 | * to configure the divisor to use for the external clock. |
54 | * |
55 | * Some devices are not identified because the PCI device IDs are not yet |
56 | * known. If you have such a board, please let the maintainers know. |
57 | */ |
58 | |
59 | /* |
60 | * TODO: |
61 | * make it return error if user attempts an ai command that uses the |
62 | * external queue, and an ao command simultaneously user counter subdevice |
63 | * there are a number of boards this driver will support when they are |
64 | * fully released, but does not yet since the pci device id numbers |
65 | * are not yet available. |
66 | * |
67 | * support prescaled 100khz clock for slow pacing (not available on 6000 |
68 | * series?) |
69 | * |
70 | * make ao fifo size adjustable like ai fifo |
71 | */ |
72 | |
73 | #include <linux/module.h> |
74 | #include <linux/delay.h> |
75 | #include <linux/interrupt.h> |
76 | #include <linux/comedi/comedi_pci.h> |
77 | #include <linux/comedi/comedi_8255.h> |
78 | |
79 | #include "plx9080.h" |
80 | |
81 | #define TIMER_BASE 25 /* 40MHz master clock */ |
82 | /* |
83 | * 100kHz 'prescaled' clock for slow acquisition, |
84 | * maybe I'll support this someday |
85 | */ |
86 | #define PRESCALED_TIMER_BASE 10000 |
87 | #define DMA_BUFFER_SIZE 0x1000 |
88 | #define DAC_FIFO_SIZE 0x2000 |
89 | |
90 | /* maximum value that can be loaded into board's 24-bit counters */ |
91 | static const int max_counter_value = 0xffffff; |
92 | |
93 | /* PCI-DAS64xxx base addresses */ |
94 | |
95 | /* devpriv->main_iobase registers */ |
96 | enum write_only_registers { |
97 | INTR_ENABLE_REG = 0x0, /* interrupt enable register */ |
98 | HW_CONFIG_REG = 0x2, /* hardware config register */ |
99 | DAQ_SYNC_REG = 0xc, |
100 | DAQ_ATRIG_LOW_4020_REG = 0xc, |
101 | ADC_CONTROL0_REG = 0x10, /* adc control register 0 */ |
102 | ADC_CONTROL1_REG = 0x12, /* adc control register 1 */ |
103 | CALIBRATION_REG = 0x14, |
104 | /* lower 16 bits of adc sample interval counter */ |
105 | ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, |
106 | /* upper 8 bits of adc sample interval counter */ |
107 | ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, |
108 | /* lower 16 bits of delay interval counter */ |
109 | ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, |
110 | /* upper 8 bits of delay interval counter */ |
111 | ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, |
112 | /* lower 16 bits of hardware conversion/scan counter */ |
113 | ADC_COUNT_LOWER_REG = 0x1e, |
114 | /* upper 8 bits of hardware conversion/scan counter */ |
115 | ADC_COUNT_UPPER_REG = 0x20, |
116 | ADC_START_REG = 0x22, /* software trigger to start acquisition */ |
117 | ADC_CONVERT_REG = 0x24, /* initiates single conversion */ |
118 | ADC_QUEUE_CLEAR_REG = 0x26, /* clears adc queue */ |
119 | ADC_QUEUE_LOAD_REG = 0x28, /* loads adc queue */ |
120 | ADC_BUFFER_CLEAR_REG = 0x2a, |
121 | /* high channel for internal queue, use adc_chan_bits() inline above */ |
122 | ADC_QUEUE_HIGH_REG = 0x2c, |
123 | DAC_CONTROL0_REG = 0x50, /* dac control register 0 */ |
124 | DAC_CONTROL1_REG = 0x52, /* dac control register 0 */ |
125 | /* lower 16 bits of dac sample interval counter */ |
126 | DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, |
127 | /* upper 8 bits of dac sample interval counter */ |
128 | DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, |
129 | DAC_SELECT_REG = 0x60, |
130 | DAC_START_REG = 0x64, |
131 | DAC_BUFFER_CLEAR_REG = 0x66, /* clear dac buffer */ |
132 | }; |
133 | |
134 | static inline unsigned int dac_convert_reg(unsigned int channel) |
135 | { |
136 | return 0x70 + (2 * (channel & 0x1)); |
137 | } |
138 | |
139 | static inline unsigned int dac_lsb_4020_reg(unsigned int channel) |
140 | { |
141 | return 0x70 + (4 * (channel & 0x1)); |
142 | } |
143 | |
144 | static inline unsigned int dac_msb_4020_reg(unsigned int channel) |
145 | { |
146 | return 0x72 + (4 * (channel & 0x1)); |
147 | } |
148 | |
149 | enum read_only_registers { |
150 | /* |
151 | * hardware status register, |
152 | * reading this apparently clears pending interrupts as well |
153 | */ |
154 | HW_STATUS_REG = 0x0, |
155 | PIPE1_READ_REG = 0x4, |
156 | ADC_READ_PNTR_REG = 0x8, |
157 | LOWER_XFER_REG = 0x10, |
158 | ADC_WRITE_PNTR_REG = 0xc, |
159 | PREPOST_REG = 0x14, |
160 | }; |
161 | |
162 | enum read_write_registers { |
163 | I8255_4020_REG = 0x48, /* 8255 offset, for 4020 only */ |
164 | /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */ |
165 | ADC_QUEUE_FIFO_REG = 0x100, |
166 | ADC_FIFO_REG = 0x200, /* adc data fifo */ |
167 | /* dac data fifo, has weird interactions with external channel queue */ |
168 | DAC_FIFO_REG = 0x300, |
169 | }; |
170 | |
171 | /* dev->mmio registers */ |
172 | enum dio_counter_registers { |
173 | DIO_8255_OFFSET = 0x0, |
174 | DO_REG = 0x20, |
175 | DI_REG = 0x28, |
176 | DIO_DIRECTION_60XX_REG = 0x40, |
177 | DIO_DATA_60XX_REG = 0x48, |
178 | }; |
179 | |
180 | /* bit definitions for write-only registers */ |
181 | |
182 | enum intr_enable_contents { |
183 | ADC_INTR_SRC_MASK = 0x3, /* adc interrupt source mask */ |
184 | ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quarter full */ |
185 | ADC_INTR_EOC_BITS = 0x1, /* interrupt end of conversion */ |
186 | ADC_INTR_EOSCAN_BITS = 0x2, /* interrupt end of scan */ |
187 | ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence mask */ |
188 | EN_ADC_INTR_SRC_BIT = 0x4, /* enable adc interrupt source */ |
189 | EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done intr */ |
190 | DAC_INTR_SRC_MASK = 0x30, |
191 | DAC_INTR_QEMPTY_BITS = 0x0, |
192 | DAC_INTR_HIGH_CHAN_BITS = 0x10, |
193 | EN_DAC_INTR_SRC_BIT = 0x40, /* enable dac interrupt source */ |
194 | EN_DAC_DONE_INTR_BIT = 0x80, |
195 | EN_ADC_ACTIVE_INTR_BIT = 0x200, /* enable adc active interrupt */ |
196 | EN_ADC_STOP_INTR_BIT = 0x400, /* enable adc stop trigger interrupt */ |
197 | EN_DAC_ACTIVE_INTR_BIT = 0x800, /* enable dac active interrupt */ |
198 | EN_DAC_UNDERRUN_BIT = 0x4000, /* enable dac underrun status bit */ |
199 | EN_ADC_OVERRUN_BIT = 0x8000, /* enable adc overrun status bit */ |
200 | }; |
201 | |
202 | enum hw_config_contents { |
203 | MASTER_CLOCK_4020_MASK = 0x3, /* master clock source mask for 4020 */ |
204 | INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock */ |
205 | BNC_CLOCK_4020_BITS = 0x2, /* use BNC input for master clock */ |
206 | EXT_CLOCK_4020_BITS = 0x3, /* use dio input for master clock */ |
207 | EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue */ |
208 | /* use 225 nanosec strobe when loading dac instead of 50 nanosec */ |
209 | SLOW_DAC_BIT = 0x400, |
210 | /* |
211 | * bit with unknown function yet given as default value in pci-das64 |
212 | * manual |
213 | */ |
214 | HW_CONFIG_DUMMY_BITS = 0x2000, |
215 | /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */ |
216 | DMA_CH_SELECT_BIT = 0x8000, |
217 | FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */ |
218 | DAC_FIFO_SIZE_MASK = 0xff00, /* bits that set dac fifo size */ |
219 | DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */ |
220 | }; |
221 | |
222 | enum daq_atrig_low_4020_contents { |
223 | /* use trig/ext clk bnc input for analog gate signal */ |
224 | EXT_AGATE_BNC_BIT = 0x8000, |
225 | /* use trig/ext clk bnc input for external stop trigger signal */ |
226 | EXT_STOP_TRIG_BNC_BIT = 0x4000, |
227 | /* use trig/ext clk bnc input for external start trigger signal */ |
228 | EXT_START_TRIG_BNC_BIT = 0x2000, |
229 | }; |
230 | |
231 | enum adc_control0_contents { |
232 | ADC_GATE_SRC_MASK = 0x3, /* bits that select gate */ |
233 | ADC_SOFT_GATE_BITS = 0x1, /* software gate */ |
234 | ADC_EXT_GATE_BITS = 0x2, /* external digital gate */ |
235 | ADC_ANALOG_GATE_BITS = 0x3, /* analog level gate */ |
236 | /* level-sensitive gate (for digital) */ |
237 | ADC_GATE_LEVEL_BIT = 0x4, |
238 | ADC_GATE_POLARITY_BIT = 0x8, /* gate active low */ |
239 | ADC_START_TRIG_SOFT_BITS = 0x10, |
240 | ADC_START_TRIG_EXT_BITS = 0x20, |
241 | ADC_START_TRIG_ANALOG_BITS = 0x30, |
242 | ADC_START_TRIG_MASK = 0x30, |
243 | ADC_START_TRIG_FALLING_BIT = 0x40, /* trig 1 uses falling edge */ |
244 | /* external pacing uses falling edge */ |
245 | ADC_EXT_CONV_FALLING_BIT = 0x800, |
246 | /* enable hardware scan counter */ |
247 | ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, |
248 | ADC_DMA_DISABLE_BIT = 0x4000, /* disables dma */ |
249 | ADC_ENABLE_BIT = 0x8000, /* master adc enable */ |
250 | }; |
251 | |
252 | enum adc_control1_contents { |
253 | /* should be set for boards with > 16 channels */ |
254 | ADC_QUEUE_CONFIG_BIT = 0x1, |
255 | CONVERT_POLARITY_BIT = 0x10, |
256 | EOC_POLARITY_BIT = 0x20, |
257 | ADC_SW_GATE_BIT = 0x40, /* software gate of adc */ |
258 | ADC_DITHER_BIT = 0x200, /* turn on extra noise for dithering */ |
259 | RETRIGGER_BIT = 0x800, |
260 | ADC_LO_CHANNEL_4020_MASK = 0x300, |
261 | ADC_HI_CHANNEL_4020_MASK = 0xc00, |
262 | TWO_CHANNEL_4020_BITS = 0x1000, /* two channel mode for 4020 */ |
263 | FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */ |
264 | CHANNEL_MODE_4020_MASK = 0x3000, |
265 | ADC_MODE_MASK = 0xf000, |
266 | }; |
267 | |
268 | static inline u16 adc_lo_chan_4020_bits(unsigned int channel) |
269 | { |
270 | return (channel & 0x3) << 8; |
271 | }; |
272 | |
273 | static inline u16 adc_hi_chan_4020_bits(unsigned int channel) |
274 | { |
275 | return (channel & 0x3) << 10; |
276 | }; |
277 | |
278 | static inline u16 adc_mode_bits(unsigned int mode) |
279 | { |
280 | return (mode & 0xf) << 12; |
281 | }; |
282 | |
283 | enum calibration_contents { |
284 | SELECT_8800_BIT = 0x1, |
285 | SELECT_8402_64XX_BIT = 0x2, |
286 | SELECT_1590_60XX_BIT = 0x2, |
287 | CAL_EN_64XX_BIT = 0x40, /* calibration enable for 64xx series */ |
288 | SERIAL_DATA_IN_BIT = 0x80, |
289 | SERIAL_CLOCK_BIT = 0x100, |
290 | CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */ |
291 | CAL_GAIN_BIT = 0x800, |
292 | }; |
293 | |
294 | /* |
295 | * calibration sources for 6025 are: |
296 | * 0 : ground |
297 | * 1 : 10V |
298 | * 2 : 5V |
299 | * 3 : 0.5V |
300 | * 4 : 0.05V |
301 | * 5 : ground |
302 | * 6 : dac channel 0 |
303 | * 7 : dac channel 1 |
304 | */ |
305 | |
306 | static inline u16 adc_src_bits(unsigned int source) |
307 | { |
308 | return (source & 0xf) << 3; |
309 | }; |
310 | |
311 | static inline u16 adc_convert_chan_4020_bits(unsigned int channel) |
312 | { |
313 | return (channel & 0x3) << 8; |
314 | }; |
315 | |
316 | enum adc_queue_load_contents { |
317 | UNIP_BIT = 0x800, /* unipolar/bipolar bit */ |
318 | ADC_SE_DIFF_BIT = 0x1000, /* single-ended/ differential bit */ |
319 | /* non-referenced single-ended (common-mode input) */ |
320 | ADC_COMMON_BIT = 0x2000, |
321 | QUEUE_EOSEQ_BIT = 0x4000, /* queue end of sequence */ |
322 | QUEUE_EOSCAN_BIT = 0x8000, /* queue end of scan */ |
323 | }; |
324 | |
325 | static inline u16 adc_chan_bits(unsigned int channel) |
326 | { |
327 | return channel & 0x3f; |
328 | }; |
329 | |
330 | enum dac_control0_contents { |
331 | DAC_ENABLE_BIT = 0x8000, /* dac controller enable bit */ |
332 | DAC_CYCLIC_STOP_BIT = 0x4000, |
333 | DAC_WAVEFORM_MODE_BIT = 0x100, |
334 | DAC_EXT_UPDATE_FALLING_BIT = 0x80, |
335 | DAC_EXT_UPDATE_ENABLE_BIT = 0x40, |
336 | WAVEFORM_TRIG_MASK = 0x30, |
337 | WAVEFORM_TRIG_DISABLED_BITS = 0x0, |
338 | WAVEFORM_TRIG_SOFT_BITS = 0x10, |
339 | WAVEFORM_TRIG_EXT_BITS = 0x20, |
340 | WAVEFORM_TRIG_ADC1_BITS = 0x30, |
341 | WAVEFORM_TRIG_FALLING_BIT = 0x8, |
342 | WAVEFORM_GATE_LEVEL_BIT = 0x4, |
343 | WAVEFORM_GATE_ENABLE_BIT = 0x2, |
344 | WAVEFORM_GATE_SELECT_BIT = 0x1, |
345 | }; |
346 | |
347 | enum dac_control1_contents { |
348 | DAC_WRITE_POLARITY_BIT = 0x800, /* board-dependent setting */ |
349 | DAC1_EXT_REF_BIT = 0x200, |
350 | DAC0_EXT_REF_BIT = 0x100, |
351 | DAC_OUTPUT_ENABLE_BIT = 0x80, /* dac output enable bit */ |
352 | DAC_UPDATE_POLARITY_BIT = 0x40, /* board-dependent setting */ |
353 | DAC_SW_GATE_BIT = 0x20, |
354 | DAC1_UNIPOLAR_BIT = 0x8, |
355 | DAC0_UNIPOLAR_BIT = 0x2, |
356 | }; |
357 | |
358 | /* bit definitions for read-only registers */ |
359 | enum hw_status_contents { |
360 | DAC_UNDERRUN_BIT = 0x1, |
361 | ADC_OVERRUN_BIT = 0x2, |
362 | DAC_ACTIVE_BIT = 0x4, |
363 | ADC_ACTIVE_BIT = 0x8, |
364 | DAC_INTR_PENDING_BIT = 0x10, |
365 | ADC_INTR_PENDING_BIT = 0x20, |
366 | DAC_DONE_BIT = 0x40, |
367 | ADC_DONE_BIT = 0x80, |
368 | EXT_INTR_PENDING_BIT = 0x100, |
369 | ADC_STOP_BIT = 0x200, |
370 | }; |
371 | |
372 | static inline u16 pipe_full_bits(u16 hw_status_bits) |
373 | { |
374 | return (hw_status_bits >> 10) & 0x3; |
375 | }; |
376 | |
377 | static inline unsigned int dma_chain_flag_bits(u16 prepost_bits) |
378 | { |
379 | return (prepost_bits >> 6) & 0x3; |
380 | } |
381 | |
382 | static inline unsigned int adc_upper_read_ptr_code(u16 prepost_bits) |
383 | { |
384 | return (prepost_bits >> 12) & 0x3; |
385 | } |
386 | |
387 | static inline unsigned int adc_upper_write_ptr_code(u16 prepost_bits) |
388 | { |
389 | return (prepost_bits >> 14) & 0x3; |
390 | } |
391 | |
392 | /* I2C addresses for 4020 */ |
393 | enum i2c_addresses { |
394 | RANGE_CAL_I2C_ADDR = 0x20, |
395 | CALDAC0_I2C_ADDR = 0xc, |
396 | CALDAC1_I2C_ADDR = 0xd, |
397 | }; |
398 | |
399 | enum range_cal_i2c_contents { |
400 | /* bits that set what source the adc converter measures */ |
401 | ADC_SRC_4020_MASK = 0x70, |
402 | /* make bnc trig/ext clock threshold 0V instead of 2.5V */ |
403 | BNC_TRIG_THRESHOLD_0V_BIT = 0x80, |
404 | }; |
405 | |
406 | static inline u8 adc_src_4020_bits(unsigned int source) |
407 | { |
408 | return (source << 4) & ADC_SRC_4020_MASK; |
409 | }; |
410 | |
411 | static inline u8 attenuate_bit(unsigned int channel) |
412 | { |
413 | /* attenuate channel (+-5V input range) */ |
414 | return 1 << (channel & 0x3); |
415 | }; |
416 | |
417 | /* analog input ranges for 64xx boards */ |
418 | static const struct comedi_lrange ai_ranges_64xx = { |
419 | 8, { |
420 | BIP_RANGE(10), |
421 | BIP_RANGE(5), |
422 | BIP_RANGE(2.5), |
423 | BIP_RANGE(1.25), |
424 | UNI_RANGE(10), |
425 | UNI_RANGE(5), |
426 | UNI_RANGE(2.5), |
427 | UNI_RANGE(1.25) |
428 | } |
429 | }; |
430 | |
431 | static const u8 ai_range_code_64xx[8] = { |
432 | 0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */ |
433 | 0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */ |
434 | }; |
435 | |
436 | /* analog input ranges for 64-Mx boards */ |
437 | static const struct comedi_lrange ai_ranges_64_mx = { |
438 | 7, { |
439 | BIP_RANGE(5), |
440 | BIP_RANGE(2.5), |
441 | BIP_RANGE(1.25), |
442 | BIP_RANGE(0.625), |
443 | UNI_RANGE(5), |
444 | UNI_RANGE(2.5), |
445 | UNI_RANGE(1.25) |
446 | } |
447 | }; |
448 | |
449 | static const u8 ai_range_code_64_mx[7] = { |
450 | 0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */ |
451 | 0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */ |
452 | }; |
453 | |
454 | /* analog input ranges for 60xx boards */ |
455 | static const struct comedi_lrange ai_ranges_60xx = { |
456 | 4, { |
457 | BIP_RANGE(10), |
458 | BIP_RANGE(5), |
459 | BIP_RANGE(0.5), |
460 | BIP_RANGE(0.05) |
461 | } |
462 | }; |
463 | |
464 | static const u8 ai_range_code_60xx[4] = { |
465 | 0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */ |
466 | }; |
467 | |
468 | /* analog input ranges for 6030, etc boards */ |
469 | static const struct comedi_lrange ai_ranges_6030 = { |
470 | 14, { |
471 | BIP_RANGE(10), |
472 | BIP_RANGE(5), |
473 | BIP_RANGE(2), |
474 | BIP_RANGE(1), |
475 | BIP_RANGE(0.5), |
476 | BIP_RANGE(0.2), |
477 | BIP_RANGE(0.1), |
478 | UNI_RANGE(10), |
479 | UNI_RANGE(5), |
480 | UNI_RANGE(2), |
481 | UNI_RANGE(1), |
482 | UNI_RANGE(0.5), |
483 | UNI_RANGE(0.2), |
484 | UNI_RANGE(0.1) |
485 | } |
486 | }; |
487 | |
488 | static const u8 ai_range_code_6030[14] = { |
489 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */ |
490 | 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */ |
491 | }; |
492 | |
493 | /* analog input ranges for 6052, etc boards */ |
494 | static const struct comedi_lrange ai_ranges_6052 = { |
495 | 15, { |
496 | BIP_RANGE(10), |
497 | BIP_RANGE(5), |
498 | BIP_RANGE(2.5), |
499 | BIP_RANGE(1), |
500 | BIP_RANGE(0.5), |
501 | BIP_RANGE(0.25), |
502 | BIP_RANGE(0.1), |
503 | BIP_RANGE(0.05), |
504 | UNI_RANGE(10), |
505 | UNI_RANGE(5), |
506 | UNI_RANGE(2), |
507 | UNI_RANGE(1), |
508 | UNI_RANGE(0.5), |
509 | UNI_RANGE(0.2), |
510 | UNI_RANGE(0.1) |
511 | } |
512 | }; |
513 | |
514 | static const u8 ai_range_code_6052[15] = { |
515 | 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */ |
516 | 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */ |
517 | }; |
518 | |
519 | /* analog input ranges for 4020 board */ |
520 | static const struct comedi_lrange ai_ranges_4020 = { |
521 | 2, { |
522 | BIP_RANGE(5), |
523 | BIP_RANGE(1) |
524 | } |
525 | }; |
526 | |
527 | /* analog output ranges */ |
528 | static const struct comedi_lrange ao_ranges_64xx = { |
529 | 4, { |
530 | BIP_RANGE(5), |
531 | BIP_RANGE(10), |
532 | UNI_RANGE(5), |
533 | UNI_RANGE(10) |
534 | } |
535 | }; |
536 | |
537 | static const int ao_range_code_64xx[] = { |
538 | 0x0, |
539 | 0x1, |
540 | 0x2, |
541 | 0x3, |
542 | }; |
543 | |
544 | static const int ao_range_code_60xx[] = { |
545 | 0x0, |
546 | }; |
547 | |
548 | static const struct comedi_lrange ao_ranges_6030 = { |
549 | 2, { |
550 | BIP_RANGE(10), |
551 | UNI_RANGE(10) |
552 | } |
553 | }; |
554 | |
555 | static const int ao_range_code_6030[] = { |
556 | 0x0, |
557 | 0x2, |
558 | }; |
559 | |
560 | static const struct comedi_lrange ao_ranges_4020 = { |
561 | 2, { |
562 | BIP_RANGE(5), |
563 | BIP_RANGE(10) |
564 | } |
565 | }; |
566 | |
567 | static const int ao_range_code_4020[] = { |
568 | 0x1, |
569 | 0x0, |
570 | }; |
571 | |
572 | enum register_layout { |
573 | LAYOUT_60XX, |
574 | LAYOUT_64XX, |
575 | LAYOUT_4020, |
576 | }; |
577 | |
578 | struct hw_fifo_info { |
579 | unsigned int num_segments; |
580 | unsigned int max_segment_length; |
581 | unsigned int sample_packing_ratio; |
582 | u16 fifo_size_reg_mask; |
583 | }; |
584 | |
585 | enum pcidas64_boardid { |
586 | BOARD_PCIDAS6402_16, |
587 | BOARD_PCIDAS6402_12, |
588 | BOARD_PCIDAS64_M1_16, |
589 | BOARD_PCIDAS64_M2_16, |
590 | BOARD_PCIDAS64_M3_16, |
591 | BOARD_PCIDAS6013, |
592 | BOARD_PCIDAS6014, |
593 | BOARD_PCIDAS6023, |
594 | BOARD_PCIDAS6025, |
595 | BOARD_PCIDAS6030, |
596 | BOARD_PCIDAS6031, |
597 | BOARD_PCIDAS6032, |
598 | BOARD_PCIDAS6033, |
599 | BOARD_PCIDAS6034, |
600 | BOARD_PCIDAS6035, |
601 | BOARD_PCIDAS6036, |
602 | BOARD_PCIDAS6040, |
603 | BOARD_PCIDAS6052, |
604 | BOARD_PCIDAS6070, |
605 | BOARD_PCIDAS6071, |
606 | BOARD_PCIDAS4020_12, |
607 | BOARD_PCIDAS6402_16_JR, |
608 | BOARD_PCIDAS64_M1_16_JR, |
609 | BOARD_PCIDAS64_M2_16_JR, |
610 | BOARD_PCIDAS64_M3_16_JR, |
611 | BOARD_PCIDAS64_M1_14, |
612 | BOARD_PCIDAS64_M2_14, |
613 | BOARD_PCIDAS64_M3_14, |
614 | }; |
615 | |
616 | struct pcidas64_board { |
617 | const char *name; |
618 | int ai_se_chans; /* number of ai inputs in single-ended mode */ |
619 | int ai_bits; /* analog input resolution */ |
620 | int ai_speed; /* fastest conversion period in ns */ |
621 | const struct comedi_lrange *ai_range_table; |
622 | const u8 *ai_range_code; |
623 | int ao_nchan; /* number of analog out channels */ |
624 | int ao_bits; /* analog output resolution */ |
625 | int ao_scan_speed; /* analog output scan speed */ |
626 | const struct comedi_lrange *ao_range_table; |
627 | const int *ao_range_code; |
628 | const struct hw_fifo_info *const ai_fifo; |
629 | /* different board families have slightly different registers */ |
630 | enum register_layout layout; |
631 | unsigned has_8255:1; |
632 | }; |
633 | |
634 | static const struct hw_fifo_info ai_fifo_4020 = { |
635 | .num_segments = 2, |
636 | .max_segment_length = 0x8000, |
637 | .sample_packing_ratio = 2, |
638 | .fifo_size_reg_mask = 0x7f, |
639 | }; |
640 | |
641 | static const struct hw_fifo_info ai_fifo_64xx = { |
642 | .num_segments = 4, |
643 | .max_segment_length = 0x800, |
644 | .sample_packing_ratio = 1, |
645 | .fifo_size_reg_mask = 0x3f, |
646 | }; |
647 | |
648 | static const struct hw_fifo_info ai_fifo_60xx = { |
649 | .num_segments = 4, |
650 | .max_segment_length = 0x800, |
651 | .sample_packing_ratio = 1, |
652 | .fifo_size_reg_mask = 0x7f, |
653 | }; |
654 | |
655 | /* |
656 | * maximum number of dma transfers we will chain together into a ring |
657 | * (and the maximum number of dma buffers we maintain) |
658 | */ |
659 | #define MAX_AI_DMA_RING_COUNT (0x80000 / DMA_BUFFER_SIZE) |
660 | #define MIN_AI_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) |
661 | #define AO_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) |
662 | static inline unsigned int ai_dma_ring_count(const struct pcidas64_board *board) |
663 | { |
664 | if (board->layout == LAYOUT_4020) |
665 | return MAX_AI_DMA_RING_COUNT; |
666 | |
667 | return MIN_AI_DMA_RING_COUNT; |
668 | } |
669 | |
670 | static const int bytes_in_sample = 2; |
671 | |
672 | static const struct pcidas64_board pcidas64_boards[] = { |
673 | [BOARD_PCIDAS6402_16] = { |
674 | .name = "pci-das6402/16" , |
675 | .ai_se_chans = 64, |
676 | .ai_bits = 16, |
677 | .ai_speed = 5000, |
678 | .ao_nchan = 2, |
679 | .ao_bits = 16, |
680 | .ao_scan_speed = 10000, |
681 | .layout = LAYOUT_64XX, |
682 | .ai_range_table = &ai_ranges_64xx, |
683 | .ai_range_code = ai_range_code_64xx, |
684 | .ao_range_table = &ao_ranges_64xx, |
685 | .ao_range_code = ao_range_code_64xx, |
686 | .ai_fifo = &ai_fifo_64xx, |
687 | .has_8255 = 1, |
688 | }, |
689 | [BOARD_PCIDAS6402_12] = { |
690 | .name = "pci-das6402/12" , /* XXX check */ |
691 | .ai_se_chans = 64, |
692 | .ai_bits = 12, |
693 | .ai_speed = 5000, |
694 | .ao_nchan = 2, |
695 | .ao_bits = 12, |
696 | .ao_scan_speed = 10000, |
697 | .layout = LAYOUT_64XX, |
698 | .ai_range_table = &ai_ranges_64xx, |
699 | .ai_range_code = ai_range_code_64xx, |
700 | .ao_range_table = &ao_ranges_64xx, |
701 | .ao_range_code = ao_range_code_64xx, |
702 | .ai_fifo = &ai_fifo_64xx, |
703 | .has_8255 = 1, |
704 | }, |
705 | [BOARD_PCIDAS64_M1_16] = { |
706 | .name = "pci-das64/m1/16" , |
707 | .ai_se_chans = 64, |
708 | .ai_bits = 16, |
709 | .ai_speed = 1000, |
710 | .ao_nchan = 2, |
711 | .ao_bits = 16, |
712 | .ao_scan_speed = 10000, |
713 | .layout = LAYOUT_64XX, |
714 | .ai_range_table = &ai_ranges_64_mx, |
715 | .ai_range_code = ai_range_code_64_mx, |
716 | .ao_range_table = &ao_ranges_64xx, |
717 | .ao_range_code = ao_range_code_64xx, |
718 | .ai_fifo = &ai_fifo_64xx, |
719 | .has_8255 = 1, |
720 | }, |
721 | [BOARD_PCIDAS64_M2_16] = { |
722 | .name = "pci-das64/m2/16" , |
723 | .ai_se_chans = 64, |
724 | .ai_bits = 16, |
725 | .ai_speed = 500, |
726 | .ao_nchan = 2, |
727 | .ao_bits = 16, |
728 | .ao_scan_speed = 10000, |
729 | .layout = LAYOUT_64XX, |
730 | .ai_range_table = &ai_ranges_64_mx, |
731 | .ai_range_code = ai_range_code_64_mx, |
732 | .ao_range_table = &ao_ranges_64xx, |
733 | .ao_range_code = ao_range_code_64xx, |
734 | .ai_fifo = &ai_fifo_64xx, |
735 | .has_8255 = 1, |
736 | }, |
737 | [BOARD_PCIDAS64_M3_16] = { |
738 | .name = "pci-das64/m3/16" , |
739 | .ai_se_chans = 64, |
740 | .ai_bits = 16, |
741 | .ai_speed = 333, |
742 | .ao_nchan = 2, |
743 | .ao_bits = 16, |
744 | .ao_scan_speed = 10000, |
745 | .layout = LAYOUT_64XX, |
746 | .ai_range_table = &ai_ranges_64_mx, |
747 | .ai_range_code = ai_range_code_64_mx, |
748 | .ao_range_table = &ao_ranges_64xx, |
749 | .ao_range_code = ao_range_code_64xx, |
750 | .ai_fifo = &ai_fifo_64xx, |
751 | .has_8255 = 1, |
752 | }, |
753 | [BOARD_PCIDAS6013] = { |
754 | .name = "pci-das6013" , |
755 | .ai_se_chans = 16, |
756 | .ai_bits = 16, |
757 | .ai_speed = 5000, |
758 | .ao_nchan = 0, |
759 | .ao_bits = 16, |
760 | .layout = LAYOUT_60XX, |
761 | .ai_range_table = &ai_ranges_60xx, |
762 | .ai_range_code = ai_range_code_60xx, |
763 | .ao_range_table = &range_bipolar10, |
764 | .ao_range_code = ao_range_code_60xx, |
765 | .ai_fifo = &ai_fifo_60xx, |
766 | .has_8255 = 0, |
767 | }, |
768 | [BOARD_PCIDAS6014] = { |
769 | .name = "pci-das6014" , |
770 | .ai_se_chans = 16, |
771 | .ai_bits = 16, |
772 | .ai_speed = 5000, |
773 | .ao_nchan = 2, |
774 | .ao_bits = 16, |
775 | .ao_scan_speed = 100000, |
776 | .layout = LAYOUT_60XX, |
777 | .ai_range_table = &ai_ranges_60xx, |
778 | .ai_range_code = ai_range_code_60xx, |
779 | .ao_range_table = &range_bipolar10, |
780 | .ao_range_code = ao_range_code_60xx, |
781 | .ai_fifo = &ai_fifo_60xx, |
782 | .has_8255 = 0, |
783 | }, |
784 | [BOARD_PCIDAS6023] = { |
785 | .name = "pci-das6023" , |
786 | .ai_se_chans = 16, |
787 | .ai_bits = 12, |
788 | .ai_speed = 5000, |
789 | .ao_nchan = 0, |
790 | .ao_scan_speed = 100000, |
791 | .layout = LAYOUT_60XX, |
792 | .ai_range_table = &ai_ranges_60xx, |
793 | .ai_range_code = ai_range_code_60xx, |
794 | .ao_range_table = &range_bipolar10, |
795 | .ao_range_code = ao_range_code_60xx, |
796 | .ai_fifo = &ai_fifo_60xx, |
797 | .has_8255 = 1, |
798 | }, |
799 | [BOARD_PCIDAS6025] = { |
800 | .name = "pci-das6025" , |
801 | .ai_se_chans = 16, |
802 | .ai_bits = 12, |
803 | .ai_speed = 5000, |
804 | .ao_nchan = 2, |
805 | .ao_bits = 12, |
806 | .ao_scan_speed = 100000, |
807 | .layout = LAYOUT_60XX, |
808 | .ai_range_table = &ai_ranges_60xx, |
809 | .ai_range_code = ai_range_code_60xx, |
810 | .ao_range_table = &range_bipolar10, |
811 | .ao_range_code = ao_range_code_60xx, |
812 | .ai_fifo = &ai_fifo_60xx, |
813 | .has_8255 = 1, |
814 | }, |
815 | [BOARD_PCIDAS6030] = { |
816 | .name = "pci-das6030" , |
817 | .ai_se_chans = 16, |
818 | .ai_bits = 16, |
819 | .ai_speed = 10000, |
820 | .ao_nchan = 2, |
821 | .ao_bits = 16, |
822 | .ao_scan_speed = 10000, |
823 | .layout = LAYOUT_60XX, |
824 | .ai_range_table = &ai_ranges_6030, |
825 | .ai_range_code = ai_range_code_6030, |
826 | .ao_range_table = &ao_ranges_6030, |
827 | .ao_range_code = ao_range_code_6030, |
828 | .ai_fifo = &ai_fifo_60xx, |
829 | .has_8255 = 0, |
830 | }, |
831 | [BOARD_PCIDAS6031] = { |
832 | .name = "pci-das6031" , |
833 | .ai_se_chans = 64, |
834 | .ai_bits = 16, |
835 | .ai_speed = 10000, |
836 | .ao_nchan = 2, |
837 | .ao_bits = 16, |
838 | .ao_scan_speed = 10000, |
839 | .layout = LAYOUT_60XX, |
840 | .ai_range_table = &ai_ranges_6030, |
841 | .ai_range_code = ai_range_code_6030, |
842 | .ao_range_table = &ao_ranges_6030, |
843 | .ao_range_code = ao_range_code_6030, |
844 | .ai_fifo = &ai_fifo_60xx, |
845 | .has_8255 = 0, |
846 | }, |
847 | [BOARD_PCIDAS6032] = { |
848 | .name = "pci-das6032" , |
849 | .ai_se_chans = 16, |
850 | .ai_bits = 16, |
851 | .ai_speed = 10000, |
852 | .ao_nchan = 0, |
853 | .layout = LAYOUT_60XX, |
854 | .ai_range_table = &ai_ranges_6030, |
855 | .ai_range_code = ai_range_code_6030, |
856 | .ai_fifo = &ai_fifo_60xx, |
857 | .has_8255 = 0, |
858 | }, |
859 | [BOARD_PCIDAS6033] = { |
860 | .name = "pci-das6033" , |
861 | .ai_se_chans = 64, |
862 | .ai_bits = 16, |
863 | .ai_speed = 10000, |
864 | .ao_nchan = 0, |
865 | .layout = LAYOUT_60XX, |
866 | .ai_range_table = &ai_ranges_6030, |
867 | .ai_range_code = ai_range_code_6030, |
868 | .ai_fifo = &ai_fifo_60xx, |
869 | .has_8255 = 0, |
870 | }, |
871 | [BOARD_PCIDAS6034] = { |
872 | .name = "pci-das6034" , |
873 | .ai_se_chans = 16, |
874 | .ai_bits = 16, |
875 | .ai_speed = 5000, |
876 | .ao_nchan = 0, |
877 | .ao_scan_speed = 0, |
878 | .layout = LAYOUT_60XX, |
879 | .ai_range_table = &ai_ranges_60xx, |
880 | .ai_range_code = ai_range_code_60xx, |
881 | .ai_fifo = &ai_fifo_60xx, |
882 | .has_8255 = 0, |
883 | }, |
884 | [BOARD_PCIDAS6035] = { |
885 | .name = "pci-das6035" , |
886 | .ai_se_chans = 16, |
887 | .ai_bits = 16, |
888 | .ai_speed = 5000, |
889 | .ao_nchan = 2, |
890 | .ao_bits = 12, |
891 | .ao_scan_speed = 100000, |
892 | .layout = LAYOUT_60XX, |
893 | .ai_range_table = &ai_ranges_60xx, |
894 | .ai_range_code = ai_range_code_60xx, |
895 | .ao_range_table = &range_bipolar10, |
896 | .ao_range_code = ao_range_code_60xx, |
897 | .ai_fifo = &ai_fifo_60xx, |
898 | .has_8255 = 0, |
899 | }, |
900 | [BOARD_PCIDAS6036] = { |
901 | .name = "pci-das6036" , |
902 | .ai_se_chans = 16, |
903 | .ai_bits = 16, |
904 | .ai_speed = 5000, |
905 | .ao_nchan = 2, |
906 | .ao_bits = 16, |
907 | .ao_scan_speed = 100000, |
908 | .layout = LAYOUT_60XX, |
909 | .ai_range_table = &ai_ranges_60xx, |
910 | .ai_range_code = ai_range_code_60xx, |
911 | .ao_range_table = &range_bipolar10, |
912 | .ao_range_code = ao_range_code_60xx, |
913 | .ai_fifo = &ai_fifo_60xx, |
914 | .has_8255 = 0, |
915 | }, |
916 | [BOARD_PCIDAS6040] = { |
917 | .name = "pci-das6040" , |
918 | .ai_se_chans = 16, |
919 | .ai_bits = 12, |
920 | .ai_speed = 2000, |
921 | .ao_nchan = 2, |
922 | .ao_bits = 12, |
923 | .ao_scan_speed = 1000, |
924 | .layout = LAYOUT_60XX, |
925 | .ai_range_table = &ai_ranges_6052, |
926 | .ai_range_code = ai_range_code_6052, |
927 | .ao_range_table = &ao_ranges_6030, |
928 | .ao_range_code = ao_range_code_6030, |
929 | .ai_fifo = &ai_fifo_60xx, |
930 | .has_8255 = 0, |
931 | }, |
932 | [BOARD_PCIDAS6052] = { |
933 | .name = "pci-das6052" , |
934 | .ai_se_chans = 16, |
935 | .ai_bits = 16, |
936 | .ai_speed = 3333, |
937 | .ao_nchan = 2, |
938 | .ao_bits = 16, |
939 | .ao_scan_speed = 3333, |
940 | .layout = LAYOUT_60XX, |
941 | .ai_range_table = &ai_ranges_6052, |
942 | .ai_range_code = ai_range_code_6052, |
943 | .ao_range_table = &ao_ranges_6030, |
944 | .ao_range_code = ao_range_code_6030, |
945 | .ai_fifo = &ai_fifo_60xx, |
946 | .has_8255 = 0, |
947 | }, |
948 | [BOARD_PCIDAS6070] = { |
949 | .name = "pci-das6070" , |
950 | .ai_se_chans = 16, |
951 | .ai_bits = 12, |
952 | .ai_speed = 800, |
953 | .ao_nchan = 2, |
954 | .ao_bits = 12, |
955 | .ao_scan_speed = 1000, |
956 | .layout = LAYOUT_60XX, |
957 | .ai_range_table = &ai_ranges_6052, |
958 | .ai_range_code = ai_range_code_6052, |
959 | .ao_range_table = &ao_ranges_6030, |
960 | .ao_range_code = ao_range_code_6030, |
961 | .ai_fifo = &ai_fifo_60xx, |
962 | .has_8255 = 0, |
963 | }, |
964 | [BOARD_PCIDAS6071] = { |
965 | .name = "pci-das6071" , |
966 | .ai_se_chans = 64, |
967 | .ai_bits = 12, |
968 | .ai_speed = 800, |
969 | .ao_nchan = 2, |
970 | .ao_bits = 12, |
971 | .ao_scan_speed = 1000, |
972 | .layout = LAYOUT_60XX, |
973 | .ai_range_table = &ai_ranges_6052, |
974 | .ai_range_code = ai_range_code_6052, |
975 | .ao_range_table = &ao_ranges_6030, |
976 | .ao_range_code = ao_range_code_6030, |
977 | .ai_fifo = &ai_fifo_60xx, |
978 | .has_8255 = 0, |
979 | }, |
980 | [BOARD_PCIDAS4020_12] = { |
981 | .name = "pci-das4020/12" , |
982 | .ai_se_chans = 4, |
983 | .ai_bits = 12, |
984 | .ai_speed = 50, |
985 | .ao_bits = 12, |
986 | .ao_nchan = 2, |
987 | .ao_scan_speed = 0, /* no hardware pacing on ao */ |
988 | .layout = LAYOUT_4020, |
989 | .ai_range_table = &ai_ranges_4020, |
990 | .ao_range_table = &ao_ranges_4020, |
991 | .ao_range_code = ao_range_code_4020, |
992 | .ai_fifo = &ai_fifo_4020, |
993 | .has_8255 = 1, |
994 | }, |
995 | #if 0 |
996 | /* The device id for these boards is unknown */ |
997 | |
998 | [BOARD_PCIDAS6402_16_JR] = { |
999 | .name = "pci-das6402/16/jr" , |
1000 | .ai_se_chans = 64, |
1001 | .ai_bits = 16, |
1002 | .ai_speed = 5000, |
1003 | .ao_nchan = 0, |
1004 | .ao_scan_speed = 10000, |
1005 | .layout = LAYOUT_64XX, |
1006 | .ai_range_table = &ai_ranges_64xx, |
1007 | .ai_range_code = ai_range_code_64xx, |
1008 | .ai_fifo = ai_fifo_64xx, |
1009 | .has_8255 = 1, |
1010 | }, |
1011 | [BOARD_PCIDAS64_M1_16_JR] = { |
1012 | .name = "pci-das64/m1/16/jr" , |
1013 | .ai_se_chans = 64, |
1014 | .ai_bits = 16, |
1015 | .ai_speed = 1000, |
1016 | .ao_nchan = 0, |
1017 | .ao_scan_speed = 10000, |
1018 | .layout = LAYOUT_64XX, |
1019 | .ai_range_table = &ai_ranges_64_mx, |
1020 | .ai_range_code = ai_range_code_64_mx, |
1021 | .ai_fifo = ai_fifo_64xx, |
1022 | .has_8255 = 1, |
1023 | }, |
1024 | [BOARD_PCIDAS64_M2_16_JR] = { |
1025 | .name = "pci-das64/m2/16/jr" , |
1026 | .ai_se_chans = 64, |
1027 | .ai_bits = 16, |
1028 | .ai_speed = 500, |
1029 | .ao_nchan = 0, |
1030 | .ao_scan_speed = 10000, |
1031 | .layout = LAYOUT_64XX, |
1032 | .ai_range_table = &ai_ranges_64_mx, |
1033 | .ai_range_code = ai_range_code_64_mx, |
1034 | .ai_fifo = ai_fifo_64xx, |
1035 | .has_8255 = 1, |
1036 | }, |
1037 | [BOARD_PCIDAS64_M3_16_JR] = { |
1038 | .name = "pci-das64/m3/16/jr" , |
1039 | .ai_se_chans = 64, |
1040 | .ai_bits = 16, |
1041 | .ai_speed = 333, |
1042 | .ao_nchan = 0, |
1043 | .ao_scan_speed = 10000, |
1044 | .layout = LAYOUT_64XX, |
1045 | .ai_range_table = &ai_ranges_64_mx, |
1046 | .ai_range_code = ai_range_code_64_mx, |
1047 | .ai_fifo = ai_fifo_64xx, |
1048 | .has_8255 = 1, |
1049 | }, |
1050 | [BOARD_PCIDAS64_M1_14] = { |
1051 | .name = "pci-das64/m1/14" , |
1052 | .ai_se_chans = 64, |
1053 | .ai_bits = 14, |
1054 | .ai_speed = 1000, |
1055 | .ao_nchan = 2, |
1056 | .ao_scan_speed = 10000, |
1057 | .layout = LAYOUT_64XX, |
1058 | .ai_range_table = &ai_ranges_64_mx, |
1059 | .ai_range_code = ai_range_code_64_mx, |
1060 | .ai_fifo = ai_fifo_64xx, |
1061 | .has_8255 = 1, |
1062 | }, |
1063 | [BOARD_PCIDAS64_M2_14] = { |
1064 | .name = "pci-das64/m2/14" , |
1065 | .ai_se_chans = 64, |
1066 | .ai_bits = 14, |
1067 | .ai_speed = 500, |
1068 | .ao_nchan = 2, |
1069 | .ao_scan_speed = 10000, |
1070 | .layout = LAYOUT_64XX, |
1071 | .ai_range_table = &ai_ranges_64_mx, |
1072 | .ai_range_code = ai_range_code_64_mx, |
1073 | .ai_fifo = ai_fifo_64xx, |
1074 | .has_8255 = 1, |
1075 | }, |
1076 | [BOARD_PCIDAS64_M3_14] = { |
1077 | .name = "pci-das64/m3/14" , |
1078 | .ai_se_chans = 64, |
1079 | .ai_bits = 14, |
1080 | .ai_speed = 333, |
1081 | .ao_nchan = 2, |
1082 | .ao_scan_speed = 10000, |
1083 | .layout = LAYOUT_64XX, |
1084 | .ai_range_table = &ai_ranges_64_mx, |
1085 | .ai_range_code = ai_range_code_64_mx, |
1086 | .ai_fifo = ai_fifo_64xx, |
1087 | .has_8255 = 1, |
1088 | }, |
1089 | #endif |
1090 | }; |
1091 | |
1092 | static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev, |
1093 | int use_differential) |
1094 | { |
1095 | const struct pcidas64_board *board = dev->board_ptr; |
1096 | |
1097 | if ((board->layout == LAYOUT_64XX && !use_differential) || |
1098 | (board->layout == LAYOUT_60XX && use_differential)) |
1099 | return ADC_SE_DIFF_BIT; |
1100 | |
1101 | return 0; |
1102 | } |
1103 | |
1104 | struct ext_clock_info { |
1105 | /* master clock divisor to use for scans with external master clock */ |
1106 | unsigned int divisor; |
1107 | /* chanspec for master clock input when used as scan begin src */ |
1108 | unsigned int chanspec; |
1109 | }; |
1110 | |
1111 | /* this structure is for data unique to this hardware driver. */ |
1112 | struct pcidas64_private { |
1113 | /* base addresses (physical) */ |
1114 | resource_size_t main_phys_iobase; |
1115 | resource_size_t dio_counter_phys_iobase; |
1116 | /* base addresses (ioremapped) */ |
1117 | void __iomem *plx9080_iobase; |
1118 | void __iomem *main_iobase; |
1119 | /* local address (used by dma controller) */ |
1120 | u32 local0_iobase; |
1121 | u32 local1_iobase; |
1122 | /* dma buffers for analog input */ |
1123 | u16 *ai_buffer[MAX_AI_DMA_RING_COUNT]; |
1124 | /* physical addresses of ai dma buffers */ |
1125 | dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; |
1126 | /* |
1127 | * array of ai dma descriptors read by plx9080, |
1128 | * allocated to get proper alignment |
1129 | */ |
1130 | struct plx_dma_desc *ai_dma_desc; |
1131 | /* physical address of ai dma descriptor array */ |
1132 | dma_addr_t ai_dma_desc_bus_addr; |
1133 | /* |
1134 | * index of the ai dma descriptor/buffer |
1135 | * that is currently being used |
1136 | */ |
1137 | unsigned int ai_dma_index; |
1138 | /* dma buffers for analog output */ |
1139 | u16 *ao_buffer[AO_DMA_RING_COUNT]; |
1140 | /* physical addresses of ao dma buffers */ |
1141 | dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; |
1142 | struct plx_dma_desc *ao_dma_desc; |
1143 | dma_addr_t ao_dma_desc_bus_addr; |
1144 | /* keeps track of buffer where the next ao sample should go */ |
1145 | unsigned int ao_dma_index; |
1146 | unsigned int hw_revision; /* stc chip hardware revision number */ |
1147 | /* last bits sent to INTR_ENABLE_REG register */ |
1148 | unsigned int intr_enable_bits; |
1149 | /* last bits sent to ADC_CONTROL1_REG register */ |
1150 | u16 adc_control1_bits; |
1151 | /* last bits sent to FIFO_SIZE_REG register */ |
1152 | u16 fifo_size_bits; |
1153 | /* last bits sent to HW_CONFIG_REG register */ |
1154 | u16 hw_config_bits; |
1155 | u16 dac_control1_bits; |
1156 | /* last bits written to plx9080 control register */ |
1157 | u32 plx_control_bits; |
1158 | /* last bits written to plx interrupt control and status register */ |
1159 | u32 plx_intcsr_bits; |
1160 | /* index of calibration source readable through ai ch0 */ |
1161 | int calibration_source; |
1162 | /* bits written to i2c calibration/range register */ |
1163 | u8 i2c_cal_range_bits; |
1164 | /* configure digital triggers to trigger on falling edge */ |
1165 | unsigned int ext_trig_falling; |
1166 | short ai_cmd_running; |
1167 | unsigned int ai_fifo_segment_length; |
1168 | struct ext_clock_info ext_clock; |
1169 | unsigned short ao_bounce_buffer[DAC_FIFO_SIZE]; |
1170 | }; |
1171 | |
1172 | static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev, |
1173 | unsigned int range_index) |
1174 | { |
1175 | const struct pcidas64_board *board = dev->board_ptr; |
1176 | |
1177 | return board->ai_range_code[range_index] << 8; |
1178 | } |
1179 | |
1180 | static unsigned int hw_revision(const struct comedi_device *dev, |
1181 | u16 hw_status_bits) |
1182 | { |
1183 | const struct pcidas64_board *board = dev->board_ptr; |
1184 | |
1185 | if (board->layout == LAYOUT_4020) |
1186 | return (hw_status_bits >> 13) & 0x7; |
1187 | |
1188 | return (hw_status_bits >> 12) & 0xf; |
1189 | } |
1190 | |
1191 | static void set_dac_range_bits(struct comedi_device *dev, |
1192 | u16 *bits, unsigned int channel, |
1193 | unsigned int range) |
1194 | { |
1195 | const struct pcidas64_board *board = dev->board_ptr; |
1196 | unsigned int code = board->ao_range_code[range]; |
1197 | |
1198 | if (channel > 1) |
1199 | dev_err(dev->class_dev, "bug! bad channel?\n" ); |
1200 | if (code & ~0x3) |
1201 | dev_err(dev->class_dev, "bug! bad range code?\n" ); |
1202 | |
1203 | *bits &= ~(0x3 << (2 * channel)); |
1204 | *bits |= code << (2 * channel); |
1205 | }; |
1206 | |
1207 | static inline int ao_cmd_is_supported(const struct pcidas64_board *board) |
1208 | { |
1209 | return board->ao_nchan && board->layout != LAYOUT_4020; |
1210 | } |
1211 | |
1212 | static void abort_dma(struct comedi_device *dev, unsigned int channel) |
1213 | { |
1214 | struct pcidas64_private *devpriv = dev->private; |
1215 | unsigned long flags; |
1216 | |
1217 | /* spinlock for plx dma control/status reg */ |
1218 | spin_lock_irqsave(&dev->spinlock, flags); |
1219 | |
1220 | plx9080_abort_dma(iobase: devpriv->plx9080_iobase, channel); |
1221 | |
1222 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1223 | } |
1224 | |
1225 | static void disable_plx_interrupts(struct comedi_device *dev) |
1226 | { |
1227 | struct pcidas64_private *devpriv = dev->private; |
1228 | |
1229 | devpriv->plx_intcsr_bits = 0; |
1230 | writel(val: devpriv->plx_intcsr_bits, |
1231 | addr: devpriv->plx9080_iobase + PLX_REG_INTCSR); |
1232 | } |
1233 | |
1234 | static void disable_ai_interrupts(struct comedi_device *dev) |
1235 | { |
1236 | struct pcidas64_private *devpriv = dev->private; |
1237 | unsigned long flags; |
1238 | |
1239 | spin_lock_irqsave(&dev->spinlock, flags); |
1240 | devpriv->intr_enable_bits &= |
1241 | ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT & |
1242 | ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & |
1243 | ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK; |
1244 | writew(val: devpriv->intr_enable_bits, |
1245 | addr: devpriv->main_iobase + INTR_ENABLE_REG); |
1246 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1247 | } |
1248 | |
1249 | static void enable_ai_interrupts(struct comedi_device *dev, |
1250 | const struct comedi_cmd *cmd) |
1251 | { |
1252 | const struct pcidas64_board *board = dev->board_ptr; |
1253 | struct pcidas64_private *devpriv = dev->private; |
1254 | u32 bits; |
1255 | unsigned long flags; |
1256 | |
1257 | bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT | |
1258 | EN_ADC_ACTIVE_INTR_BIT | EN_ADC_STOP_INTR_BIT; |
1259 | /* |
1260 | * Use pio transfer and interrupt on end of conversion |
1261 | * if CMDF_WAKE_EOS flag is set. |
1262 | */ |
1263 | if (cmd->flags & CMDF_WAKE_EOS) { |
1264 | /* 4020 doesn't support pio transfers except for fifo dregs */ |
1265 | if (board->layout != LAYOUT_4020) |
1266 | bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT; |
1267 | } |
1268 | spin_lock_irqsave(&dev->spinlock, flags); |
1269 | devpriv->intr_enable_bits |= bits; |
1270 | writew(val: devpriv->intr_enable_bits, |
1271 | addr: devpriv->main_iobase + INTR_ENABLE_REG); |
1272 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1273 | } |
1274 | |
1275 | /* initialize plx9080 chip */ |
1276 | static void init_plx9080(struct comedi_device *dev) |
1277 | { |
1278 | const struct pcidas64_board *board = dev->board_ptr; |
1279 | struct pcidas64_private *devpriv = dev->private; |
1280 | u32 bits; |
1281 | void __iomem *plx_iobase = devpriv->plx9080_iobase; |
1282 | |
1283 | devpriv->plx_control_bits = |
1284 | readl(addr: devpriv->plx9080_iobase + PLX_REG_CNTRL); |
1285 | |
1286 | #ifdef __BIG_ENDIAN |
1287 | bits = PLX_BIGEND_DMA0 | PLX_BIGEND_DMA1; |
1288 | #else |
1289 | bits = 0; |
1290 | #endif |
1291 | writel(val: bits, addr: devpriv->plx9080_iobase + PLX_REG_BIGEND); |
1292 | |
1293 | disable_plx_interrupts(dev); |
1294 | |
1295 | abort_dma(dev, channel: 0); |
1296 | abort_dma(dev, channel: 1); |
1297 | |
1298 | /* configure dma0 mode */ |
1299 | bits = 0; |
1300 | /* enable ready input, not sure if this is necessary */ |
1301 | bits |= PLX_DMAMODE_READYIEN; |
1302 | /* enable bterm, not sure if this is necessary */ |
1303 | bits |= PLX_DMAMODE_BTERMIEN; |
1304 | /* enable dma chaining */ |
1305 | bits |= PLX_DMAMODE_CHAINEN; |
1306 | /* |
1307 | * enable interrupt on dma done |
1308 | * (probably don't need this, since chain never finishes) |
1309 | */ |
1310 | bits |= PLX_DMAMODE_DONEIEN; |
1311 | /* |
1312 | * don't increment local address during transfers |
1313 | * (we are transferring from a fixed fifo register) |
1314 | */ |
1315 | bits |= PLX_DMAMODE_LACONST; |
1316 | /* route dma interrupt to pci bus */ |
1317 | bits |= PLX_DMAMODE_INTRPCI; |
1318 | /* enable demand mode */ |
1319 | bits |= PLX_DMAMODE_DEMAND; |
1320 | /* enable local burst mode */ |
1321 | bits |= PLX_DMAMODE_BURSTEN; |
1322 | /* 4020 uses 32 bit dma */ |
1323 | if (board->layout == LAYOUT_4020) |
1324 | bits |= PLX_DMAMODE_WIDTH_32; |
1325 | else /* localspace0 bus is 16 bits wide */ |
1326 | bits |= PLX_DMAMODE_WIDTH_16; |
1327 | writel(val: bits, addr: plx_iobase + PLX_REG_DMAMODE1); |
1328 | if (ao_cmd_is_supported(board)) |
1329 | writel(val: bits, addr: plx_iobase + PLX_REG_DMAMODE0); |
1330 | |
1331 | /* enable interrupts on plx 9080 */ |
1332 | devpriv->plx_intcsr_bits |= |
1333 | PLX_INTCSR_LSEABORTEN | PLX_INTCSR_LSEPARITYEN | PLX_INTCSR_PIEN | |
1334 | PLX_INTCSR_PLIEN | PLX_INTCSR_PABORTIEN | PLX_INTCSR_LIOEN | |
1335 | PLX_INTCSR_DMA0IEN | PLX_INTCSR_DMA1IEN; |
1336 | writel(val: devpriv->plx_intcsr_bits, |
1337 | addr: devpriv->plx9080_iobase + PLX_REG_INTCSR); |
1338 | } |
1339 | |
1340 | static void disable_ai_pacing(struct comedi_device *dev) |
1341 | { |
1342 | struct pcidas64_private *devpriv = dev->private; |
1343 | unsigned long flags; |
1344 | |
1345 | disable_ai_interrupts(dev); |
1346 | |
1347 | spin_lock_irqsave(&dev->spinlock, flags); |
1348 | devpriv->adc_control1_bits &= ~ADC_SW_GATE_BIT; |
1349 | writew(val: devpriv->adc_control1_bits, |
1350 | addr: devpriv->main_iobase + ADC_CONTROL1_REG); |
1351 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1352 | |
1353 | /* disable pacing, triggering, etc */ |
1354 | writew(val: ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT, |
1355 | addr: devpriv->main_iobase + ADC_CONTROL0_REG); |
1356 | } |
1357 | |
1358 | static int set_ai_fifo_segment_length(struct comedi_device *dev, |
1359 | unsigned int num_entries) |
1360 | { |
1361 | const struct pcidas64_board *board = dev->board_ptr; |
1362 | struct pcidas64_private *devpriv = dev->private; |
1363 | static const int increment_size = 0x100; |
1364 | const struct hw_fifo_info *const fifo = board->ai_fifo; |
1365 | unsigned int num_increments; |
1366 | u16 bits; |
1367 | |
1368 | if (num_entries < increment_size) |
1369 | num_entries = increment_size; |
1370 | if (num_entries > fifo->max_segment_length) |
1371 | num_entries = fifo->max_segment_length; |
1372 | |
1373 | /* 1 == 256 entries, 2 == 512 entries, etc */ |
1374 | num_increments = DIV_ROUND_CLOSEST(num_entries, increment_size); |
1375 | |
1376 | bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask; |
1377 | devpriv->fifo_size_bits &= ~fifo->fifo_size_reg_mask; |
1378 | devpriv->fifo_size_bits |= bits; |
1379 | writew(val: devpriv->fifo_size_bits, |
1380 | addr: devpriv->main_iobase + FIFO_SIZE_REG); |
1381 | |
1382 | devpriv->ai_fifo_segment_length = num_increments * increment_size; |
1383 | |
1384 | return devpriv->ai_fifo_segment_length; |
1385 | } |
1386 | |
1387 | /* |
1388 | * adjusts the size of hardware fifo (which determines block size for dma xfers) |
1389 | */ |
1390 | static int set_ai_fifo_size(struct comedi_device *dev, unsigned int num_samples) |
1391 | { |
1392 | const struct pcidas64_board *board = dev->board_ptr; |
1393 | unsigned int num_fifo_entries; |
1394 | int retval; |
1395 | const struct hw_fifo_info *const fifo = board->ai_fifo; |
1396 | |
1397 | num_fifo_entries = num_samples / fifo->sample_packing_ratio; |
1398 | |
1399 | retval = set_ai_fifo_segment_length(dev, |
1400 | num_entries: num_fifo_entries / |
1401 | fifo->num_segments); |
1402 | if (retval < 0) |
1403 | return retval; |
1404 | |
1405 | return retval * fifo->num_segments * fifo->sample_packing_ratio; |
1406 | } |
1407 | |
1408 | /* query length of fifo */ |
1409 | static unsigned int ai_fifo_size(struct comedi_device *dev) |
1410 | { |
1411 | const struct pcidas64_board *board = dev->board_ptr; |
1412 | struct pcidas64_private *devpriv = dev->private; |
1413 | |
1414 | return devpriv->ai_fifo_segment_length * |
1415 | board->ai_fifo->num_segments * |
1416 | board->ai_fifo->sample_packing_ratio; |
1417 | } |
1418 | |
1419 | static void init_stc_registers(struct comedi_device *dev) |
1420 | { |
1421 | const struct pcidas64_board *board = dev->board_ptr; |
1422 | struct pcidas64_private *devpriv = dev->private; |
1423 | u16 bits; |
1424 | unsigned long flags; |
1425 | |
1426 | spin_lock_irqsave(&dev->spinlock, flags); |
1427 | |
1428 | /* |
1429 | * bit should be set for 6025, |
1430 | * although docs say boards with <= 16 chans should be cleared XXX |
1431 | */ |
1432 | if (1) |
1433 | devpriv->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT; |
1434 | writew(val: devpriv->adc_control1_bits, |
1435 | addr: devpriv->main_iobase + ADC_CONTROL1_REG); |
1436 | |
1437 | /* 6402/16 manual says this register must be initialized to 0xff? */ |
1438 | writew(val: 0xff, addr: devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); |
1439 | |
1440 | bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT; |
1441 | if (board->layout == LAYOUT_4020) |
1442 | bits |= INTERNAL_CLOCK_4020_BITS; |
1443 | devpriv->hw_config_bits |= bits; |
1444 | writew(val: devpriv->hw_config_bits, |
1445 | addr: devpriv->main_iobase + HW_CONFIG_REG); |
1446 | |
1447 | writew(val: 0, addr: devpriv->main_iobase + DAQ_SYNC_REG); |
1448 | writew(val: 0, addr: devpriv->main_iobase + CALIBRATION_REG); |
1449 | |
1450 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1451 | |
1452 | /* set fifos to maximum size */ |
1453 | devpriv->fifo_size_bits |= DAC_FIFO_BITS; |
1454 | set_ai_fifo_segment_length(dev, num_entries: board->ai_fifo->max_segment_length); |
1455 | |
1456 | devpriv->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT; |
1457 | devpriv->intr_enable_bits = |
1458 | /* EN_DAC_INTR_SRC_BIT | DAC_INTR_QEMPTY_BITS | */ |
1459 | EN_DAC_DONE_INTR_BIT | EN_DAC_UNDERRUN_BIT; |
1460 | writew(val: devpriv->intr_enable_bits, |
1461 | addr: devpriv->main_iobase + INTR_ENABLE_REG); |
1462 | |
1463 | disable_ai_pacing(dev); |
1464 | }; |
1465 | |
1466 | static int alloc_and_init_dma_members(struct comedi_device *dev) |
1467 | { |
1468 | const struct pcidas64_board *board = dev->board_ptr; |
1469 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
1470 | struct pcidas64_private *devpriv = dev->private; |
1471 | int i; |
1472 | |
1473 | /* allocate pci dma buffers */ |
1474 | for (i = 0; i < ai_dma_ring_count(board); i++) { |
1475 | devpriv->ai_buffer[i] = |
1476 | dma_alloc_coherent(dev: &pcidev->dev, DMA_BUFFER_SIZE, |
1477 | dma_handle: &devpriv->ai_buffer_bus_addr[i], |
1478 | GFP_KERNEL); |
1479 | if (!devpriv->ai_buffer[i]) |
1480 | return -ENOMEM; |
1481 | } |
1482 | for (i = 0; i < AO_DMA_RING_COUNT; i++) { |
1483 | if (ao_cmd_is_supported(board)) { |
1484 | devpriv->ao_buffer[i] = |
1485 | dma_alloc_coherent(dev: &pcidev->dev, |
1486 | DMA_BUFFER_SIZE, |
1487 | dma_handle: &devpriv->ao_buffer_bus_addr[i], |
1488 | GFP_KERNEL); |
1489 | if (!devpriv->ao_buffer[i]) |
1490 | return -ENOMEM; |
1491 | } |
1492 | } |
1493 | /* allocate dma descriptors */ |
1494 | devpriv->ai_dma_desc = |
1495 | dma_alloc_coherent(dev: &pcidev->dev, size: sizeof(struct plx_dma_desc) * |
1496 | ai_dma_ring_count(board), |
1497 | dma_handle: &devpriv->ai_dma_desc_bus_addr, GFP_KERNEL); |
1498 | if (!devpriv->ai_dma_desc) |
1499 | return -ENOMEM; |
1500 | |
1501 | if (ao_cmd_is_supported(board)) { |
1502 | devpriv->ao_dma_desc = |
1503 | dma_alloc_coherent(dev: &pcidev->dev, |
1504 | size: sizeof(struct plx_dma_desc) * |
1505 | AO_DMA_RING_COUNT, |
1506 | dma_handle: &devpriv->ao_dma_desc_bus_addr, |
1507 | GFP_KERNEL); |
1508 | if (!devpriv->ao_dma_desc) |
1509 | return -ENOMEM; |
1510 | } |
1511 | /* initialize dma descriptors */ |
1512 | for (i = 0; i < ai_dma_ring_count(board); i++) { |
1513 | devpriv->ai_dma_desc[i].pci_start_addr = |
1514 | cpu_to_le32(devpriv->ai_buffer_bus_addr[i]); |
1515 | if (board->layout == LAYOUT_4020) |
1516 | devpriv->ai_dma_desc[i].local_start_addr = |
1517 | cpu_to_le32(devpriv->local1_iobase + |
1518 | ADC_FIFO_REG); |
1519 | else |
1520 | devpriv->ai_dma_desc[i].local_start_addr = |
1521 | cpu_to_le32(devpriv->local0_iobase + |
1522 | ADC_FIFO_REG); |
1523 | devpriv->ai_dma_desc[i].transfer_size = cpu_to_le32(0); |
1524 | devpriv->ai_dma_desc[i].next = |
1525 | cpu_to_le32((devpriv->ai_dma_desc_bus_addr + |
1526 | ((i + 1) % ai_dma_ring_count(board)) * |
1527 | sizeof(devpriv->ai_dma_desc[0])) | |
1528 | PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR | |
1529 | PLX_DMADPR_XFERL2P); |
1530 | } |
1531 | if (ao_cmd_is_supported(board)) { |
1532 | for (i = 0; i < AO_DMA_RING_COUNT; i++) { |
1533 | devpriv->ao_dma_desc[i].pci_start_addr = |
1534 | cpu_to_le32(devpriv->ao_buffer_bus_addr[i]); |
1535 | devpriv->ao_dma_desc[i].local_start_addr = |
1536 | cpu_to_le32(devpriv->local0_iobase + |
1537 | DAC_FIFO_REG); |
1538 | devpriv->ao_dma_desc[i].transfer_size = cpu_to_le32(0); |
1539 | devpriv->ao_dma_desc[i].next = |
1540 | cpu_to_le32((devpriv->ao_dma_desc_bus_addr + |
1541 | ((i + 1) % (AO_DMA_RING_COUNT)) * |
1542 | sizeof(devpriv->ao_dma_desc[0])) | |
1543 | PLX_DMADPR_DESCPCI | |
1544 | PLX_DMADPR_TCINTR); |
1545 | } |
1546 | } |
1547 | return 0; |
1548 | } |
1549 | |
1550 | static void cb_pcidas64_free_dma(struct comedi_device *dev) |
1551 | { |
1552 | const struct pcidas64_board *board = dev->board_ptr; |
1553 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
1554 | struct pcidas64_private *devpriv = dev->private; |
1555 | int i; |
1556 | |
1557 | if (!devpriv) |
1558 | return; |
1559 | |
1560 | /* free pci dma buffers */ |
1561 | for (i = 0; i < ai_dma_ring_count(board); i++) { |
1562 | if (devpriv->ai_buffer[i]) |
1563 | dma_free_coherent(dev: &pcidev->dev, |
1564 | DMA_BUFFER_SIZE, |
1565 | cpu_addr: devpriv->ai_buffer[i], |
1566 | dma_handle: devpriv->ai_buffer_bus_addr[i]); |
1567 | } |
1568 | for (i = 0; i < AO_DMA_RING_COUNT; i++) { |
1569 | if (devpriv->ao_buffer[i]) |
1570 | dma_free_coherent(dev: &pcidev->dev, |
1571 | DMA_BUFFER_SIZE, |
1572 | cpu_addr: devpriv->ao_buffer[i], |
1573 | dma_handle: devpriv->ao_buffer_bus_addr[i]); |
1574 | } |
1575 | /* free dma descriptors */ |
1576 | if (devpriv->ai_dma_desc) |
1577 | dma_free_coherent(dev: &pcidev->dev, |
1578 | size: sizeof(struct plx_dma_desc) * |
1579 | ai_dma_ring_count(board), |
1580 | cpu_addr: devpriv->ai_dma_desc, |
1581 | dma_handle: devpriv->ai_dma_desc_bus_addr); |
1582 | if (devpriv->ao_dma_desc) |
1583 | dma_free_coherent(dev: &pcidev->dev, |
1584 | size: sizeof(struct plx_dma_desc) * |
1585 | AO_DMA_RING_COUNT, |
1586 | cpu_addr: devpriv->ao_dma_desc, |
1587 | dma_handle: devpriv->ao_dma_desc_bus_addr); |
1588 | } |
1589 | |
1590 | static inline void warn_external_queue(struct comedi_device *dev) |
1591 | { |
1592 | dev_err(dev->class_dev, |
1593 | "AO command and AI external channel queue cannot be used simultaneously\n" ); |
1594 | dev_err(dev->class_dev, |
1595 | "Use internal AI channel queue (channels must be consecutive and use same range/aref)\n" ); |
1596 | } |
1597 | |
1598 | /* |
1599 | * their i2c requires a huge delay on setting clock or data high for some reason |
1600 | */ |
1601 | static const int i2c_high_udelay = 1000; |
1602 | static const int i2c_low_udelay = 10; |
1603 | |
1604 | /* set i2c data line high or low */ |
1605 | static void i2c_set_sda(struct comedi_device *dev, int state) |
1606 | { |
1607 | struct pcidas64_private *devpriv = dev->private; |
1608 | static const int data_bit = PLX_CNTRL_EEWB; |
1609 | void __iomem *plx_control_addr = devpriv->plx9080_iobase + |
1610 | PLX_REG_CNTRL; |
1611 | |
1612 | if (state) { /* set data line high */ |
1613 | devpriv->plx_control_bits &= ~data_bit; |
1614 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
1615 | udelay(i2c_high_udelay); |
1616 | } else { /* set data line low */ |
1617 | devpriv->plx_control_bits |= data_bit; |
1618 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
1619 | udelay(i2c_low_udelay); |
1620 | } |
1621 | } |
1622 | |
1623 | /* set i2c clock line high or low */ |
1624 | static void i2c_set_scl(struct comedi_device *dev, int state) |
1625 | { |
1626 | struct pcidas64_private *devpriv = dev->private; |
1627 | static const int clock_bit = PLX_CNTRL_USERO; |
1628 | void __iomem *plx_control_addr = devpriv->plx9080_iobase + |
1629 | PLX_REG_CNTRL; |
1630 | |
1631 | if (state) { /* set clock line high */ |
1632 | devpriv->plx_control_bits &= ~clock_bit; |
1633 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
1634 | udelay(i2c_high_udelay); |
1635 | } else { /* set clock line low */ |
1636 | devpriv->plx_control_bits |= clock_bit; |
1637 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
1638 | udelay(i2c_low_udelay); |
1639 | } |
1640 | } |
1641 | |
1642 | static void i2c_write_byte(struct comedi_device *dev, u8 byte) |
1643 | { |
1644 | u8 bit; |
1645 | unsigned int num_bits = 8; |
1646 | |
1647 | for (bit = 1 << (num_bits - 1); bit; bit >>= 1) { |
1648 | i2c_set_scl(dev, state: 0); |
1649 | if ((byte & bit)) |
1650 | i2c_set_sda(dev, state: 1); |
1651 | else |
1652 | i2c_set_sda(dev, state: 0); |
1653 | i2c_set_scl(dev, state: 1); |
1654 | } |
1655 | } |
1656 | |
1657 | /* we can't really read the lines, so fake it */ |
1658 | static int i2c_read_ack(struct comedi_device *dev) |
1659 | { |
1660 | i2c_set_scl(dev, state: 0); |
1661 | i2c_set_sda(dev, state: 1); |
1662 | i2c_set_scl(dev, state: 1); |
1663 | |
1664 | return 0; /* return fake acknowledge bit */ |
1665 | } |
1666 | |
1667 | /* send start bit */ |
1668 | static void i2c_start(struct comedi_device *dev) |
1669 | { |
1670 | i2c_set_scl(dev, state: 1); |
1671 | i2c_set_sda(dev, state: 1); |
1672 | i2c_set_sda(dev, state: 0); |
1673 | } |
1674 | |
1675 | /* send stop bit */ |
1676 | static void i2c_stop(struct comedi_device *dev) |
1677 | { |
1678 | i2c_set_scl(dev, state: 0); |
1679 | i2c_set_sda(dev, state: 0); |
1680 | i2c_set_scl(dev, state: 1); |
1681 | i2c_set_sda(dev, state: 1); |
1682 | } |
1683 | |
1684 | static void i2c_write(struct comedi_device *dev, unsigned int address, |
1685 | const u8 *data, unsigned int length) |
1686 | { |
1687 | struct pcidas64_private *devpriv = dev->private; |
1688 | unsigned int i; |
1689 | u8 bitstream; |
1690 | static const int read_bit = 0x1; |
1691 | |
1692 | /* |
1693 | * XXX need mutex to prevent simultaneous attempts to access |
1694 | * eeprom and i2c bus |
1695 | */ |
1696 | |
1697 | /* make sure we don't send anything to eeprom */ |
1698 | devpriv->plx_control_bits &= ~PLX_CNTRL_EECS; |
1699 | |
1700 | i2c_stop(dev); |
1701 | i2c_start(dev); |
1702 | |
1703 | /* send address and write bit */ |
1704 | bitstream = (address << 1) & ~read_bit; |
1705 | i2c_write_byte(dev, byte: bitstream); |
1706 | |
1707 | /* get acknowledge */ |
1708 | if (i2c_read_ack(dev) != 0) { |
1709 | dev_err(dev->class_dev, "failed: no acknowledge\n" ); |
1710 | i2c_stop(dev); |
1711 | return; |
1712 | } |
1713 | /* write data bytes */ |
1714 | for (i = 0; i < length; i++) { |
1715 | i2c_write_byte(dev, byte: data[i]); |
1716 | if (i2c_read_ack(dev) != 0) { |
1717 | dev_err(dev->class_dev, "failed: no acknowledge\n" ); |
1718 | i2c_stop(dev); |
1719 | return; |
1720 | } |
1721 | } |
1722 | i2c_stop(dev); |
1723 | } |
1724 | |
1725 | static int cb_pcidas64_ai_eoc(struct comedi_device *dev, |
1726 | struct comedi_subdevice *s, |
1727 | struct comedi_insn *insn, |
1728 | unsigned long context) |
1729 | { |
1730 | const struct pcidas64_board *board = dev->board_ptr; |
1731 | struct pcidas64_private *devpriv = dev->private; |
1732 | unsigned int status; |
1733 | |
1734 | status = readw(addr: devpriv->main_iobase + HW_STATUS_REG); |
1735 | if (board->layout == LAYOUT_4020) { |
1736 | status = readw(addr: devpriv->main_iobase + ADC_WRITE_PNTR_REG); |
1737 | if (status) |
1738 | return 0; |
1739 | } else { |
1740 | if (pipe_full_bits(hw_status_bits: status)) |
1741 | return 0; |
1742 | } |
1743 | return -EBUSY; |
1744 | } |
1745 | |
1746 | static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, |
1747 | struct comedi_insn *insn, unsigned int *data) |
1748 | { |
1749 | const struct pcidas64_board *board = dev->board_ptr; |
1750 | struct pcidas64_private *devpriv = dev->private; |
1751 | unsigned int bits = 0, n; |
1752 | unsigned int channel, range, aref; |
1753 | unsigned long flags; |
1754 | int ret; |
1755 | |
1756 | channel = CR_CHAN(insn->chanspec); |
1757 | range = CR_RANGE(insn->chanspec); |
1758 | aref = CR_AREF(insn->chanspec); |
1759 | |
1760 | /* disable card's analog input interrupt sources and pacing */ |
1761 | /* 4020 generates dac done interrupts even though they are disabled */ |
1762 | disable_ai_pacing(dev); |
1763 | |
1764 | spin_lock_irqsave(&dev->spinlock, flags); |
1765 | if (insn->chanspec & CR_ALT_FILTER) |
1766 | devpriv->adc_control1_bits |= ADC_DITHER_BIT; |
1767 | else |
1768 | devpriv->adc_control1_bits &= ~ADC_DITHER_BIT; |
1769 | writew(val: devpriv->adc_control1_bits, |
1770 | addr: devpriv->main_iobase + ADC_CONTROL1_REG); |
1771 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
1772 | |
1773 | if (board->layout != LAYOUT_4020) { |
1774 | /* use internal queue */ |
1775 | devpriv->hw_config_bits &= ~EXT_QUEUE_BIT; |
1776 | writew(val: devpriv->hw_config_bits, |
1777 | addr: devpriv->main_iobase + HW_CONFIG_REG); |
1778 | |
1779 | /* ALT_SOURCE is internal calibration reference */ |
1780 | if (insn->chanspec & CR_ALT_SOURCE) { |
1781 | unsigned int cal_en_bit; |
1782 | |
1783 | if (board->layout == LAYOUT_60XX) |
1784 | cal_en_bit = CAL_EN_60XX_BIT; |
1785 | else |
1786 | cal_en_bit = CAL_EN_64XX_BIT; |
1787 | /* |
1788 | * select internal reference source to connect |
1789 | * to channel 0 |
1790 | */ |
1791 | writew(val: cal_en_bit | |
1792 | adc_src_bits(source: devpriv->calibration_source), |
1793 | addr: devpriv->main_iobase + CALIBRATION_REG); |
1794 | } else { |
1795 | /* |
1796 | * make sure internal calibration source |
1797 | * is turned off |
1798 | */ |
1799 | writew(val: 0, addr: devpriv->main_iobase + CALIBRATION_REG); |
1800 | } |
1801 | /* load internal queue */ |
1802 | bits = 0; |
1803 | /* set gain */ |
1804 | bits |= ai_range_bits_6xxx(dev, CR_RANGE(insn->chanspec)); |
1805 | /* set single-ended / differential */ |
1806 | bits |= se_diff_bit_6xxx(dev, use_differential: aref == AREF_DIFF); |
1807 | if (aref == AREF_COMMON) |
1808 | bits |= ADC_COMMON_BIT; |
1809 | bits |= adc_chan_bits(channel); |
1810 | /* set stop channel */ |
1811 | writew(val: adc_chan_bits(channel), |
1812 | addr: devpriv->main_iobase + ADC_QUEUE_HIGH_REG); |
1813 | /* set start channel, and rest of settings */ |
1814 | writew(val: bits, addr: devpriv->main_iobase + ADC_QUEUE_LOAD_REG); |
1815 | } else { |
1816 | u8 old_cal_range_bits = devpriv->i2c_cal_range_bits; |
1817 | |
1818 | devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; |
1819 | if (insn->chanspec & CR_ALT_SOURCE) { |
1820 | devpriv->i2c_cal_range_bits |= |
1821 | adc_src_4020_bits(source: devpriv->calibration_source); |
1822 | } else { /* select BNC inputs */ |
1823 | devpriv->i2c_cal_range_bits |= adc_src_4020_bits(source: 4); |
1824 | } |
1825 | /* select range */ |
1826 | if (range == 0) |
1827 | devpriv->i2c_cal_range_bits |= attenuate_bit(channel); |
1828 | else |
1829 | devpriv->i2c_cal_range_bits &= ~attenuate_bit(channel); |
1830 | /* |
1831 | * update calibration/range i2c register only if necessary, |
1832 | * as it is very slow |
1833 | */ |
1834 | if (old_cal_range_bits != devpriv->i2c_cal_range_bits) { |
1835 | u8 i2c_data = devpriv->i2c_cal_range_bits; |
1836 | |
1837 | i2c_write(dev, address: RANGE_CAL_I2C_ADDR, data: &i2c_data, |
1838 | length: sizeof(i2c_data)); |
1839 | } |
1840 | |
1841 | /* |
1842 | * 4020 manual asks that sample interval register to be set |
1843 | * before writing to convert register. |
1844 | * Using somewhat arbitrary setting of 4 master clock ticks |
1845 | * = 0.1 usec |
1846 | */ |
1847 | writew(val: 0, addr: devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); |
1848 | writew(val: 2, addr: devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); |
1849 | } |
1850 | |
1851 | for (n = 0; n < insn->n; n++) { |
1852 | /* clear adc buffer (inside loop for 4020 sake) */ |
1853 | writew(val: 0, addr: devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); |
1854 | |
1855 | /* trigger conversion, bits sent only matter for 4020 */ |
1856 | writew(val: adc_convert_chan_4020_bits(CR_CHAN(insn->chanspec)), |
1857 | addr: devpriv->main_iobase + ADC_CONVERT_REG); |
1858 | |
1859 | /* wait for data */ |
1860 | ret = comedi_timeout(dev, s, insn, cb: cb_pcidas64_ai_eoc, context: 0); |
1861 | if (ret) |
1862 | return ret; |
1863 | |
1864 | if (board->layout == LAYOUT_4020) |
1865 | data[n] = readl(addr: dev->mmio + ADC_FIFO_REG) & 0xffff; |
1866 | else |
1867 | data[n] = readw(addr: devpriv->main_iobase + PIPE1_READ_REG); |
1868 | } |
1869 | |
1870 | return n; |
1871 | } |
1872 | |
1873 | static int ai_config_calibration_source(struct comedi_device *dev, |
1874 | unsigned int *data) |
1875 | { |
1876 | const struct pcidas64_board *board = dev->board_ptr; |
1877 | struct pcidas64_private *devpriv = dev->private; |
1878 | unsigned int source = data[1]; |
1879 | int num_calibration_sources; |
1880 | |
1881 | if (board->layout == LAYOUT_60XX) |
1882 | num_calibration_sources = 16; |
1883 | else |
1884 | num_calibration_sources = 8; |
1885 | if (source >= num_calibration_sources) { |
1886 | dev_dbg(dev->class_dev, "invalid calibration source: %i\n" , |
1887 | source); |
1888 | return -EINVAL; |
1889 | } |
1890 | |
1891 | devpriv->calibration_source = source; |
1892 | |
1893 | return 2; |
1894 | } |
1895 | |
1896 | static int ai_config_block_size(struct comedi_device *dev, unsigned int *data) |
1897 | { |
1898 | const struct pcidas64_board *board = dev->board_ptr; |
1899 | int fifo_size; |
1900 | const struct hw_fifo_info *const fifo = board->ai_fifo; |
1901 | unsigned int block_size, requested_block_size; |
1902 | int retval; |
1903 | |
1904 | requested_block_size = data[1]; |
1905 | |
1906 | if (requested_block_size) { |
1907 | fifo_size = requested_block_size * fifo->num_segments / |
1908 | bytes_in_sample; |
1909 | |
1910 | retval = set_ai_fifo_size(dev, num_samples: fifo_size); |
1911 | if (retval < 0) |
1912 | return retval; |
1913 | } |
1914 | |
1915 | block_size = ai_fifo_size(dev) / fifo->num_segments * bytes_in_sample; |
1916 | |
1917 | data[1] = block_size; |
1918 | |
1919 | return 2; |
1920 | } |
1921 | |
1922 | static int ai_config_master_clock_4020(struct comedi_device *dev, |
1923 | unsigned int *data) |
1924 | { |
1925 | struct pcidas64_private *devpriv = dev->private; |
1926 | unsigned int divisor = data[4]; |
1927 | int retval = 0; |
1928 | |
1929 | if (divisor < 2) { |
1930 | divisor = 2; |
1931 | retval = -EAGAIN; |
1932 | } |
1933 | |
1934 | switch (data[1]) { |
1935 | case COMEDI_EV_SCAN_BEGIN: |
1936 | devpriv->ext_clock.divisor = divisor; |
1937 | devpriv->ext_clock.chanspec = data[2]; |
1938 | break; |
1939 | default: |
1940 | return -EINVAL; |
1941 | } |
1942 | |
1943 | data[4] = divisor; |
1944 | |
1945 | return retval ? retval : 5; |
1946 | } |
1947 | |
1948 | /* XXX could add support for 60xx series */ |
1949 | static int ai_config_master_clock(struct comedi_device *dev, unsigned int *data) |
1950 | { |
1951 | const struct pcidas64_board *board = dev->board_ptr; |
1952 | |
1953 | switch (board->layout) { |
1954 | case LAYOUT_4020: |
1955 | return ai_config_master_clock_4020(dev, data); |
1956 | default: |
1957 | return -EINVAL; |
1958 | } |
1959 | |
1960 | return -EINVAL; |
1961 | } |
1962 | |
1963 | static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, |
1964 | struct comedi_insn *insn, unsigned int *data) |
1965 | { |
1966 | int id = data[0]; |
1967 | |
1968 | switch (id) { |
1969 | case INSN_CONFIG_ALT_SOURCE: |
1970 | return ai_config_calibration_source(dev, data); |
1971 | case INSN_CONFIG_BLOCK_SIZE: |
1972 | return ai_config_block_size(dev, data); |
1973 | case INSN_CONFIG_TIMER_1: |
1974 | return ai_config_master_clock(dev, data); |
1975 | default: |
1976 | return -EINVAL; |
1977 | } |
1978 | return -EINVAL; |
1979 | } |
1980 | |
1981 | /* |
1982 | * Gets nearest achievable timing given master clock speed, does not |
1983 | * take into account possible minimum/maximum divisor values. Used |
1984 | * by other timing checking functions. |
1985 | */ |
1986 | static unsigned int get_divisor(unsigned int ns, unsigned int flags) |
1987 | { |
1988 | unsigned int divisor; |
1989 | |
1990 | switch (flags & CMDF_ROUND_MASK) { |
1991 | case CMDF_ROUND_UP: |
1992 | divisor = DIV_ROUND_UP(ns, TIMER_BASE); |
1993 | break; |
1994 | case CMDF_ROUND_DOWN: |
1995 | divisor = ns / TIMER_BASE; |
1996 | break; |
1997 | case CMDF_ROUND_NEAREST: |
1998 | default: |
1999 | divisor = DIV_ROUND_CLOSEST(ns, TIMER_BASE); |
2000 | break; |
2001 | } |
2002 | return divisor; |
2003 | } |
2004 | |
2005 | /* |
2006 | * utility function that rounds desired timing to an achievable time, and |
2007 | * sets cmd members appropriately. |
2008 | * adc paces conversions from master clock by dividing by (x + 3) where x is |
2009 | * 24 bit number |
2010 | */ |
2011 | static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) |
2012 | { |
2013 | const struct pcidas64_board *board = dev->board_ptr; |
2014 | unsigned long long convert_divisor = 0; |
2015 | unsigned int scan_divisor; |
2016 | static const int min_convert_divisor = 3; |
2017 | static const int max_convert_divisor = |
2018 | max_counter_value + min_convert_divisor; |
2019 | static const int min_scan_divisor_4020 = 2; |
2020 | unsigned long long max_scan_divisor, min_scan_divisor; |
2021 | |
2022 | if (cmd->convert_src == TRIG_TIMER) { |
2023 | if (board->layout == LAYOUT_4020) { |
2024 | cmd->convert_arg = 0; |
2025 | } else { |
2026 | convert_divisor = get_divisor(ns: cmd->convert_arg, |
2027 | flags: cmd->flags); |
2028 | if (convert_divisor > max_convert_divisor) |
2029 | convert_divisor = max_convert_divisor; |
2030 | if (convert_divisor < min_convert_divisor) |
2031 | convert_divisor = min_convert_divisor; |
2032 | cmd->convert_arg = convert_divisor * TIMER_BASE; |
2033 | } |
2034 | } else if (cmd->convert_src == TRIG_NOW) { |
2035 | cmd->convert_arg = 0; |
2036 | } |
2037 | |
2038 | if (cmd->scan_begin_src == TRIG_TIMER) { |
2039 | scan_divisor = get_divisor(ns: cmd->scan_begin_arg, flags: cmd->flags); |
2040 | if (cmd->convert_src == TRIG_TIMER) { |
2041 | min_scan_divisor = convert_divisor * cmd->chanlist_len; |
2042 | max_scan_divisor = |
2043 | (convert_divisor * cmd->chanlist_len - 1) + |
2044 | max_counter_value; |
2045 | } else { |
2046 | min_scan_divisor = min_scan_divisor_4020; |
2047 | max_scan_divisor = max_counter_value + min_scan_divisor; |
2048 | } |
2049 | if (scan_divisor > max_scan_divisor) |
2050 | scan_divisor = max_scan_divisor; |
2051 | if (scan_divisor < min_scan_divisor) |
2052 | scan_divisor = min_scan_divisor; |
2053 | cmd->scan_begin_arg = scan_divisor * TIMER_BASE; |
2054 | } |
2055 | } |
2056 | |
2057 | static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, |
2058 | struct comedi_subdevice *s, |
2059 | struct comedi_cmd *cmd) |
2060 | { |
2061 | const struct pcidas64_board *board = dev->board_ptr; |
2062 | unsigned int aref0 = CR_AREF(cmd->chanlist[0]); |
2063 | int i; |
2064 | |
2065 | for (i = 1; i < cmd->chanlist_len; i++) { |
2066 | unsigned int aref = CR_AREF(cmd->chanlist[i]); |
2067 | |
2068 | if (aref != aref0) { |
2069 | dev_dbg(dev->class_dev, |
2070 | "all elements in chanlist must use the same analog reference\n" ); |
2071 | return -EINVAL; |
2072 | } |
2073 | } |
2074 | |
2075 | if (board->layout == LAYOUT_4020) { |
2076 | unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); |
2077 | |
2078 | for (i = 1; i < cmd->chanlist_len; i++) { |
2079 | unsigned int chan = CR_CHAN(cmd->chanlist[i]); |
2080 | |
2081 | if (chan != (chan0 + i)) { |
2082 | dev_dbg(dev->class_dev, |
2083 | "chanlist must use consecutive channels\n" ); |
2084 | return -EINVAL; |
2085 | } |
2086 | } |
2087 | if (cmd->chanlist_len == 3) { |
2088 | dev_dbg(dev->class_dev, |
2089 | "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n" ); |
2090 | return -EINVAL; |
2091 | } |
2092 | } |
2093 | |
2094 | return 0; |
2095 | } |
2096 | |
2097 | static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, |
2098 | struct comedi_cmd *cmd) |
2099 | { |
2100 | const struct pcidas64_board *board = dev->board_ptr; |
2101 | int err = 0; |
2102 | unsigned int tmp_arg, tmp_arg2; |
2103 | unsigned int triggers; |
2104 | |
2105 | /* Step 1 : check if triggers are trivially valid */ |
2106 | |
2107 | err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_NOW | TRIG_EXT); |
2108 | |
2109 | triggers = TRIG_TIMER; |
2110 | if (board->layout == LAYOUT_4020) |
2111 | triggers |= TRIG_OTHER; |
2112 | else |
2113 | triggers |= TRIG_FOLLOW; |
2114 | err |= comedi_check_trigger_src(src: &cmd->scan_begin_src, flags: triggers); |
2115 | |
2116 | triggers = TRIG_TIMER; |
2117 | if (board->layout == LAYOUT_4020) |
2118 | triggers |= TRIG_NOW; |
2119 | else |
2120 | triggers |= TRIG_EXT; |
2121 | err |= comedi_check_trigger_src(src: &cmd->convert_src, flags: triggers); |
2122 | err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT); |
2123 | err |= comedi_check_trigger_src(src: &cmd->stop_src, |
2124 | TRIG_COUNT | TRIG_EXT | TRIG_NONE); |
2125 | |
2126 | if (err) |
2127 | return 1; |
2128 | |
2129 | /* Step 2a : make sure trigger sources are unique */ |
2130 | |
2131 | err |= comedi_check_trigger_is_unique(src: cmd->start_src); |
2132 | err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src); |
2133 | err |= comedi_check_trigger_is_unique(src: cmd->convert_src); |
2134 | err |= comedi_check_trigger_is_unique(src: cmd->stop_src); |
2135 | |
2136 | /* Step 2b : and mutually compatible */ |
2137 | |
2138 | if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) |
2139 | err |= -EINVAL; |
2140 | |
2141 | if (err) |
2142 | return 2; |
2143 | |
2144 | /* Step 3: check if arguments are trivially valid */ |
2145 | |
2146 | switch (cmd->start_src) { |
2147 | case TRIG_NOW: |
2148 | err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0); |
2149 | break; |
2150 | case TRIG_EXT: |
2151 | /* |
2152 | * start_arg is the CR_CHAN | CR_INVERT of the |
2153 | * external trigger. |
2154 | */ |
2155 | break; |
2156 | } |
2157 | |
2158 | if (cmd->convert_src == TRIG_TIMER) { |
2159 | if (board->layout == LAYOUT_4020) { |
2160 | err |= comedi_check_trigger_arg_is(arg: &cmd->convert_arg, |
2161 | val: 0); |
2162 | } else { |
2163 | err |= comedi_check_trigger_arg_min(arg: &cmd->convert_arg, |
2164 | val: board->ai_speed); |
2165 | /* |
2166 | * if scans are timed faster than conversion rate |
2167 | * allows |
2168 | */ |
2169 | if (cmd->scan_begin_src == TRIG_TIMER) { |
2170 | err |= comedi_check_trigger_arg_min( |
2171 | arg: &cmd->scan_begin_arg, |
2172 | val: cmd->convert_arg * |
2173 | cmd->chanlist_len); |
2174 | } |
2175 | } |
2176 | } |
2177 | |
2178 | err |= comedi_check_trigger_arg_min(arg: &cmd->chanlist_len, val: 1); |
2179 | err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg, |
2180 | val: cmd->chanlist_len); |
2181 | |
2182 | switch (cmd->stop_src) { |
2183 | case TRIG_EXT: |
2184 | break; |
2185 | case TRIG_COUNT: |
2186 | err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1); |
2187 | break; |
2188 | case TRIG_NONE: |
2189 | err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0); |
2190 | break; |
2191 | default: |
2192 | break; |
2193 | } |
2194 | |
2195 | if (err) |
2196 | return 3; |
2197 | |
2198 | /* step 4: fix up any arguments */ |
2199 | |
2200 | if (cmd->convert_src == TRIG_TIMER) { |
2201 | tmp_arg = cmd->convert_arg; |
2202 | tmp_arg2 = cmd->scan_begin_arg; |
2203 | check_adc_timing(dev, cmd); |
2204 | if (tmp_arg != cmd->convert_arg) |
2205 | err++; |
2206 | if (tmp_arg2 != cmd->scan_begin_arg) |
2207 | err++; |
2208 | } |
2209 | |
2210 | if (err) |
2211 | return 4; |
2212 | |
2213 | /* Step 5: check channel list if it exists */ |
2214 | if (cmd->chanlist && cmd->chanlist_len > 0) |
2215 | err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd); |
2216 | |
2217 | if (err) |
2218 | return 5; |
2219 | |
2220 | return 0; |
2221 | } |
2222 | |
2223 | static int use_hw_sample_counter(struct comedi_cmd *cmd) |
2224 | { |
2225 | /* disable for now until I work out a race */ |
2226 | return 0; |
2227 | |
2228 | if (cmd->stop_src == TRIG_COUNT && cmd->stop_arg <= max_counter_value) |
2229 | return 1; |
2230 | |
2231 | return 0; |
2232 | } |
2233 | |
2234 | static void setup_sample_counters(struct comedi_device *dev, |
2235 | struct comedi_cmd *cmd) |
2236 | { |
2237 | struct pcidas64_private *devpriv = dev->private; |
2238 | |
2239 | /* load hardware conversion counter */ |
2240 | if (use_hw_sample_counter(cmd)) { |
2241 | writew(val: cmd->stop_arg & 0xffff, |
2242 | addr: devpriv->main_iobase + ADC_COUNT_LOWER_REG); |
2243 | writew(val: (cmd->stop_arg >> 16) & 0xff, |
2244 | addr: devpriv->main_iobase + ADC_COUNT_UPPER_REG); |
2245 | } else { |
2246 | writew(val: 1, addr: devpriv->main_iobase + ADC_COUNT_LOWER_REG); |
2247 | } |
2248 | } |
2249 | |
2250 | static inline unsigned int dma_transfer_size(struct comedi_device *dev) |
2251 | { |
2252 | const struct pcidas64_board *board = dev->board_ptr; |
2253 | struct pcidas64_private *devpriv = dev->private; |
2254 | unsigned int num_samples; |
2255 | |
2256 | num_samples = devpriv->ai_fifo_segment_length * |
2257 | board->ai_fifo->sample_packing_ratio; |
2258 | if (num_samples > DMA_BUFFER_SIZE / sizeof(u16)) |
2259 | num_samples = DMA_BUFFER_SIZE / sizeof(u16); |
2260 | |
2261 | return num_samples; |
2262 | } |
2263 | |
2264 | static u32 ai_convert_counter_6xxx(const struct comedi_device *dev, |
2265 | const struct comedi_cmd *cmd) |
2266 | { |
2267 | /* supposed to load counter with desired divisor minus 3 */ |
2268 | return cmd->convert_arg / TIMER_BASE - 3; |
2269 | } |
2270 | |
2271 | static u32 ai_scan_counter_6xxx(struct comedi_device *dev, |
2272 | struct comedi_cmd *cmd) |
2273 | { |
2274 | u32 count; |
2275 | |
2276 | /* figure out how long we need to delay at end of scan */ |
2277 | switch (cmd->scan_begin_src) { |
2278 | case TRIG_TIMER: |
2279 | count = (cmd->scan_begin_arg - |
2280 | (cmd->convert_arg * (cmd->chanlist_len - 1))) / |
2281 | TIMER_BASE; |
2282 | break; |
2283 | case TRIG_FOLLOW: |
2284 | count = cmd->convert_arg / TIMER_BASE; |
2285 | break; |
2286 | default: |
2287 | return 0; |
2288 | } |
2289 | return count - 3; |
2290 | } |
2291 | |
2292 | static u32 ai_convert_counter_4020(struct comedi_device *dev, |
2293 | struct comedi_cmd *cmd) |
2294 | { |
2295 | struct pcidas64_private *devpriv = dev->private; |
2296 | unsigned int divisor; |
2297 | |
2298 | switch (cmd->scan_begin_src) { |
2299 | case TRIG_TIMER: |
2300 | divisor = cmd->scan_begin_arg / TIMER_BASE; |
2301 | break; |
2302 | case TRIG_OTHER: |
2303 | divisor = devpriv->ext_clock.divisor; |
2304 | break; |
2305 | default: /* should never happen */ |
2306 | dev_err(dev->class_dev, "bug! failed to set ai pacing!\n" ); |
2307 | divisor = 1000; |
2308 | break; |
2309 | } |
2310 | |
2311 | /* supposed to load counter with desired divisor minus 2 for 4020 */ |
2312 | return divisor - 2; |
2313 | } |
2314 | |
2315 | static void select_master_clock_4020(struct comedi_device *dev, |
2316 | const struct comedi_cmd *cmd) |
2317 | { |
2318 | struct pcidas64_private *devpriv = dev->private; |
2319 | |
2320 | /* select internal/external master clock */ |
2321 | devpriv->hw_config_bits &= ~MASTER_CLOCK_4020_MASK; |
2322 | if (cmd->scan_begin_src == TRIG_OTHER) { |
2323 | int chanspec = devpriv->ext_clock.chanspec; |
2324 | |
2325 | if (CR_CHAN(chanspec)) |
2326 | devpriv->hw_config_bits |= BNC_CLOCK_4020_BITS; |
2327 | else |
2328 | devpriv->hw_config_bits |= EXT_CLOCK_4020_BITS; |
2329 | } else { |
2330 | devpriv->hw_config_bits |= INTERNAL_CLOCK_4020_BITS; |
2331 | } |
2332 | writew(val: devpriv->hw_config_bits, |
2333 | addr: devpriv->main_iobase + HW_CONFIG_REG); |
2334 | } |
2335 | |
2336 | static void select_master_clock(struct comedi_device *dev, |
2337 | const struct comedi_cmd *cmd) |
2338 | { |
2339 | const struct pcidas64_board *board = dev->board_ptr; |
2340 | |
2341 | switch (board->layout) { |
2342 | case LAYOUT_4020: |
2343 | select_master_clock_4020(dev, cmd); |
2344 | break; |
2345 | default: |
2346 | break; |
2347 | } |
2348 | } |
2349 | |
2350 | static inline void dma_start_sync(struct comedi_device *dev, |
2351 | unsigned int channel) |
2352 | { |
2353 | struct pcidas64_private *devpriv = dev->private; |
2354 | unsigned long flags; |
2355 | |
2356 | /* spinlock for plx dma control/status reg */ |
2357 | spin_lock_irqsave(&dev->spinlock, flags); |
2358 | writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_START | PLX_DMACSR_CLEARINTR, |
2359 | addr: devpriv->plx9080_iobase + PLX_REG_DMACSR(channel)); |
2360 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2361 | } |
2362 | |
2363 | static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) |
2364 | { |
2365 | const struct pcidas64_board *board = dev->board_ptr; |
2366 | struct pcidas64_private *devpriv = dev->private; |
2367 | u32 convert_counter = 0, scan_counter = 0; |
2368 | |
2369 | check_adc_timing(dev, cmd); |
2370 | |
2371 | select_master_clock(dev, cmd); |
2372 | |
2373 | if (board->layout == LAYOUT_4020) { |
2374 | convert_counter = ai_convert_counter_4020(dev, cmd); |
2375 | } else { |
2376 | convert_counter = ai_convert_counter_6xxx(dev, cmd); |
2377 | scan_counter = ai_scan_counter_6xxx(dev, cmd); |
2378 | } |
2379 | |
2380 | /* load lower 16 bits of convert interval */ |
2381 | writew(val: convert_counter & 0xffff, |
2382 | addr: devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); |
2383 | /* load upper 8 bits of convert interval */ |
2384 | writew(val: (convert_counter >> 16) & 0xff, |
2385 | addr: devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); |
2386 | /* load lower 16 bits of scan delay */ |
2387 | writew(val: scan_counter & 0xffff, |
2388 | addr: devpriv->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG); |
2389 | /* load upper 8 bits of scan delay */ |
2390 | writew(val: (scan_counter >> 16) & 0xff, |
2391 | addr: devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); |
2392 | } |
2393 | |
2394 | static int use_internal_queue_6xxx(const struct comedi_cmd *cmd) |
2395 | { |
2396 | int i; |
2397 | |
2398 | for (i = 0; i + 1 < cmd->chanlist_len; i++) { |
2399 | if (CR_CHAN(cmd->chanlist[i + 1]) != |
2400 | CR_CHAN(cmd->chanlist[i]) + 1) |
2401 | return 0; |
2402 | if (CR_RANGE(cmd->chanlist[i + 1]) != |
2403 | CR_RANGE(cmd->chanlist[i])) |
2404 | return 0; |
2405 | if (CR_AREF(cmd->chanlist[i + 1]) != CR_AREF(cmd->chanlist[i])) |
2406 | return 0; |
2407 | } |
2408 | return 1; |
2409 | } |
2410 | |
2411 | static int setup_channel_queue(struct comedi_device *dev, |
2412 | const struct comedi_cmd *cmd) |
2413 | { |
2414 | const struct pcidas64_board *board = dev->board_ptr; |
2415 | struct pcidas64_private *devpriv = dev->private; |
2416 | unsigned short bits; |
2417 | int i; |
2418 | |
2419 | if (board->layout != LAYOUT_4020) { |
2420 | if (use_internal_queue_6xxx(cmd)) { |
2421 | devpriv->hw_config_bits &= ~EXT_QUEUE_BIT; |
2422 | writew(val: devpriv->hw_config_bits, |
2423 | addr: devpriv->main_iobase + HW_CONFIG_REG); |
2424 | bits = 0; |
2425 | /* set channel */ |
2426 | bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[0])); |
2427 | /* set gain */ |
2428 | bits |= ai_range_bits_6xxx(dev, |
2429 | CR_RANGE(cmd->chanlist[0])); |
2430 | /* set single-ended / differential */ |
2431 | bits |= se_diff_bit_6xxx(dev, |
2432 | CR_AREF(cmd->chanlist[0]) == |
2433 | AREF_DIFF); |
2434 | if (CR_AREF(cmd->chanlist[0]) == AREF_COMMON) |
2435 | bits |= ADC_COMMON_BIT; |
2436 | /* set stop channel */ |
2437 | writew(val: adc_chan_bits |
2438 | (CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])), |
2439 | addr: devpriv->main_iobase + ADC_QUEUE_HIGH_REG); |
2440 | /* set start channel, and rest of settings */ |
2441 | writew(val: bits, |
2442 | addr: devpriv->main_iobase + ADC_QUEUE_LOAD_REG); |
2443 | } else { |
2444 | /* use external queue */ |
2445 | if (dev->write_subdev && dev->write_subdev->busy) { |
2446 | warn_external_queue(dev); |
2447 | return -EBUSY; |
2448 | } |
2449 | devpriv->hw_config_bits |= EXT_QUEUE_BIT; |
2450 | writew(val: devpriv->hw_config_bits, |
2451 | addr: devpriv->main_iobase + HW_CONFIG_REG); |
2452 | /* clear DAC buffer to prevent weird interactions */ |
2453 | writew(val: 0, |
2454 | addr: devpriv->main_iobase + DAC_BUFFER_CLEAR_REG); |
2455 | /* clear queue pointer */ |
2456 | writew(val: 0, addr: devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); |
2457 | /* load external queue */ |
2458 | for (i = 0; i < cmd->chanlist_len; i++) { |
2459 | unsigned int chanspec = cmd->chanlist[i]; |
2460 | int use_differential; |
2461 | |
2462 | bits = 0; |
2463 | /* set channel */ |
2464 | bits |= adc_chan_bits(CR_CHAN(chanspec)); |
2465 | /* set gain */ |
2466 | bits |= ai_range_bits_6xxx(dev, |
2467 | CR_RANGE(chanspec)); |
2468 | /* set single-ended / differential */ |
2469 | use_differential = 0; |
2470 | if (CR_AREF(chanspec) == AREF_DIFF) |
2471 | use_differential = 1; |
2472 | bits |= se_diff_bit_6xxx(dev, use_differential); |
2473 | |
2474 | if (CR_AREF(cmd->chanlist[i]) == AREF_COMMON) |
2475 | bits |= ADC_COMMON_BIT; |
2476 | /* mark end of queue */ |
2477 | if (i == cmd->chanlist_len - 1) |
2478 | bits |= QUEUE_EOSCAN_BIT | |
2479 | QUEUE_EOSEQ_BIT; |
2480 | writew(val: bits, |
2481 | addr: devpriv->main_iobase + |
2482 | ADC_QUEUE_FIFO_REG); |
2483 | } |
2484 | /* |
2485 | * doing a queue clear is not specified in board docs, |
2486 | * but required for reliable operation |
2487 | */ |
2488 | writew(val: 0, addr: devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); |
2489 | /* prime queue holding register */ |
2490 | writew(val: 0, addr: devpriv->main_iobase + ADC_QUEUE_LOAD_REG); |
2491 | } |
2492 | } else { |
2493 | unsigned short old_cal_range_bits = devpriv->i2c_cal_range_bits; |
2494 | |
2495 | devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; |
2496 | /* select BNC inputs */ |
2497 | devpriv->i2c_cal_range_bits |= adc_src_4020_bits(source: 4); |
2498 | /* select ranges */ |
2499 | for (i = 0; i < cmd->chanlist_len; i++) { |
2500 | unsigned int channel = CR_CHAN(cmd->chanlist[i]); |
2501 | unsigned int range = CR_RANGE(cmd->chanlist[i]); |
2502 | |
2503 | if (range == 0) |
2504 | devpriv->i2c_cal_range_bits |= |
2505 | attenuate_bit(channel); |
2506 | else |
2507 | devpriv->i2c_cal_range_bits &= |
2508 | ~attenuate_bit(channel); |
2509 | } |
2510 | /* |
2511 | * update calibration/range i2c register only if necessary, |
2512 | * as it is very slow |
2513 | */ |
2514 | if (old_cal_range_bits != devpriv->i2c_cal_range_bits) { |
2515 | u8 i2c_data = devpriv->i2c_cal_range_bits; |
2516 | |
2517 | i2c_write(dev, address: RANGE_CAL_I2C_ADDR, data: &i2c_data, |
2518 | length: sizeof(i2c_data)); |
2519 | } |
2520 | } |
2521 | return 0; |
2522 | } |
2523 | |
2524 | static inline void load_first_dma_descriptor(struct comedi_device *dev, |
2525 | unsigned int dma_channel, |
2526 | unsigned int descriptor_bits) |
2527 | { |
2528 | struct pcidas64_private *devpriv = dev->private; |
2529 | |
2530 | /* |
2531 | * The transfer size, pci address, and local address registers |
2532 | * are supposedly unused during chained dma, |
2533 | * but I have found that left over values from last operation |
2534 | * occasionally cause problems with transfer of first dma |
2535 | * block. Initializing them to zero seems to fix the problem. |
2536 | */ |
2537 | if (dma_channel) { |
2538 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMASIZ1); |
2539 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMAPADR1); |
2540 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMALADR1); |
2541 | writel(val: descriptor_bits, |
2542 | addr: devpriv->plx9080_iobase + PLX_REG_DMADPR1); |
2543 | } else { |
2544 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMASIZ0); |
2545 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMAPADR0); |
2546 | writel(val: 0, addr: devpriv->plx9080_iobase + PLX_REG_DMALADR0); |
2547 | writel(val: descriptor_bits, |
2548 | addr: devpriv->plx9080_iobase + PLX_REG_DMADPR0); |
2549 | } |
2550 | } |
2551 | |
2552 | static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) |
2553 | { |
2554 | const struct pcidas64_board *board = dev->board_ptr; |
2555 | struct pcidas64_private *devpriv = dev->private; |
2556 | struct comedi_async *async = s->async; |
2557 | struct comedi_cmd *cmd = &async->cmd; |
2558 | u32 bits; |
2559 | unsigned int i; |
2560 | unsigned long flags; |
2561 | int retval; |
2562 | |
2563 | disable_ai_pacing(dev); |
2564 | abort_dma(dev, channel: 1); |
2565 | |
2566 | retval = setup_channel_queue(dev, cmd); |
2567 | if (retval < 0) |
2568 | return retval; |
2569 | |
2570 | /* make sure internal calibration source is turned off */ |
2571 | writew(val: 0, addr: devpriv->main_iobase + CALIBRATION_REG); |
2572 | |
2573 | set_ai_pacing(dev, cmd); |
2574 | |
2575 | setup_sample_counters(dev, cmd); |
2576 | |
2577 | enable_ai_interrupts(dev, cmd); |
2578 | |
2579 | spin_lock_irqsave(&dev->spinlock, flags); |
2580 | /* set mode, allow conversions through software gate */ |
2581 | devpriv->adc_control1_bits |= ADC_SW_GATE_BIT; |
2582 | devpriv->adc_control1_bits &= ~ADC_DITHER_BIT; |
2583 | if (board->layout != LAYOUT_4020) { |
2584 | devpriv->adc_control1_bits &= ~ADC_MODE_MASK; |
2585 | if (cmd->convert_src == TRIG_EXT) |
2586 | /* good old mode 13 */ |
2587 | devpriv->adc_control1_bits |= adc_mode_bits(mode: 13); |
2588 | else |
2589 | /* mode 8. What else could you need? */ |
2590 | devpriv->adc_control1_bits |= adc_mode_bits(mode: 8); |
2591 | } else { |
2592 | devpriv->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK; |
2593 | if (cmd->chanlist_len == 4) |
2594 | devpriv->adc_control1_bits |= FOUR_CHANNEL_4020_BITS; |
2595 | else if (cmd->chanlist_len == 2) |
2596 | devpriv->adc_control1_bits |= TWO_CHANNEL_4020_BITS; |
2597 | devpriv->adc_control1_bits &= ~ADC_LO_CHANNEL_4020_MASK; |
2598 | devpriv->adc_control1_bits |= |
2599 | adc_lo_chan_4020_bits(CR_CHAN(cmd->chanlist[0])); |
2600 | devpriv->adc_control1_bits &= ~ADC_HI_CHANNEL_4020_MASK; |
2601 | devpriv->adc_control1_bits |= |
2602 | adc_hi_chan_4020_bits(CR_CHAN(cmd->chanlist |
2603 | [cmd->chanlist_len - 1])); |
2604 | } |
2605 | writew(val: devpriv->adc_control1_bits, |
2606 | addr: devpriv->main_iobase + ADC_CONTROL1_REG); |
2607 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2608 | |
2609 | /* clear adc buffer */ |
2610 | writew(val: 0, addr: devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); |
2611 | |
2612 | if ((cmd->flags & CMDF_WAKE_EOS) == 0 || |
2613 | board->layout == LAYOUT_4020) { |
2614 | devpriv->ai_dma_index = 0; |
2615 | |
2616 | /* set dma transfer size */ |
2617 | for (i = 0; i < ai_dma_ring_count(board); i++) |
2618 | devpriv->ai_dma_desc[i].transfer_size = |
2619 | cpu_to_le32(dma_transfer_size(dev) * |
2620 | sizeof(u16)); |
2621 | |
2622 | /* give location of first dma descriptor */ |
2623 | load_first_dma_descriptor(dev, dma_channel: 1, |
2624 | descriptor_bits: devpriv->ai_dma_desc_bus_addr | |
2625 | PLX_DMADPR_DESCPCI | |
2626 | PLX_DMADPR_TCINTR | |
2627 | PLX_DMADPR_XFERL2P); |
2628 | |
2629 | dma_start_sync(dev, channel: 1); |
2630 | } |
2631 | |
2632 | if (board->layout == LAYOUT_4020) { |
2633 | /* set source for external triggers */ |
2634 | bits = 0; |
2635 | if (cmd->start_src == TRIG_EXT && CR_CHAN(cmd->start_arg)) |
2636 | bits |= EXT_START_TRIG_BNC_BIT; |
2637 | if (cmd->stop_src == TRIG_EXT && CR_CHAN(cmd->stop_arg)) |
2638 | bits |= EXT_STOP_TRIG_BNC_BIT; |
2639 | writew(val: bits, addr: devpriv->main_iobase + DAQ_ATRIG_LOW_4020_REG); |
2640 | } |
2641 | |
2642 | spin_lock_irqsave(&dev->spinlock, flags); |
2643 | |
2644 | /* enable pacing, triggering, etc */ |
2645 | bits = ADC_ENABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT; |
2646 | if (cmd->flags & CMDF_WAKE_EOS) |
2647 | bits |= ADC_DMA_DISABLE_BIT; |
2648 | /* set start trigger */ |
2649 | if (cmd->start_src == TRIG_EXT) { |
2650 | bits |= ADC_START_TRIG_EXT_BITS; |
2651 | if (cmd->start_arg & CR_INVERT) |
2652 | bits |= ADC_START_TRIG_FALLING_BIT; |
2653 | } else if (cmd->start_src == TRIG_NOW) { |
2654 | bits |= ADC_START_TRIG_SOFT_BITS; |
2655 | } |
2656 | if (use_hw_sample_counter(cmd)) |
2657 | bits |= ADC_SAMPLE_COUNTER_EN_BIT; |
2658 | writew(val: bits, addr: devpriv->main_iobase + ADC_CONTROL0_REG); |
2659 | |
2660 | devpriv->ai_cmd_running = 1; |
2661 | |
2662 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2663 | |
2664 | /* start acquisition */ |
2665 | if (cmd->start_src == TRIG_NOW) |
2666 | writew(val: 0, addr: devpriv->main_iobase + ADC_START_REG); |
2667 | |
2668 | return 0; |
2669 | } |
2670 | |
2671 | /* read num_samples from 16 bit wide ai fifo */ |
2672 | static void pio_drain_ai_fifo_16(struct comedi_device *dev) |
2673 | { |
2674 | struct pcidas64_private *devpriv = dev->private; |
2675 | struct comedi_subdevice *s = dev->read_subdev; |
2676 | unsigned int i; |
2677 | u16 prepost_bits; |
2678 | int read_segment, read_index, write_segment, write_index; |
2679 | int num_samples; |
2680 | |
2681 | do { |
2682 | /* get least significant 15 bits */ |
2683 | read_index = readw(addr: devpriv->main_iobase + ADC_READ_PNTR_REG) & |
2684 | 0x7fff; |
2685 | write_index = readw(addr: devpriv->main_iobase + ADC_WRITE_PNTR_REG) & |
2686 | 0x7fff; |
2687 | /* |
2688 | * Get most significant bits (grey code). |
2689 | * Different boards use different code so use a scheme |
2690 | * that doesn't depend on encoding. This read must |
2691 | * occur after reading least significant 15 bits to avoid race |
2692 | * with fifo switching to next segment. |
2693 | */ |
2694 | prepost_bits = readw(addr: devpriv->main_iobase + PREPOST_REG); |
2695 | |
2696 | /* |
2697 | * if read and write pointers are not on the same fifo segment, |
2698 | * read to the end of the read segment |
2699 | */ |
2700 | read_segment = adc_upper_read_ptr_code(prepost_bits); |
2701 | write_segment = adc_upper_write_ptr_code(prepost_bits); |
2702 | |
2703 | if (read_segment != write_segment) |
2704 | num_samples = |
2705 | devpriv->ai_fifo_segment_length - read_index; |
2706 | else |
2707 | num_samples = write_index - read_index; |
2708 | if (num_samples < 0) { |
2709 | dev_err(dev->class_dev, |
2710 | "cb_pcidas64: bug! num_samples < 0\n" ); |
2711 | break; |
2712 | } |
2713 | |
2714 | num_samples = comedi_nsamples_left(s, nsamples: num_samples); |
2715 | if (num_samples == 0) |
2716 | break; |
2717 | |
2718 | for (i = 0; i < num_samples; i++) { |
2719 | unsigned short val; |
2720 | |
2721 | val = readw(addr: devpriv->main_iobase + ADC_FIFO_REG); |
2722 | comedi_buf_write_samples(s, data: &val, nsamples: 1); |
2723 | } |
2724 | |
2725 | } while (read_segment != write_segment); |
2726 | } |
2727 | |
2728 | /* |
2729 | * Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of |
2730 | * pointers. The pci-4020 hardware only supports dma transfers (it only |
2731 | * supports the use of pio for draining the last remaining points from the |
2732 | * fifo when a data acquisition operation has completed). |
2733 | */ |
2734 | static void pio_drain_ai_fifo_32(struct comedi_device *dev) |
2735 | { |
2736 | struct pcidas64_private *devpriv = dev->private; |
2737 | struct comedi_subdevice *s = dev->read_subdev; |
2738 | unsigned int nsamples; |
2739 | unsigned int i; |
2740 | u32 fifo_data; |
2741 | int write_code = |
2742 | readw(addr: devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff; |
2743 | int read_code = |
2744 | readw(addr: devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; |
2745 | |
2746 | nsamples = comedi_nsamples_left(s, nsamples: 100000); |
2747 | for (i = 0; read_code != write_code && i < nsamples;) { |
2748 | unsigned short val; |
2749 | |
2750 | fifo_data = readl(addr: dev->mmio + ADC_FIFO_REG); |
2751 | val = fifo_data & 0xffff; |
2752 | comedi_buf_write_samples(s, data: &val, nsamples: 1); |
2753 | i++; |
2754 | if (i < nsamples) { |
2755 | val = (fifo_data >> 16) & 0xffff; |
2756 | comedi_buf_write_samples(s, data: &val, nsamples: 1); |
2757 | i++; |
2758 | } |
2759 | read_code = readw(addr: devpriv->main_iobase + ADC_READ_PNTR_REG) & |
2760 | 0x7fff; |
2761 | } |
2762 | } |
2763 | |
2764 | /* empty fifo */ |
2765 | static void pio_drain_ai_fifo(struct comedi_device *dev) |
2766 | { |
2767 | const struct pcidas64_board *board = dev->board_ptr; |
2768 | |
2769 | if (board->layout == LAYOUT_4020) |
2770 | pio_drain_ai_fifo_32(dev); |
2771 | else |
2772 | pio_drain_ai_fifo_16(dev); |
2773 | } |
2774 | |
2775 | static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) |
2776 | { |
2777 | const struct pcidas64_board *board = dev->board_ptr; |
2778 | struct pcidas64_private *devpriv = dev->private; |
2779 | struct comedi_subdevice *s = dev->read_subdev; |
2780 | u32 next_transfer_addr; |
2781 | int j; |
2782 | int num_samples = 0; |
2783 | void __iomem *pci_addr_reg; |
2784 | |
2785 | pci_addr_reg = devpriv->plx9080_iobase + PLX_REG_DMAPADR(channel); |
2786 | |
2787 | /* loop until we have read all the full buffers */ |
2788 | for (j = 0, next_transfer_addr = readl(addr: pci_addr_reg); |
2789 | (next_transfer_addr < |
2790 | devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] || |
2791 | next_transfer_addr >= |
2792 | devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] + |
2793 | DMA_BUFFER_SIZE) && j < ai_dma_ring_count(board); j++) { |
2794 | /* transfer data from dma buffer to comedi buffer */ |
2795 | num_samples = comedi_nsamples_left(s, nsamples: dma_transfer_size(dev)); |
2796 | comedi_buf_write_samples(s, |
2797 | data: devpriv->ai_buffer[devpriv->ai_dma_index], |
2798 | nsamples: num_samples); |
2799 | devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) % |
2800 | ai_dma_ring_count(board); |
2801 | } |
2802 | /* |
2803 | * XXX check for dma ring buffer overrun |
2804 | * (use end-of-chain bit to mark last unused buffer) |
2805 | */ |
2806 | } |
2807 | |
2808 | static void handle_ai_interrupt(struct comedi_device *dev, |
2809 | unsigned short status, |
2810 | unsigned int plx_status) |
2811 | { |
2812 | const struct pcidas64_board *board = dev->board_ptr; |
2813 | struct pcidas64_private *devpriv = dev->private; |
2814 | struct comedi_subdevice *s = dev->read_subdev; |
2815 | struct comedi_async *async = s->async; |
2816 | struct comedi_cmd *cmd = &async->cmd; |
2817 | u8 dma1_status; |
2818 | unsigned long flags; |
2819 | |
2820 | /* check for fifo overrun */ |
2821 | if (status & ADC_OVERRUN_BIT) { |
2822 | dev_err(dev->class_dev, "fifo overrun\n" ); |
2823 | async->events |= COMEDI_CB_ERROR; |
2824 | } |
2825 | /* spin lock makes sure no one else changes plx dma control reg */ |
2826 | spin_lock_irqsave(&dev->spinlock, flags); |
2827 | dma1_status = readb(addr: devpriv->plx9080_iobase + PLX_REG_DMACSR1); |
2828 | if (plx_status & PLX_INTCSR_DMA1IA) { /* dma chan 1 interrupt */ |
2829 | writeb(val: (dma1_status & PLX_DMACSR_ENABLE) | PLX_DMACSR_CLEARINTR, |
2830 | addr: devpriv->plx9080_iobase + PLX_REG_DMACSR1); |
2831 | |
2832 | if (dma1_status & PLX_DMACSR_ENABLE) |
2833 | drain_dma_buffers(dev, channel: 1); |
2834 | } |
2835 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2836 | |
2837 | /* drain fifo with pio */ |
2838 | if ((status & ADC_DONE_BIT) || |
2839 | ((cmd->flags & CMDF_WAKE_EOS) && |
2840 | (status & ADC_INTR_PENDING_BIT) && |
2841 | (board->layout != LAYOUT_4020))) { |
2842 | spin_lock_irqsave(&dev->spinlock, flags); |
2843 | if (devpriv->ai_cmd_running) { |
2844 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2845 | pio_drain_ai_fifo(dev); |
2846 | } else { |
2847 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
2848 | } |
2849 | } |
2850 | /* if we are have all the data, then quit */ |
2851 | if ((cmd->stop_src == TRIG_COUNT && |
2852 | async->scans_done >= cmd->stop_arg) || |
2853 | (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) |
2854 | async->events |= COMEDI_CB_EOA; |
2855 | |
2856 | comedi_handle_events(dev, s); |
2857 | } |
2858 | |
2859 | static inline unsigned int prev_ao_dma_index(struct comedi_device *dev) |
2860 | { |
2861 | struct pcidas64_private *devpriv = dev->private; |
2862 | unsigned int buffer_index; |
2863 | |
2864 | if (devpriv->ao_dma_index == 0) |
2865 | buffer_index = AO_DMA_RING_COUNT - 1; |
2866 | else |
2867 | buffer_index = devpriv->ao_dma_index - 1; |
2868 | return buffer_index; |
2869 | } |
2870 | |
2871 | static int last_ao_dma_load_completed(struct comedi_device *dev) |
2872 | { |
2873 | struct pcidas64_private *devpriv = dev->private; |
2874 | unsigned int buffer_index; |
2875 | unsigned int transfer_address; |
2876 | unsigned short dma_status; |
2877 | |
2878 | buffer_index = prev_ao_dma_index(dev); |
2879 | dma_status = readb(addr: devpriv->plx9080_iobase + PLX_REG_DMACSR0); |
2880 | if ((dma_status & PLX_DMACSR_DONE) == 0) |
2881 | return 0; |
2882 | |
2883 | transfer_address = |
2884 | readl(addr: devpriv->plx9080_iobase + PLX_REG_DMAPADR0); |
2885 | if (transfer_address != devpriv->ao_buffer_bus_addr[buffer_index]) |
2886 | return 0; |
2887 | |
2888 | return 1; |
2889 | } |
2890 | |
2891 | static inline int ao_dma_needs_restart(struct comedi_device *dev, |
2892 | unsigned short dma_status) |
2893 | { |
2894 | if ((dma_status & PLX_DMACSR_DONE) == 0 || |
2895 | (dma_status & PLX_DMACSR_ENABLE) == 0) |
2896 | return 0; |
2897 | if (last_ao_dma_load_completed(dev)) |
2898 | return 0; |
2899 | |
2900 | return 1; |
2901 | } |
2902 | |
2903 | static void restart_ao_dma(struct comedi_device *dev) |
2904 | { |
2905 | struct pcidas64_private *devpriv = dev->private; |
2906 | unsigned int dma_desc_bits; |
2907 | |
2908 | dma_desc_bits = readl(addr: devpriv->plx9080_iobase + PLX_REG_DMADPR0); |
2909 | dma_desc_bits &= ~PLX_DMADPR_CHAINEND; |
2910 | load_first_dma_descriptor(dev, dma_channel: 0, descriptor_bits: dma_desc_bits); |
2911 | |
2912 | dma_start_sync(dev, channel: 0); |
2913 | } |
2914 | |
2915 | static unsigned int cb_pcidas64_ao_fill_buffer(struct comedi_device *dev, |
2916 | struct comedi_subdevice *s, |
2917 | unsigned short *dest, |
2918 | unsigned int max_bytes) |
2919 | { |
2920 | unsigned int nsamples = comedi_bytes_to_samples(s, nbytes: max_bytes); |
2921 | unsigned int actual_bytes; |
2922 | |
2923 | nsamples = comedi_nsamples_left(s, nsamples); |
2924 | actual_bytes = comedi_buf_read_samples(s, data: dest, nsamples); |
2925 | |
2926 | return comedi_bytes_to_samples(s, nbytes: actual_bytes); |
2927 | } |
2928 | |
2929 | static unsigned int load_ao_dma_buffer(struct comedi_device *dev, |
2930 | const struct comedi_cmd *cmd) |
2931 | { |
2932 | struct pcidas64_private *devpriv = dev->private; |
2933 | struct comedi_subdevice *s = dev->write_subdev; |
2934 | unsigned int buffer_index = devpriv->ao_dma_index; |
2935 | unsigned int prev_buffer_index = prev_ao_dma_index(dev); |
2936 | unsigned int nsamples; |
2937 | unsigned int nbytes; |
2938 | unsigned int next_bits; |
2939 | |
2940 | nsamples = cb_pcidas64_ao_fill_buffer(dev, s, |
2941 | dest: devpriv->ao_buffer[buffer_index], |
2942 | DMA_BUFFER_SIZE); |
2943 | if (nsamples == 0) |
2944 | return 0; |
2945 | |
2946 | nbytes = comedi_samples_to_bytes(s, nsamples); |
2947 | devpriv->ao_dma_desc[buffer_index].transfer_size = cpu_to_le32(nbytes); |
2948 | /* set end of chain bit so we catch underruns */ |
2949 | next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next); |
2950 | next_bits |= PLX_DMADPR_CHAINEND; |
2951 | devpriv->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits); |
2952 | /* |
2953 | * clear end of chain bit on previous buffer now that we have set it |
2954 | * for the last buffer |
2955 | */ |
2956 | next_bits = le32_to_cpu(devpriv->ao_dma_desc[prev_buffer_index].next); |
2957 | next_bits &= ~PLX_DMADPR_CHAINEND; |
2958 | devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits); |
2959 | |
2960 | devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT; |
2961 | |
2962 | return nbytes; |
2963 | } |
2964 | |
2965 | static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) |
2966 | { |
2967 | struct pcidas64_private *devpriv = dev->private; |
2968 | unsigned int num_bytes; |
2969 | unsigned int next_transfer_addr; |
2970 | void __iomem *pci_addr_reg = devpriv->plx9080_iobase + PLX_REG_DMAPADR0; |
2971 | unsigned int buffer_index; |
2972 | |
2973 | do { |
2974 | buffer_index = devpriv->ao_dma_index; |
2975 | /* don't overwrite data that hasn't been transferred yet */ |
2976 | next_transfer_addr = readl(addr: pci_addr_reg); |
2977 | if (next_transfer_addr >= |
2978 | devpriv->ao_buffer_bus_addr[buffer_index] && |
2979 | next_transfer_addr < |
2980 | devpriv->ao_buffer_bus_addr[buffer_index] + |
2981 | DMA_BUFFER_SIZE) |
2982 | return; |
2983 | num_bytes = load_ao_dma_buffer(dev, cmd); |
2984 | } while (num_bytes >= DMA_BUFFER_SIZE); |
2985 | } |
2986 | |
2987 | static void handle_ao_interrupt(struct comedi_device *dev, |
2988 | unsigned short status, unsigned int plx_status) |
2989 | { |
2990 | struct pcidas64_private *devpriv = dev->private; |
2991 | struct comedi_subdevice *s = dev->write_subdev; |
2992 | struct comedi_async *async; |
2993 | struct comedi_cmd *cmd; |
2994 | u8 dma0_status; |
2995 | unsigned long flags; |
2996 | |
2997 | /* board might not support ao, in which case write_subdev is NULL */ |
2998 | if (!s) |
2999 | return; |
3000 | async = s->async; |
3001 | cmd = &async->cmd; |
3002 | |
3003 | /* spin lock makes sure no one else changes plx dma control reg */ |
3004 | spin_lock_irqsave(&dev->spinlock, flags); |
3005 | dma0_status = readb(addr: devpriv->plx9080_iobase + PLX_REG_DMACSR0); |
3006 | if (plx_status & PLX_INTCSR_DMA0IA) { /* dma chan 0 interrupt */ |
3007 | if ((dma0_status & PLX_DMACSR_ENABLE) && |
3008 | !(dma0_status & PLX_DMACSR_DONE)) { |
3009 | writeb(PLX_DMACSR_ENABLE | PLX_DMACSR_CLEARINTR, |
3010 | addr: devpriv->plx9080_iobase + PLX_REG_DMACSR0); |
3011 | } else { |
3012 | writeb(PLX_DMACSR_CLEARINTR, |
3013 | addr: devpriv->plx9080_iobase + PLX_REG_DMACSR0); |
3014 | } |
3015 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
3016 | if (dma0_status & PLX_DMACSR_ENABLE) { |
3017 | load_ao_dma(dev, cmd); |
3018 | /* try to recover from dma end-of-chain event */ |
3019 | if (ao_dma_needs_restart(dev, dma_status: dma0_status)) |
3020 | restart_ao_dma(dev); |
3021 | } |
3022 | } else { |
3023 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
3024 | } |
3025 | |
3026 | if ((status & DAC_DONE_BIT)) { |
3027 | if ((cmd->stop_src == TRIG_COUNT && |
3028 | async->scans_done >= cmd->stop_arg) || |
3029 | last_ao_dma_load_completed(dev)) |
3030 | async->events |= COMEDI_CB_EOA; |
3031 | else |
3032 | async->events |= COMEDI_CB_ERROR; |
3033 | } |
3034 | comedi_handle_events(dev, s); |
3035 | } |
3036 | |
3037 | static irqreturn_t handle_interrupt(int irq, void *d) |
3038 | { |
3039 | struct comedi_device *dev = d; |
3040 | struct pcidas64_private *devpriv = dev->private; |
3041 | unsigned short status; |
3042 | u32 plx_status; |
3043 | u32 plx_bits; |
3044 | |
3045 | plx_status = readl(addr: devpriv->plx9080_iobase + PLX_REG_INTCSR); |
3046 | status = readw(addr: devpriv->main_iobase + HW_STATUS_REG); |
3047 | |
3048 | /* |
3049 | * an interrupt before all the postconfig stuff gets done could |
3050 | * cause a NULL dereference if we continue through the |
3051 | * interrupt handler |
3052 | */ |
3053 | if (!dev->attached) |
3054 | return IRQ_HANDLED; |
3055 | |
3056 | handle_ai_interrupt(dev, status, plx_status); |
3057 | handle_ao_interrupt(dev, status, plx_status); |
3058 | |
3059 | /* clear possible plx9080 interrupt sources */ |
3060 | if (plx_status & PLX_INTCSR_LDBIA) { |
3061 | /* clear local doorbell interrupt */ |
3062 | plx_bits = readl(addr: devpriv->plx9080_iobase + PLX_REG_L2PDBELL); |
3063 | writel(val: plx_bits, addr: devpriv->plx9080_iobase + PLX_REG_L2PDBELL); |
3064 | } |
3065 | |
3066 | return IRQ_HANDLED; |
3067 | } |
3068 | |
3069 | static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) |
3070 | { |
3071 | struct pcidas64_private *devpriv = dev->private; |
3072 | unsigned long flags; |
3073 | |
3074 | spin_lock_irqsave(&dev->spinlock, flags); |
3075 | if (devpriv->ai_cmd_running == 0) { |
3076 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
3077 | return 0; |
3078 | } |
3079 | devpriv->ai_cmd_running = 0; |
3080 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
3081 | |
3082 | disable_ai_pacing(dev); |
3083 | |
3084 | abort_dma(dev, channel: 1); |
3085 | |
3086 | return 0; |
3087 | } |
3088 | |
3089 | static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, |
3090 | struct comedi_insn *insn, unsigned int *data) |
3091 | { |
3092 | const struct pcidas64_board *board = dev->board_ptr; |
3093 | struct pcidas64_private *devpriv = dev->private; |
3094 | unsigned int chan = CR_CHAN(insn->chanspec); |
3095 | unsigned int range = CR_RANGE(insn->chanspec); |
3096 | unsigned int val = s->readback[chan]; |
3097 | unsigned int i; |
3098 | |
3099 | /* do some initializing */ |
3100 | writew(val: 0, addr: devpriv->main_iobase + DAC_CONTROL0_REG); |
3101 | |
3102 | /* set range */ |
3103 | set_dac_range_bits(dev, bits: &devpriv->dac_control1_bits, channel: chan, range); |
3104 | writew(val: devpriv->dac_control1_bits, |
3105 | addr: devpriv->main_iobase + DAC_CONTROL1_REG); |
3106 | |
3107 | for (i = 0; i < insn->n; i++) { |
3108 | /* write to channel */ |
3109 | val = data[i]; |
3110 | if (board->layout == LAYOUT_4020) { |
3111 | writew(val: val & 0xff, |
3112 | addr: devpriv->main_iobase + dac_lsb_4020_reg(channel: chan)); |
3113 | writew(val: (val >> 8) & 0xf, |
3114 | addr: devpriv->main_iobase + dac_msb_4020_reg(channel: chan)); |
3115 | } else { |
3116 | writew(val, |
3117 | addr: devpriv->main_iobase + dac_convert_reg(channel: chan)); |
3118 | } |
3119 | } |
3120 | |
3121 | /* remember last output value */ |
3122 | s->readback[chan] = val; |
3123 | |
3124 | return insn->n; |
3125 | } |
3126 | |
3127 | static void set_dac_control0_reg(struct comedi_device *dev, |
3128 | const struct comedi_cmd *cmd) |
3129 | { |
3130 | struct pcidas64_private *devpriv = dev->private; |
3131 | unsigned int bits = DAC_ENABLE_BIT | WAVEFORM_GATE_LEVEL_BIT | |
3132 | WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT; |
3133 | |
3134 | if (cmd->start_src == TRIG_EXT) { |
3135 | bits |= WAVEFORM_TRIG_EXT_BITS; |
3136 | if (cmd->start_arg & CR_INVERT) |
3137 | bits |= WAVEFORM_TRIG_FALLING_BIT; |
3138 | } else { |
3139 | bits |= WAVEFORM_TRIG_SOFT_BITS; |
3140 | } |
3141 | if (cmd->scan_begin_src == TRIG_EXT) { |
3142 | bits |= DAC_EXT_UPDATE_ENABLE_BIT; |
3143 | if (cmd->scan_begin_arg & CR_INVERT) |
3144 | bits |= DAC_EXT_UPDATE_FALLING_BIT; |
3145 | } |
3146 | writew(val: bits, addr: devpriv->main_iobase + DAC_CONTROL0_REG); |
3147 | } |
3148 | |
3149 | static void set_dac_control1_reg(struct comedi_device *dev, |
3150 | const struct comedi_cmd *cmd) |
3151 | { |
3152 | struct pcidas64_private *devpriv = dev->private; |
3153 | int i; |
3154 | |
3155 | for (i = 0; i < cmd->chanlist_len; i++) { |
3156 | int channel, range; |
3157 | |
3158 | channel = CR_CHAN(cmd->chanlist[i]); |
3159 | range = CR_RANGE(cmd->chanlist[i]); |
3160 | set_dac_range_bits(dev, bits: &devpriv->dac_control1_bits, channel, |
3161 | range); |
3162 | } |
3163 | devpriv->dac_control1_bits |= DAC_SW_GATE_BIT; |
3164 | writew(val: devpriv->dac_control1_bits, |
3165 | addr: devpriv->main_iobase + DAC_CONTROL1_REG); |
3166 | } |
3167 | |
3168 | static void set_dac_select_reg(struct comedi_device *dev, |
3169 | const struct comedi_cmd *cmd) |
3170 | { |
3171 | struct pcidas64_private *devpriv = dev->private; |
3172 | u16 bits; |
3173 | unsigned int first_channel, last_channel; |
3174 | |
3175 | first_channel = CR_CHAN(cmd->chanlist[0]); |
3176 | last_channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); |
3177 | if (last_channel < first_channel) |
3178 | dev_err(dev->class_dev, |
3179 | "bug! last ao channel < first ao channel\n" ); |
3180 | |
3181 | bits = (first_channel & 0x7) | (last_channel & 0x7) << 3; |
3182 | |
3183 | writew(val: bits, addr: devpriv->main_iobase + DAC_SELECT_REG); |
3184 | } |
3185 | |
3186 | static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags) |
3187 | { |
3188 | return get_divisor(ns, flags) - 2; |
3189 | } |
3190 | |
3191 | static void set_dac_interval_regs(struct comedi_device *dev, |
3192 | const struct comedi_cmd *cmd) |
3193 | { |
3194 | struct pcidas64_private *devpriv = dev->private; |
3195 | unsigned int divisor; |
3196 | |
3197 | if (cmd->scan_begin_src != TRIG_TIMER) |
3198 | return; |
3199 | |
3200 | divisor = get_ao_divisor(ns: cmd->scan_begin_arg, flags: cmd->flags); |
3201 | if (divisor > max_counter_value) { |
3202 | dev_err(dev->class_dev, "bug! ao divisor too big\n" ); |
3203 | divisor = max_counter_value; |
3204 | } |
3205 | writew(val: divisor & 0xffff, |
3206 | addr: devpriv->main_iobase + DAC_SAMPLE_INTERVAL_LOWER_REG); |
3207 | writew(val: (divisor >> 16) & 0xff, |
3208 | addr: devpriv->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG); |
3209 | } |
3210 | |
3211 | static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) |
3212 | { |
3213 | struct pcidas64_private *devpriv = dev->private; |
3214 | struct comedi_subdevice *s = dev->write_subdev; |
3215 | unsigned int nsamples; |
3216 | unsigned int nbytes; |
3217 | int i; |
3218 | |
3219 | /* |
3220 | * clear queue pointer too, since external queue has |
3221 | * weird interactions with ao fifo |
3222 | */ |
3223 | writew(val: 0, addr: devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); |
3224 | writew(val: 0, addr: devpriv->main_iobase + DAC_BUFFER_CLEAR_REG); |
3225 | |
3226 | nsamples = cb_pcidas64_ao_fill_buffer(dev, s, |
3227 | dest: devpriv->ao_bounce_buffer, |
3228 | DAC_FIFO_SIZE); |
3229 | if (nsamples == 0) |
3230 | return -1; |
3231 | |
3232 | for (i = 0; i < nsamples; i++) { |
3233 | writew(val: devpriv->ao_bounce_buffer[i], |
3234 | addr: devpriv->main_iobase + DAC_FIFO_REG); |
3235 | } |
3236 | |
3237 | if (cmd->stop_src == TRIG_COUNT && |
3238 | s->async->scans_done >= cmd->stop_arg) |
3239 | return 0; |
3240 | |
3241 | nbytes = load_ao_dma_buffer(dev, cmd); |
3242 | if (nbytes == 0) |
3243 | return -1; |
3244 | load_ao_dma(dev, cmd); |
3245 | |
3246 | dma_start_sync(dev, channel: 0); |
3247 | |
3248 | return 0; |
3249 | } |
3250 | |
3251 | static inline int external_ai_queue_in_use(struct comedi_device *dev) |
3252 | { |
3253 | const struct pcidas64_board *board = dev->board_ptr; |
3254 | |
3255 | if (!dev->read_subdev->busy) |
3256 | return 0; |
3257 | if (board->layout == LAYOUT_4020) |
3258 | return 0; |
3259 | else if (use_internal_queue_6xxx(cmd: &dev->read_subdev->async->cmd)) |
3260 | return 0; |
3261 | return 1; |
3262 | } |
3263 | |
3264 | static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, |
3265 | unsigned int trig_num) |
3266 | { |
3267 | struct pcidas64_private *devpriv = dev->private; |
3268 | struct comedi_cmd *cmd = &s->async->cmd; |
3269 | int retval; |
3270 | |
3271 | if (trig_num != cmd->start_arg) |
3272 | return -EINVAL; |
3273 | |
3274 | retval = prep_ao_dma(dev, cmd); |
3275 | if (retval < 0) |
3276 | return -EPIPE; |
3277 | |
3278 | set_dac_control0_reg(dev, cmd); |
3279 | |
3280 | if (cmd->start_src == TRIG_INT) |
3281 | writew(val: 0, addr: devpriv->main_iobase + DAC_START_REG); |
3282 | |
3283 | s->async->inttrig = NULL; |
3284 | |
3285 | return 0; |
3286 | } |
3287 | |
3288 | static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) |
3289 | { |
3290 | struct pcidas64_private *devpriv = dev->private; |
3291 | struct comedi_cmd *cmd = &s->async->cmd; |
3292 | |
3293 | if (external_ai_queue_in_use(dev)) { |
3294 | warn_external_queue(dev); |
3295 | return -EBUSY; |
3296 | } |
3297 | /* disable analog output system during setup */ |
3298 | writew(val: 0x0, addr: devpriv->main_iobase + DAC_CONTROL0_REG); |
3299 | |
3300 | devpriv->ao_dma_index = 0; |
3301 | |
3302 | set_dac_select_reg(dev, cmd); |
3303 | set_dac_interval_regs(dev, cmd); |
3304 | load_first_dma_descriptor(dev, dma_channel: 0, descriptor_bits: devpriv->ao_dma_desc_bus_addr | |
3305 | PLX_DMADPR_DESCPCI | PLX_DMADPR_TCINTR); |
3306 | |
3307 | set_dac_control1_reg(dev, cmd); |
3308 | s->async->inttrig = ao_inttrig; |
3309 | |
3310 | return 0; |
3311 | } |
3312 | |
3313 | static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev, |
3314 | struct comedi_subdevice *s, |
3315 | struct comedi_cmd *cmd) |
3316 | { |
3317 | unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); |
3318 | int i; |
3319 | |
3320 | for (i = 1; i < cmd->chanlist_len; i++) { |
3321 | unsigned int chan = CR_CHAN(cmd->chanlist[i]); |
3322 | |
3323 | if (chan != (chan0 + i)) { |
3324 | dev_dbg(dev->class_dev, |
3325 | "chanlist must use consecutive channels\n" ); |
3326 | return -EINVAL; |
3327 | } |
3328 | } |
3329 | |
3330 | return 0; |
3331 | } |
3332 | |
3333 | static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, |
3334 | struct comedi_cmd *cmd) |
3335 | { |
3336 | const struct pcidas64_board *board = dev->board_ptr; |
3337 | int err = 0; |
3338 | unsigned int tmp_arg; |
3339 | |
3340 | /* Step 1 : check if triggers are trivially valid */ |
3341 | |
3342 | err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_INT | TRIG_EXT); |
3343 | err |= comedi_check_trigger_src(src: &cmd->scan_begin_src, |
3344 | TRIG_TIMER | TRIG_EXT); |
3345 | err |= comedi_check_trigger_src(src: &cmd->convert_src, TRIG_NOW); |
3346 | err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT); |
3347 | err |= comedi_check_trigger_src(src: &cmd->stop_src, TRIG_NONE); |
3348 | |
3349 | if (err) |
3350 | return 1; |
3351 | |
3352 | /* Step 2a : make sure trigger sources are unique */ |
3353 | |
3354 | err |= comedi_check_trigger_is_unique(src: cmd->start_src); |
3355 | err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src); |
3356 | |
3357 | /* Step 2b : and mutually compatible */ |
3358 | |
3359 | if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) |
3360 | err |= -EINVAL; |
3361 | if (cmd->stop_src != TRIG_COUNT && |
3362 | cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) |
3363 | err |= -EINVAL; |
3364 | |
3365 | if (err) |
3366 | return 2; |
3367 | |
3368 | /* Step 3: check if arguments are trivially valid */ |
3369 | |
3370 | err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0); |
3371 | |
3372 | if (cmd->scan_begin_src == TRIG_TIMER) { |
3373 | err |= comedi_check_trigger_arg_min(arg: &cmd->scan_begin_arg, |
3374 | val: board->ao_scan_speed); |
3375 | if (get_ao_divisor(ns: cmd->scan_begin_arg, flags: cmd->flags) > |
3376 | max_counter_value) { |
3377 | cmd->scan_begin_arg = (max_counter_value + 2) * |
3378 | TIMER_BASE; |
3379 | err |= -EINVAL; |
3380 | } |
3381 | } |
3382 | |
3383 | err |= comedi_check_trigger_arg_min(arg: &cmd->chanlist_len, val: 1); |
3384 | err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg, |
3385 | val: cmd->chanlist_len); |
3386 | |
3387 | if (err) |
3388 | return 3; |
3389 | |
3390 | /* step 4: fix up any arguments */ |
3391 | |
3392 | if (cmd->scan_begin_src == TRIG_TIMER) { |
3393 | tmp_arg = cmd->scan_begin_arg; |
3394 | cmd->scan_begin_arg = get_divisor(ns: cmd->scan_begin_arg, |
3395 | flags: cmd->flags) * TIMER_BASE; |
3396 | if (tmp_arg != cmd->scan_begin_arg) |
3397 | err++; |
3398 | } |
3399 | |
3400 | if (err) |
3401 | return 4; |
3402 | |
3403 | /* Step 5: check channel list if it exists */ |
3404 | if (cmd->chanlist && cmd->chanlist_len > 0) |
3405 | err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd); |
3406 | |
3407 | if (err) |
3408 | return 5; |
3409 | |
3410 | return 0; |
3411 | } |
3412 | |
3413 | static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) |
3414 | { |
3415 | struct pcidas64_private *devpriv = dev->private; |
3416 | |
3417 | writew(val: 0x0, addr: devpriv->main_iobase + DAC_CONTROL0_REG); |
3418 | abort_dma(dev, channel: 0); |
3419 | return 0; |
3420 | } |
3421 | |
3422 | static int dio_callback_4020(struct comedi_device *dev, |
3423 | int dir, int port, int data, unsigned long iobase) |
3424 | { |
3425 | struct pcidas64_private *devpriv = dev->private; |
3426 | |
3427 | if (dir) { |
3428 | writew(val: data, addr: devpriv->main_iobase + iobase + 2 * port); |
3429 | return 0; |
3430 | } |
3431 | return readw(addr: devpriv->main_iobase + iobase + 2 * port); |
3432 | } |
3433 | |
3434 | static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, |
3435 | struct comedi_insn *insn, unsigned int *data) |
3436 | { |
3437 | unsigned int bits; |
3438 | |
3439 | bits = readb(addr: dev->mmio + DI_REG); |
3440 | bits &= 0xf; |
3441 | data[1] = bits; |
3442 | data[0] = 0; |
3443 | |
3444 | return insn->n; |
3445 | } |
3446 | |
3447 | static int do_wbits(struct comedi_device *dev, |
3448 | struct comedi_subdevice *s, |
3449 | struct comedi_insn *insn, |
3450 | unsigned int *data) |
3451 | { |
3452 | if (comedi_dio_update_state(s, data)) |
3453 | writeb(val: s->state, addr: dev->mmio + DO_REG); |
3454 | |
3455 | data[1] = s->state; |
3456 | |
3457 | return insn->n; |
3458 | } |
3459 | |
3460 | static int dio_60xx_config_insn(struct comedi_device *dev, |
3461 | struct comedi_subdevice *s, |
3462 | struct comedi_insn *insn, |
3463 | unsigned int *data) |
3464 | { |
3465 | int ret; |
3466 | |
3467 | ret = comedi_dio_insn_config(dev, s, insn, data, mask: 0); |
3468 | if (ret) |
3469 | return ret; |
3470 | |
3471 | writeb(val: s->io_bits, addr: dev->mmio + DIO_DIRECTION_60XX_REG); |
3472 | |
3473 | return insn->n; |
3474 | } |
3475 | |
3476 | static int dio_60xx_wbits(struct comedi_device *dev, |
3477 | struct comedi_subdevice *s, |
3478 | struct comedi_insn *insn, |
3479 | unsigned int *data) |
3480 | { |
3481 | if (comedi_dio_update_state(s, data)) |
3482 | writeb(val: s->state, addr: dev->mmio + DIO_DATA_60XX_REG); |
3483 | |
3484 | data[1] = readb(addr: dev->mmio + DIO_DATA_60XX_REG); |
3485 | |
3486 | return insn->n; |
3487 | } |
3488 | |
3489 | /* |
3490 | * pci-6025 8800 caldac: |
3491 | * address 0 == dac channel 0 offset |
3492 | * address 1 == dac channel 0 gain |
3493 | * address 2 == dac channel 1 offset |
3494 | * address 3 == dac channel 1 gain |
3495 | * address 4 == fine adc offset |
3496 | * address 5 == coarse adc offset |
3497 | * address 6 == coarse adc gain |
3498 | * address 7 == fine adc gain |
3499 | */ |
3500 | /* |
3501 | * pci-6402/16 uses all 8 channels for dac: |
3502 | * address 0 == dac channel 0 fine gain |
3503 | * address 1 == dac channel 0 coarse gain |
3504 | * address 2 == dac channel 0 coarse offset |
3505 | * address 3 == dac channel 1 coarse offset |
3506 | * address 4 == dac channel 1 fine gain |
3507 | * address 5 == dac channel 1 coarse gain |
3508 | * address 6 == dac channel 0 fine offset |
3509 | * address 7 == dac channel 1 fine offset |
3510 | */ |
3511 | |
3512 | static int caldac_8800_write(struct comedi_device *dev, unsigned int address, |
3513 | u8 value) |
3514 | { |
3515 | struct pcidas64_private *devpriv = dev->private; |
3516 | static const int num_caldac_channels = 8; |
3517 | static const int bitstream_length = 11; |
3518 | unsigned int bitstream = ((address & 0x7) << 8) | value; |
3519 | unsigned int bit, register_bits; |
3520 | static const int caldac_8800_udelay = 1; |
3521 | |
3522 | if (address >= num_caldac_channels) { |
3523 | dev_err(dev->class_dev, "illegal caldac channel\n" ); |
3524 | return -1; |
3525 | } |
3526 | for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { |
3527 | register_bits = 0; |
3528 | if (bitstream & bit) |
3529 | register_bits |= SERIAL_DATA_IN_BIT; |
3530 | udelay(caldac_8800_udelay); |
3531 | writew(val: register_bits, addr: devpriv->main_iobase + CALIBRATION_REG); |
3532 | register_bits |= SERIAL_CLOCK_BIT; |
3533 | udelay(caldac_8800_udelay); |
3534 | writew(val: register_bits, addr: devpriv->main_iobase + CALIBRATION_REG); |
3535 | } |
3536 | udelay(caldac_8800_udelay); |
3537 | writew(val: SELECT_8800_BIT, addr: devpriv->main_iobase + CALIBRATION_REG); |
3538 | udelay(caldac_8800_udelay); |
3539 | writew(val: 0, addr: devpriv->main_iobase + CALIBRATION_REG); |
3540 | udelay(caldac_8800_udelay); |
3541 | return 0; |
3542 | } |
3543 | |
3544 | /* 4020 caldacs */ |
3545 | static int caldac_i2c_write(struct comedi_device *dev, |
3546 | unsigned int caldac_channel, unsigned int value) |
3547 | { |
3548 | u8 serial_bytes[3]; |
3549 | u8 i2c_addr; |
3550 | enum pointer_bits { |
3551 | /* manual has gain and offset bits switched */ |
3552 | OFFSET_0_2 = 0x1, |
3553 | GAIN_0_2 = 0x2, |
3554 | OFFSET_1_3 = 0x4, |
3555 | GAIN_1_3 = 0x8, |
3556 | }; |
3557 | enum data_bits { |
3558 | NOT_CLEAR_REGISTERS = 0x20, |
3559 | }; |
3560 | |
3561 | switch (caldac_channel) { |
3562 | case 0: /* chan 0 offset */ |
3563 | i2c_addr = CALDAC0_I2C_ADDR; |
3564 | serial_bytes[0] = OFFSET_0_2; |
3565 | break; |
3566 | case 1: /* chan 1 offset */ |
3567 | i2c_addr = CALDAC0_I2C_ADDR; |
3568 | serial_bytes[0] = OFFSET_1_3; |
3569 | break; |
3570 | case 2: /* chan 2 offset */ |
3571 | i2c_addr = CALDAC1_I2C_ADDR; |
3572 | serial_bytes[0] = OFFSET_0_2; |
3573 | break; |
3574 | case 3: /* chan 3 offset */ |
3575 | i2c_addr = CALDAC1_I2C_ADDR; |
3576 | serial_bytes[0] = OFFSET_1_3; |
3577 | break; |
3578 | case 4: /* chan 0 gain */ |
3579 | i2c_addr = CALDAC0_I2C_ADDR; |
3580 | serial_bytes[0] = GAIN_0_2; |
3581 | break; |
3582 | case 5: /* chan 1 gain */ |
3583 | i2c_addr = CALDAC0_I2C_ADDR; |
3584 | serial_bytes[0] = GAIN_1_3; |
3585 | break; |
3586 | case 6: /* chan 2 gain */ |
3587 | i2c_addr = CALDAC1_I2C_ADDR; |
3588 | serial_bytes[0] = GAIN_0_2; |
3589 | break; |
3590 | case 7: /* chan 3 gain */ |
3591 | i2c_addr = CALDAC1_I2C_ADDR; |
3592 | serial_bytes[0] = GAIN_1_3; |
3593 | break; |
3594 | default: |
3595 | dev_err(dev->class_dev, "invalid caldac channel\n" ); |
3596 | return -1; |
3597 | } |
3598 | serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf); |
3599 | serial_bytes[2] = value & 0xff; |
3600 | i2c_write(dev, address: i2c_addr, data: serial_bytes, length: 3); |
3601 | return 0; |
3602 | } |
3603 | |
3604 | static void caldac_write(struct comedi_device *dev, unsigned int channel, |
3605 | unsigned int value) |
3606 | { |
3607 | const struct pcidas64_board *board = dev->board_ptr; |
3608 | |
3609 | switch (board->layout) { |
3610 | case LAYOUT_60XX: |
3611 | case LAYOUT_64XX: |
3612 | caldac_8800_write(dev, address: channel, value); |
3613 | break; |
3614 | case LAYOUT_4020: |
3615 | caldac_i2c_write(dev, caldac_channel: channel, value); |
3616 | break; |
3617 | default: |
3618 | break; |
3619 | } |
3620 | } |
3621 | |
3622 | static int cb_pcidas64_calib_insn_write(struct comedi_device *dev, |
3623 | struct comedi_subdevice *s, |
3624 | struct comedi_insn *insn, |
3625 | unsigned int *data) |
3626 | { |
3627 | unsigned int chan = CR_CHAN(insn->chanspec); |
3628 | |
3629 | /* |
3630 | * Programming the calib device is slow. Only write the |
3631 | * last data value if the value has changed. |
3632 | */ |
3633 | if (insn->n) { |
3634 | unsigned int val = data[insn->n - 1]; |
3635 | |
3636 | if (s->readback[chan] != val) { |
3637 | caldac_write(dev, channel: chan, value: val); |
3638 | s->readback[chan] = val; |
3639 | } |
3640 | } |
3641 | |
3642 | return insn->n; |
3643 | } |
3644 | |
3645 | static void ad8402_write(struct comedi_device *dev, unsigned int channel, |
3646 | unsigned int value) |
3647 | { |
3648 | struct pcidas64_private *devpriv = dev->private; |
3649 | static const int bitstream_length = 10; |
3650 | unsigned int bit, register_bits; |
3651 | unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); |
3652 | static const int ad8402_udelay = 1; |
3653 | |
3654 | register_bits = SELECT_8402_64XX_BIT; |
3655 | udelay(ad8402_udelay); |
3656 | writew(val: register_bits, addr: devpriv->main_iobase + CALIBRATION_REG); |
3657 | |
3658 | for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { |
3659 | if (bitstream & bit) |
3660 | register_bits |= SERIAL_DATA_IN_BIT; |
3661 | else |
3662 | register_bits &= ~SERIAL_DATA_IN_BIT; |
3663 | udelay(ad8402_udelay); |
3664 | writew(val: register_bits, addr: devpriv->main_iobase + CALIBRATION_REG); |
3665 | udelay(ad8402_udelay); |
3666 | writew(val: register_bits | SERIAL_CLOCK_BIT, |
3667 | addr: devpriv->main_iobase + CALIBRATION_REG); |
3668 | } |
3669 | |
3670 | udelay(ad8402_udelay); |
3671 | writew(val: 0, addr: devpriv->main_iobase + CALIBRATION_REG); |
3672 | } |
3673 | |
3674 | /* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */ |
3675 | static int cb_pcidas64_ad8402_insn_write(struct comedi_device *dev, |
3676 | struct comedi_subdevice *s, |
3677 | struct comedi_insn *insn, |
3678 | unsigned int *data) |
3679 | { |
3680 | unsigned int chan = CR_CHAN(insn->chanspec); |
3681 | |
3682 | /* |
3683 | * Programming the calib device is slow. Only write the |
3684 | * last data value if the value has changed. |
3685 | */ |
3686 | if (insn->n) { |
3687 | unsigned int val = data[insn->n - 1]; |
3688 | |
3689 | if (s->readback[chan] != val) { |
3690 | ad8402_write(dev, channel: chan, value: val); |
3691 | s->readback[chan] = val; |
3692 | } |
3693 | } |
3694 | |
3695 | return insn->n; |
3696 | } |
3697 | |
3698 | static u16 read_eeprom(struct comedi_device *dev, u8 address) |
3699 | { |
3700 | struct pcidas64_private *devpriv = dev->private; |
3701 | static const int bitstream_length = 11; |
3702 | static const int read_command = 0x6; |
3703 | unsigned int bitstream = (read_command << 8) | address; |
3704 | unsigned int bit; |
3705 | void __iomem * const plx_control_addr = |
3706 | devpriv->plx9080_iobase + PLX_REG_CNTRL; |
3707 | u16 value; |
3708 | static const int value_length = 16; |
3709 | static const int eeprom_udelay = 1; |
3710 | |
3711 | udelay(eeprom_udelay); |
3712 | devpriv->plx_control_bits &= ~PLX_CNTRL_EESK & ~PLX_CNTRL_EECS; |
3713 | /* make sure we don't send anything to the i2c bus on 4020 */ |
3714 | devpriv->plx_control_bits |= PLX_CNTRL_USERO; |
3715 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3716 | /* activate serial eeprom */ |
3717 | udelay(eeprom_udelay); |
3718 | devpriv->plx_control_bits |= PLX_CNTRL_EECS; |
3719 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3720 | |
3721 | /* write read command and desired memory address */ |
3722 | for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { |
3723 | /* set bit to be written */ |
3724 | udelay(eeprom_udelay); |
3725 | if (bitstream & bit) |
3726 | devpriv->plx_control_bits |= PLX_CNTRL_EEWB; |
3727 | else |
3728 | devpriv->plx_control_bits &= ~PLX_CNTRL_EEWB; |
3729 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3730 | /* clock in bit */ |
3731 | udelay(eeprom_udelay); |
3732 | devpriv->plx_control_bits |= PLX_CNTRL_EESK; |
3733 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3734 | udelay(eeprom_udelay); |
3735 | devpriv->plx_control_bits &= ~PLX_CNTRL_EESK; |
3736 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3737 | } |
3738 | /* read back value from eeprom memory location */ |
3739 | value = 0; |
3740 | for (bit = 1 << (value_length - 1); bit; bit >>= 1) { |
3741 | /* clock out bit */ |
3742 | udelay(eeprom_udelay); |
3743 | devpriv->plx_control_bits |= PLX_CNTRL_EESK; |
3744 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3745 | udelay(eeprom_udelay); |
3746 | devpriv->plx_control_bits &= ~PLX_CNTRL_EESK; |
3747 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3748 | udelay(eeprom_udelay); |
3749 | if (readl(addr: plx_control_addr) & PLX_CNTRL_EERB) |
3750 | value |= bit; |
3751 | } |
3752 | |
3753 | /* deactivate eeprom serial input */ |
3754 | udelay(eeprom_udelay); |
3755 | devpriv->plx_control_bits &= ~PLX_CNTRL_EECS; |
3756 | writel(val: devpriv->plx_control_bits, addr: plx_control_addr); |
3757 | |
3758 | return value; |
3759 | } |
3760 | |
3761 | static int eeprom_read_insn(struct comedi_device *dev, |
3762 | struct comedi_subdevice *s, |
3763 | struct comedi_insn *insn, unsigned int *data) |
3764 | { |
3765 | unsigned int val; |
3766 | unsigned int i; |
3767 | |
3768 | if (insn->n) { |
3769 | /* No point reading the same EEPROM location more than once. */ |
3770 | val = read_eeprom(dev, CR_CHAN(insn->chanspec)); |
3771 | for (i = 0; i < insn->n; i++) |
3772 | data[i] = val; |
3773 | } |
3774 | |
3775 | return insn->n; |
3776 | } |
3777 | |
3778 | /* Allocate and initialize the subdevice structures. */ |
3779 | static int setup_subdevices(struct comedi_device *dev) |
3780 | { |
3781 | const struct pcidas64_board *board = dev->board_ptr; |
3782 | struct pcidas64_private *devpriv = dev->private; |
3783 | struct comedi_subdevice *s; |
3784 | int i; |
3785 | int ret; |
3786 | |
3787 | ret = comedi_alloc_subdevices(dev, num_subdevices: 10); |
3788 | if (ret) |
3789 | return ret; |
3790 | |
3791 | s = &dev->subdevices[0]; |
3792 | /* analog input subdevice */ |
3793 | dev->read_subdev = s; |
3794 | s->type = COMEDI_SUBD_AI; |
3795 | s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ; |
3796 | if (board->layout == LAYOUT_60XX) |
3797 | s->subdev_flags |= SDF_COMMON | SDF_DIFF; |
3798 | else if (board->layout == LAYOUT_64XX) |
3799 | s->subdev_flags |= SDF_DIFF; |
3800 | /* XXX Number of inputs in differential mode is ignored */ |
3801 | s->n_chan = board->ai_se_chans; |
3802 | s->len_chanlist = 0x2000; |
3803 | s->maxdata = (1 << board->ai_bits) - 1; |
3804 | s->range_table = board->ai_range_table; |
3805 | s->insn_read = ai_rinsn; |
3806 | s->insn_config = ai_config_insn; |
3807 | s->do_cmd = ai_cmd; |
3808 | s->do_cmdtest = ai_cmdtest; |
3809 | s->cancel = ai_cancel; |
3810 | if (board->layout == LAYOUT_4020) { |
3811 | u8 data; |
3812 | /* |
3813 | * set adc to read from inputs |
3814 | * (not internal calibration sources) |
3815 | */ |
3816 | devpriv->i2c_cal_range_bits = adc_src_4020_bits(source: 4); |
3817 | /* set channels to +-5 volt input ranges */ |
3818 | for (i = 0; i < s->n_chan; i++) |
3819 | devpriv->i2c_cal_range_bits |= attenuate_bit(channel: i); |
3820 | data = devpriv->i2c_cal_range_bits; |
3821 | i2c_write(dev, address: RANGE_CAL_I2C_ADDR, data: &data, length: sizeof(data)); |
3822 | } |
3823 | |
3824 | /* analog output subdevice */ |
3825 | s = &dev->subdevices[1]; |
3826 | if (board->ao_nchan) { |
3827 | s->type = COMEDI_SUBD_AO; |
3828 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE | |
3829 | SDF_GROUND | SDF_CMD_WRITE; |
3830 | s->n_chan = board->ao_nchan; |
3831 | s->maxdata = (1 << board->ao_bits) - 1; |
3832 | s->range_table = board->ao_range_table; |
3833 | s->insn_write = ao_winsn; |
3834 | |
3835 | ret = comedi_alloc_subdev_readback(s); |
3836 | if (ret) |
3837 | return ret; |
3838 | |
3839 | if (ao_cmd_is_supported(board)) { |
3840 | dev->write_subdev = s; |
3841 | s->do_cmdtest = ao_cmdtest; |
3842 | s->do_cmd = ao_cmd; |
3843 | s->len_chanlist = board->ao_nchan; |
3844 | s->cancel = ao_cancel; |
3845 | } |
3846 | } else { |
3847 | s->type = COMEDI_SUBD_UNUSED; |
3848 | } |
3849 | |
3850 | /* digital input */ |
3851 | s = &dev->subdevices[2]; |
3852 | if (board->layout == LAYOUT_64XX) { |
3853 | s->type = COMEDI_SUBD_DI; |
3854 | s->subdev_flags = SDF_READABLE; |
3855 | s->n_chan = 4; |
3856 | s->maxdata = 1; |
3857 | s->range_table = &range_digital; |
3858 | s->insn_bits = di_rbits; |
3859 | } else { |
3860 | s->type = COMEDI_SUBD_UNUSED; |
3861 | } |
3862 | |
3863 | /* digital output */ |
3864 | if (board->layout == LAYOUT_64XX) { |
3865 | s = &dev->subdevices[3]; |
3866 | s->type = COMEDI_SUBD_DO; |
3867 | s->subdev_flags = SDF_WRITABLE; |
3868 | s->n_chan = 4; |
3869 | s->maxdata = 1; |
3870 | s->range_table = &range_digital; |
3871 | s->insn_bits = do_wbits; |
3872 | } else { |
3873 | s->type = COMEDI_SUBD_UNUSED; |
3874 | } |
3875 | |
3876 | /* 8255 */ |
3877 | s = &dev->subdevices[4]; |
3878 | if (board->has_8255) { |
3879 | if (board->layout == LAYOUT_4020) { |
3880 | ret = subdev_8255_cb_init(dev, s, io: dio_callback_4020, |
3881 | context: I8255_4020_REG); |
3882 | } else { |
3883 | ret = subdev_8255_mm_init(dev, s, regbase: DIO_8255_OFFSET); |
3884 | } |
3885 | if (ret) |
3886 | return ret; |
3887 | } else { |
3888 | s->type = COMEDI_SUBD_UNUSED; |
3889 | } |
3890 | |
3891 | /* 8 channel dio for 60xx */ |
3892 | s = &dev->subdevices[5]; |
3893 | if (board->layout == LAYOUT_60XX) { |
3894 | s->type = COMEDI_SUBD_DIO; |
3895 | s->subdev_flags = SDF_WRITABLE | SDF_READABLE; |
3896 | s->n_chan = 8; |
3897 | s->maxdata = 1; |
3898 | s->range_table = &range_digital; |
3899 | s->insn_config = dio_60xx_config_insn; |
3900 | s->insn_bits = dio_60xx_wbits; |
3901 | } else { |
3902 | s->type = COMEDI_SUBD_UNUSED; |
3903 | } |
3904 | |
3905 | /* caldac */ |
3906 | s = &dev->subdevices[6]; |
3907 | s->type = COMEDI_SUBD_CALIB; |
3908 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; |
3909 | s->n_chan = 8; |
3910 | if (board->layout == LAYOUT_4020) |
3911 | s->maxdata = 0xfff; |
3912 | else |
3913 | s->maxdata = 0xff; |
3914 | s->insn_write = cb_pcidas64_calib_insn_write; |
3915 | |
3916 | ret = comedi_alloc_subdev_readback(s); |
3917 | if (ret) |
3918 | return ret; |
3919 | |
3920 | for (i = 0; i < s->n_chan; i++) { |
3921 | caldac_write(dev, channel: i, value: s->maxdata / 2); |
3922 | s->readback[i] = s->maxdata / 2; |
3923 | } |
3924 | |
3925 | /* 2 channel ad8402 potentiometer */ |
3926 | s = &dev->subdevices[7]; |
3927 | if (board->layout == LAYOUT_64XX) { |
3928 | s->type = COMEDI_SUBD_CALIB; |
3929 | s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; |
3930 | s->n_chan = 2; |
3931 | s->maxdata = 0xff; |
3932 | s->insn_write = cb_pcidas64_ad8402_insn_write; |
3933 | |
3934 | ret = comedi_alloc_subdev_readback(s); |
3935 | if (ret) |
3936 | return ret; |
3937 | |
3938 | for (i = 0; i < s->n_chan; i++) { |
3939 | ad8402_write(dev, channel: i, value: s->maxdata / 2); |
3940 | s->readback[i] = s->maxdata / 2; |
3941 | } |
3942 | } else { |
3943 | s->type = COMEDI_SUBD_UNUSED; |
3944 | } |
3945 | |
3946 | /* serial EEPROM, if present */ |
3947 | s = &dev->subdevices[8]; |
3948 | if (readl(addr: devpriv->plx9080_iobase + PLX_REG_CNTRL) & |
3949 | PLX_CNTRL_EEPRESENT) { |
3950 | s->type = COMEDI_SUBD_MEMORY; |
3951 | s->subdev_flags = SDF_READABLE | SDF_INTERNAL; |
3952 | s->n_chan = 128; |
3953 | s->maxdata = 0xffff; |
3954 | s->insn_read = eeprom_read_insn; |
3955 | } else { |
3956 | s->type = COMEDI_SUBD_UNUSED; |
3957 | } |
3958 | |
3959 | /* user counter subd XXX */ |
3960 | s = &dev->subdevices[9]; |
3961 | s->type = COMEDI_SUBD_UNUSED; |
3962 | |
3963 | return 0; |
3964 | } |
3965 | |
3966 | static int auto_attach(struct comedi_device *dev, |
3967 | unsigned long context) |
3968 | { |
3969 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
3970 | const struct pcidas64_board *board = NULL; |
3971 | struct pcidas64_private *devpriv; |
3972 | u32 local_range, local_decode; |
3973 | int retval; |
3974 | |
3975 | if (context < ARRAY_SIZE(pcidas64_boards)) |
3976 | board = &pcidas64_boards[context]; |
3977 | if (!board) |
3978 | return -ENODEV; |
3979 | dev->board_ptr = board; |
3980 | |
3981 | devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv)); |
3982 | if (!devpriv) |
3983 | return -ENOMEM; |
3984 | |
3985 | retval = comedi_pci_enable(dev); |
3986 | if (retval) |
3987 | return retval; |
3988 | pci_set_master(dev: pcidev); |
3989 | |
3990 | /* Initialize dev->board_name */ |
3991 | dev->board_name = board->name; |
3992 | |
3993 | devpriv->main_phys_iobase = pci_resource_start(pcidev, 2); |
3994 | devpriv->dio_counter_phys_iobase = pci_resource_start(pcidev, 3); |
3995 | |
3996 | devpriv->plx9080_iobase = pci_ioremap_bar(pdev: pcidev, bar: 0); |
3997 | devpriv->main_iobase = pci_ioremap_bar(pdev: pcidev, bar: 2); |
3998 | dev->mmio = pci_ioremap_bar(pdev: pcidev, bar: 3); |
3999 | |
4000 | if (!devpriv->plx9080_iobase || !devpriv->main_iobase || !dev->mmio) { |
4001 | dev_warn(dev->class_dev, "failed to remap io memory\n" ); |
4002 | return -ENOMEM; |
4003 | } |
4004 | |
4005 | /* figure out what local addresses are */ |
4006 | local_range = readl(addr: devpriv->plx9080_iobase + PLX_REG_LAS0RR) & |
4007 | PLX_LASRR_MEM_MASK; |
4008 | local_decode = readl(addr: devpriv->plx9080_iobase + PLX_REG_LAS0BA) & |
4009 | local_range & PLX_LASBA_MEM_MASK; |
4010 | devpriv->local0_iobase = ((u32)devpriv->main_phys_iobase & |
4011 | ~local_range) | local_decode; |
4012 | local_range = readl(addr: devpriv->plx9080_iobase + PLX_REG_LAS1RR) & |
4013 | PLX_LASRR_MEM_MASK; |
4014 | local_decode = readl(addr: devpriv->plx9080_iobase + PLX_REG_LAS1BA) & |
4015 | local_range & PLX_LASBA_MEM_MASK; |
4016 | devpriv->local1_iobase = ((u32)devpriv->dio_counter_phys_iobase & |
4017 | ~local_range) | local_decode; |
4018 | |
4019 | retval = alloc_and_init_dma_members(dev); |
4020 | if (retval < 0) |
4021 | return retval; |
4022 | |
4023 | devpriv->hw_revision = |
4024 | hw_revision(dev, readw(addr: devpriv->main_iobase + HW_STATUS_REG)); |
4025 | dev_dbg(dev->class_dev, "stc hardware revision %i\n" , |
4026 | devpriv->hw_revision); |
4027 | init_plx9080(dev); |
4028 | init_stc_registers(dev); |
4029 | |
4030 | retval = request_irq(irq: pcidev->irq, handler: handle_interrupt, IRQF_SHARED, |
4031 | name: "cb_pcidas64" , dev); |
4032 | if (retval) { |
4033 | dev_dbg(dev->class_dev, "unable to allocate irq %u\n" , |
4034 | pcidev->irq); |
4035 | return retval; |
4036 | } |
4037 | dev->irq = pcidev->irq; |
4038 | dev_dbg(dev->class_dev, "irq %u\n" , dev->irq); |
4039 | |
4040 | retval = setup_subdevices(dev); |
4041 | if (retval < 0) |
4042 | return retval; |
4043 | |
4044 | return 0; |
4045 | } |
4046 | |
4047 | static void detach(struct comedi_device *dev) |
4048 | { |
4049 | struct pcidas64_private *devpriv = dev->private; |
4050 | |
4051 | if (dev->irq) |
4052 | free_irq(dev->irq, dev); |
4053 | if (devpriv) { |
4054 | if (devpriv->plx9080_iobase) { |
4055 | disable_plx_interrupts(dev); |
4056 | iounmap(addr: devpriv->plx9080_iobase); |
4057 | } |
4058 | if (devpriv->main_iobase) |
4059 | iounmap(addr: devpriv->main_iobase); |
4060 | if (dev->mmio) |
4061 | iounmap(addr: dev->mmio); |
4062 | } |
4063 | comedi_pci_disable(dev); |
4064 | cb_pcidas64_free_dma(dev); |
4065 | } |
4066 | |
4067 | static struct comedi_driver cb_pcidas64_driver = { |
4068 | .driver_name = "cb_pcidas64" , |
4069 | .module = THIS_MODULE, |
4070 | .auto_attach = auto_attach, |
4071 | .detach = detach, |
4072 | }; |
4073 | |
4074 | static int cb_pcidas64_pci_probe(struct pci_dev *dev, |
4075 | const struct pci_device_id *id) |
4076 | { |
4077 | return comedi_pci_auto_config(pcidev: dev, driver: &cb_pcidas64_driver, |
4078 | context: id->driver_data); |
4079 | } |
4080 | |
4081 | static const struct pci_device_id cb_pcidas64_pci_table[] = { |
4082 | { PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 }, |
4083 | { PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 }, |
4084 | { PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 }, |
4085 | { PCI_VDEVICE(CB, 0x0036), BOARD_PCIDAS64_M2_16 }, |
4086 | { PCI_VDEVICE(CB, 0x0037), BOARD_PCIDAS64_M3_16 }, |
4087 | { PCI_VDEVICE(CB, 0x0052), BOARD_PCIDAS4020_12 }, |
4088 | { PCI_VDEVICE(CB, 0x005d), BOARD_PCIDAS6023 }, |
4089 | { PCI_VDEVICE(CB, 0x005e), BOARD_PCIDAS6025 }, |
4090 | { PCI_VDEVICE(CB, 0x005f), BOARD_PCIDAS6030 }, |
4091 | { PCI_VDEVICE(CB, 0x0060), BOARD_PCIDAS6031 }, |
4092 | { PCI_VDEVICE(CB, 0x0061), BOARD_PCIDAS6032 }, |
4093 | { PCI_VDEVICE(CB, 0x0062), BOARD_PCIDAS6033 }, |
4094 | { PCI_VDEVICE(CB, 0x0063), BOARD_PCIDAS6034 }, |
4095 | { PCI_VDEVICE(CB, 0x0064), BOARD_PCIDAS6035 }, |
4096 | { PCI_VDEVICE(CB, 0x0065), BOARD_PCIDAS6040 }, |
4097 | { PCI_VDEVICE(CB, 0x0066), BOARD_PCIDAS6052 }, |
4098 | { PCI_VDEVICE(CB, 0x0067), BOARD_PCIDAS6070 }, |
4099 | { PCI_VDEVICE(CB, 0x0068), BOARD_PCIDAS6071 }, |
4100 | { PCI_VDEVICE(CB, 0x006f), BOARD_PCIDAS6036 }, |
4101 | { PCI_VDEVICE(CB, 0x0078), BOARD_PCIDAS6013 }, |
4102 | { PCI_VDEVICE(CB, 0x0079), BOARD_PCIDAS6014 }, |
4103 | { 0 } |
4104 | }; |
4105 | MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table); |
4106 | |
4107 | static struct pci_driver cb_pcidas64_pci_driver = { |
4108 | .name = "cb_pcidas64" , |
4109 | .id_table = cb_pcidas64_pci_table, |
4110 | .probe = cb_pcidas64_pci_probe, |
4111 | .remove = comedi_pci_auto_unconfig, |
4112 | }; |
4113 | module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver); |
4114 | |
4115 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
4116 | MODULE_DESCRIPTION("Comedi low-level driver" ); |
4117 | MODULE_LICENSE("GPL" ); |
4118 | |