1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#include <linux/module.h>
39#include "../comedidev.h"
40
41
42
43
44#define S526_TIMER_REG 0x00
45#define S526_TIMER_LOAD(x) (((x) & 0xff) << 8)
46#define S526_TIMER_MODE ((x) << 1)
47#define S526_TIMER_MANUAL S526_TIMER_MODE(0)
48#define S526_TIMER_AUTO S526_TIMER_MODE(1)
49#define S526_TIMER_RESTART BIT(0)
50#define S526_WDOG_REG 0x02
51#define S526_WDOG_INVERTED BIT(4)
52#define S526_WDOG_ENA BIT(3)
53#define S526_WDOG_INTERVAL(x) (((x) & 0x7) << 0)
54#define S526_AO_CTRL_REG 0x04
55#define S526_AO_CTRL_RESET BIT(3)
56#define S526_AO_CTRL_CHAN(x) (((x) & 0x3) << 1)
57#define S526_AO_CTRL_START BIT(0)
58#define S526_AI_CTRL_REG 0x06
59#define S526_AI_CTRL_DELAY BIT(15)
60#define S526_AI_CTRL_CONV(x) (1 << (5 + ((x) & 0x9)))
61#define S526_AI_CTRL_READ(x) (((x) & 0xf) << 1)
62#define S526_AI_CTRL_START BIT(0)
63#define S526_AO_REG 0x08
64#define S526_AI_REG 0x08
65#define S526_DIO_CTRL_REG 0x0a
66#define S526_DIO_CTRL_DIO3_NEG BIT(15)
67#define S526_DIO_CTRL_DIO2_NEG BIT(14)
68#define S526_DIO_CTRL_DIO1_NEG BIT(13)
69#define S526_DIO_CTRL_DIO0_NEG BIT(12)
70#define S526_DIO_CTRL_GRP2_OUT BIT(11)
71#define S526_DIO_CTRL_GRP1_OUT BIT(10)
72#define S526_DIO_CTRL_GRP2_NEG BIT(8)
73#define S526_INT_ENA_REG 0x0c
74#define S526_INT_STATUS_REG 0x0e
75#define S526_INT_DIO(x) BIT(8 + ((x) & 0x7))
76#define S526_INT_EEPROM BIT(7)
77#define S526_INT_CNTR(x) BIT(3 + (3 - ((x) & 0x3)))
78#define S526_INT_AI BIT(2)
79#define S526_INT_AO BIT(1)
80#define S526_INT_TIMER BIT(0)
81#define S526_MISC_REG 0x10
82#define S526_MISC_LED_OFF BIT(0)
83#define S526_GPCT_LSB_REG(x) (0x12 + ((x) * 8))
84#define S526_GPCT_MSB_REG(x) (0x14 + ((x) * 8))
85#define S526_GPCT_MODE_REG(x) (0x16 + ((x) * 8))
86#define S526_GPCT_MODE_COUT_SRC(x) ((x) << 0)
87#define S526_GPCT_MODE_COUT_SRC_MASK S526_GPCT_MODE_COUT_SRC(0x1)
88#define S526_GPCT_MODE_COUT_SRC_RCAP S526_GPCT_MODE_COUT_SRC(0)
89#define S526_GPCT_MODE_COUT_SRC_RTGL S526_GPCT_MODE_COUT_SRC(1)
90#define S526_GPCT_MODE_COUT_POL(x) ((x) << 1)
91#define S526_GPCT_MODE_COUT_POL_MASK S526_GPCT_MODE_COUT_POL(0x1)
92#define S526_GPCT_MODE_COUT_POL_NORM S526_GPCT_MODE_COUT_POL(0)
93#define S526_GPCT_MODE_COUT_POL_INV S526_GPCT_MODE_COUT_POL(1)
94#define S526_GPCT_MODE_AUTOLOAD(x) ((x) << 2)
95#define S526_GPCT_MODE_AUTOLOAD_MASK S526_GPCT_MODE_AUTOLOAD(0x7)
96#define S526_GPCT_MODE_AUTOLOAD_NONE S526_GPCT_MODE_AUTOLOAD(0)
97
98#define S526_GPCT_MODE_AUTOLOAD_RO S526_GPCT_MODE_AUTOLOAD(0x1)
99#define S526_GPCT_MODE_AUTOLOAD_IXFALL S526_GPCT_MODE_AUTOLOAD(0x2)
100#define S526_GPCT_MODE_AUTOLOAD_IXRISE S526_GPCT_MODE_AUTOLOAD(0x4)
101#define S526_GPCT_MODE_HWCTEN_SRC(x) ((x) << 5)
102#define S526_GPCT_MODE_HWCTEN_SRC_MASK S526_GPCT_MODE_HWCTEN_SRC(0x3)
103#define S526_GPCT_MODE_HWCTEN_SRC_CEN S526_GPCT_MODE_HWCTEN_SRC(0)
104#define S526_GPCT_MODE_HWCTEN_SRC_IX S526_GPCT_MODE_HWCTEN_SRC(1)
105#define S526_GPCT_MODE_HWCTEN_SRC_IXRF S526_GPCT_MODE_HWCTEN_SRC(2)
106#define S526_GPCT_MODE_HWCTEN_SRC_NRCAP S526_GPCT_MODE_HWCTEN_SRC(3)
107#define S526_GPCT_MODE_CTEN_CTRL(x) ((x) << 7)
108#define S526_GPCT_MODE_CTEN_CTRL_MASK S526_GPCT_MODE_CTEN_CTRL(0x3)
109#define S526_GPCT_MODE_CTEN_CTRL_DIS S526_GPCT_MODE_CTEN_CTRL(0)
110#define S526_GPCT_MODE_CTEN_CTRL_ENA S526_GPCT_MODE_CTEN_CTRL(1)
111#define S526_GPCT_MODE_CTEN_CTRL_HW S526_GPCT_MODE_CTEN_CTRL(2)
112#define S526_GPCT_MODE_CTEN_CTRL_INVHW S526_GPCT_MODE_CTEN_CTRL(3)
113#define S526_GPCT_MODE_CLK_SRC(x) ((x) << 9)
114#define S526_GPCT_MODE_CLK_SRC_MASK S526_GPCT_MODE_CLK_SRC(0x3)
115
116#define S526_GPCT_MODE_CLK_SRC_QUADX1 S526_GPCT_MODE_CLK_SRC(0)
117#define S526_GPCT_MODE_CLK_SRC_QUADX2 S526_GPCT_MODE_CLK_SRC(1)
118#define S526_GPCT_MODE_CLK_SRC_QUADX4 S526_GPCT_MODE_CLK_SRC(2)
119#define S526_GPCT_MODE_CLK_SRC_QUADX4_ S526_GPCT_MODE_CLK_SRC(3)
120
121#define S526_GPCT_MODE_CLK_SRC_ARISE S526_GPCT_MODE_CLK_SRC(0)
122#define S526_GPCT_MODE_CLK_SRC_AFALL S526_GPCT_MODE_CLK_SRC(1)
123#define S526_GPCT_MODE_CLK_SRC_INT S526_GPCT_MODE_CLK_SRC(2)
124#define S526_GPCT_MODE_CLK_SRC_INTHALF S526_GPCT_MODE_CLK_SRC(3)
125#define S526_GPCT_MODE_CT_DIR(x) ((x) << 11)
126#define S526_GPCT_MODE_CT_DIR_MASK S526_GPCT_MODE_CT_DIR(0x1)
127
128#define S526_GPCT_MODE_CT_DIR_UP S526_GPCT_MODE_CT_DIR(0)
129#define S526_GPCT_MODE_CT_DIR_DOWN S526_GPCT_MODE_CT_DIR(1)
130#define S526_GPCT_MODE_CTDIR_CTRL(x) ((x) << 12)
131#define S526_GPCT_MODE_CTDIR_CTRL_MASK S526_GPCT_MODE_CTDIR_CTRL(0x1)
132#define S526_GPCT_MODE_CTDIR_CTRL_QUAD S526_GPCT_MODE_CTDIR_CTRL(0)
133#define S526_GPCT_MODE_CTDIR_CTRL_SOFT S526_GPCT_MODE_CTDIR_CTRL(1)
134#define S526_GPCT_MODE_LATCH_CTRL(x) ((x) << 13)
135#define S526_GPCT_MODE_LATCH_CTRL_MASK S526_GPCT_MODE_LATCH_CTRL(0x1)
136#define S526_GPCT_MODE_LATCH_CTRL_READ S526_GPCT_MODE_LATCH_CTRL(0)
137#define S526_GPCT_MODE_LATCH_CTRL_EVENT S526_GPCT_MODE_LATCH_CTRL(1)
138#define S526_GPCT_MODE_PR_SELECT(x) ((x) << 14)
139#define S526_GPCT_MODE_PR_SELECT_MASK S526_GPCT_MODE_PR_SELECT(0x1)
140#define S526_GPCT_MODE_PR_SELECT_PR0 S526_GPCT_MODE_PR_SELECT(0)
141#define S526_GPCT_MODE_PR_SELECT_PR1 S526_GPCT_MODE_PR_SELECT(1)
142
143#define S526_GPCT_CTRL_REG(x) (0x18 + ((x) * 8))
144#define S526_GPCT_CTRL_EV_STATUS(x) ((x) << 0)
145#define S526_GPCT_CTRL_EV_STATUS_MASK S526_GPCT_EV_STATUS(0xf)
146#define S526_GPCT_CTRL_EV_STATUS_NONE S526_GPCT_EV_STATUS(0)
147
148#define S526_GPCT_CTRL_EV_STATUS_ECAP S526_GPCT_EV_STATUS(0x1)
149#define S526_GPCT_CTRL_EV_STATUS_ICAPN S526_GPCT_EV_STATUS(0x2)
150#define S526_GPCT_CTRL_EV_STATUS_ICAPP S526_GPCT_EV_STATUS(0x4)
151#define S526_GPCT_CTRL_EV_STATUS_RCAP S526_GPCT_EV_STATUS(0x8)
152#define S526_GPCT_CTRL_COUT_STATUS BIT(4)
153#define S526_GPCT_CTRL_INDEX_STATUS BIT(5)
154#define S525_GPCT_CTRL_INTEN(x) ((x) << 6)
155#define S525_GPCT_CTRL_INTEN_MASK S526_GPCT_CTRL_INTEN(0xf)
156#define S525_GPCT_CTRL_INTEN_NONE S526_GPCT_CTRL_INTEN(0)
157
158#define S525_GPCT_CTRL_INTEN_ERROR S526_GPCT_CTRL_INTEN(0x1)
159#define S525_GPCT_CTRL_INTEN_IXFALL S526_GPCT_CTRL_INTEN(0x2)
160#define S525_GPCT_CTRL_INTEN_IXRISE S526_GPCT_CTRL_INTEN(0x4)
161#define S525_GPCT_CTRL_INTEN_RO S526_GPCT_CTRL_INTEN(0x8)
162#define S525_GPCT_CTRL_LATCH_SEL(x) ((x) << 10)
163#define S525_GPCT_CTRL_LATCH_SEL_MASK S526_GPCT_CTRL_LATCH_SEL(0x7)
164#define S525_GPCT_CTRL_LATCH_SEL_NONE S526_GPCT_CTRL_LATCH_SEL(0)
165
166#define S525_GPCT_CTRL_LATCH_SEL_IXFALL S526_GPCT_CTRL_LATCH_SEL(0x1)
167#define S525_GPCT_CTRL_LATCH_SEL_IXRISE S526_GPCT_CTRL_LATCH_SEL(0x2)
168#define S525_GPCT_CTRL_LATCH_SEL_ITIMER S526_GPCT_CTRL_LATCH_SEL(0x4)
169#define S525_GPCT_CTRL_CT_ARM BIT(13)
170#define S525_GPCT_CTRL_CT_LOAD BIT(14)
171#define S526_GPCT_CTRL_CT_RESET BIT(15)
172#define S526_EEPROM_DATA_REG 0x32
173#define S526_EEPROM_CTRL_REG 0x34
174#define S526_EEPROM_CTRL_ADDR(x) (((x) & 0x3f) << 3)
175#define S526_EEPROM_CTRL(x) (((x) & 0x3) << 1)
176#define S526_EEPROM_CTRL_READ S526_EEPROM_CTRL(2)
177#define S526_EEPROM_CTRL_START BIT(0)
178
179struct s526_private {
180 unsigned int gpct_config[4];
181 unsigned short ai_ctrl;
182};
183
184static void s526_gpct_write(struct comedi_device *dev,
185 unsigned int chan, unsigned int val)
186{
187
188 outw((val >> 16) & 0xffff, dev->iobase + S526_GPCT_MSB_REG(chan));
189 outw(val & 0xffff, dev->iobase + S526_GPCT_LSB_REG(chan));
190}
191
192static unsigned int s526_gpct_read(struct comedi_device *dev,
193 unsigned int chan)
194{
195 unsigned int val;
196
197
198 val = inw(dev->iobase + S526_GPCT_LSB_REG(chan)) & 0xffff;
199 val |= (inw(dev->iobase + S526_GPCT_MSB_REG(chan)) & 0xff) << 16;
200
201 return val;
202}
203
204static int s526_gpct_rinsn(struct comedi_device *dev,
205 struct comedi_subdevice *s,
206 struct comedi_insn *insn,
207 unsigned int *data)
208{
209 unsigned int chan = CR_CHAN(insn->chanspec);
210 int i;
211
212 for (i = 0; i < insn->n; i++)
213 data[i] = s526_gpct_read(dev, chan);
214
215 return insn->n;
216}
217
218static int s526_gpct_insn_config(struct comedi_device *dev,
219 struct comedi_subdevice *s,
220 struct comedi_insn *insn,
221 unsigned int *data)
222{
223 struct s526_private *devpriv = dev->private;
224 unsigned int chan = CR_CHAN(insn->chanspec);
225 unsigned int val;
226
227
228
229
230
231 switch (data[0]) {
232 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
233
234
235
236
237
238
239 devpriv->gpct_config[chan] = data[0];
240
241#if 1
242
243 val = data[1] & 0xffff;
244 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
245
246
247 if ((val & S526_GPCT_MODE_AUTOLOAD_MASK) ==
248 S526_GPCT_MODE_AUTOLOAD_NONE) {
249
250 outw(S526_GPCT_CTRL_CT_RESET,
251 dev->iobase + S526_GPCT_CTRL_REG(chan));
252
253
254
255
256
257 }
258#else
259 val = S526_GPCT_MODE_CTDIR_CTRL_QUAD;
260
261
262 if (data[1] == GPCT_X2)
263 val |= S526_GPCT_MODE_CLK_SRC_QUADX2;
264 else if (data[1] == GPCT_X4)
265 val |= S526_GPCT_MODE_CLK_SRC_QUADX4;
266 else
267 val |= S526_GPCT_MODE_CLK_SRC_QUADX1;
268
269
270
271
272
273
274
275
276
277
278 if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) {
279
280 val |= S526_GPCT_MODE_AUTOLOAD_IXRISE;
281 }
282
283
284 val = data[1] & 0xffff;
285 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
286
287
288 s526_gpct_write(dev, chan, data[2]);
289
290
291 if (data[3])
292 outw(data[3] & 0xffff,
293 dev->iobase + S526_GPCT_CTRL_REG(chan));
294
295
296 if ((val & S526_GPCT_MODE_AUTOLOAD_MASK) ==
297 S526_GPCT_MODE_AUTOLOAD_NONE) {
298
299 outw(S526_GPCT_CTRL_CT_RESET,
300 dev->iobase + S526_GPCT_CTRL_REG(chan));
301
302 outw(S526_GPCT_CTRL_CT_LOAD,
303 dev->iobase + S526_GPCT_CTRL_REG(chan));
304 }
305#endif
306 break;
307
308 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
309
310
311
312
313
314
315
316 devpriv->gpct_config[chan] = data[0];
317
318
319 val = data[1] & 0xffff;
320
321 val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
322 val |= S526_GPCT_MODE_PR_SELECT_PR0;
323 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
324
325
326 s526_gpct_write(dev, chan, data[2]);
327
328
329 val = data[1] & 0xffff;
330
331 val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
332 val |= S526_GPCT_MODE_PR_SELECT_PR1;
333 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
334
335
336 s526_gpct_write(dev, chan, data[3]);
337
338
339 if (data[4]) {
340 val = data[4] & 0xffff;
341 outw(val, dev->iobase + S526_GPCT_CTRL_REG(chan));
342 }
343 break;
344
345 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
346
347
348
349
350
351
352
353 devpriv->gpct_config[chan] = data[0];
354
355
356 val = data[1] & 0xffff;
357
358 val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
359 val |= S526_GPCT_MODE_PR_SELECT_PR0;
360 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
361
362
363 s526_gpct_write(dev, chan, data[2]);
364
365
366 val = data[1] & 0xffff;
367
368 val &= ~S526_GPCT_MODE_PR_SELECT_MASK;
369 val |= S526_GPCT_MODE_PR_SELECT_PR1;
370 outw(val, dev->iobase + S526_GPCT_MODE_REG(chan));
371
372
373 s526_gpct_write(dev, chan, data[3]);
374
375
376 if (data[4]) {
377 val = data[4] & 0xffff;
378 outw(val, dev->iobase + S526_GPCT_CTRL_REG(chan));
379 }
380 break;
381
382 default:
383 return -EINVAL;
384 }
385
386 return insn->n;
387}
388
389static int s526_gpct_winsn(struct comedi_device *dev,
390 struct comedi_subdevice *s,
391 struct comedi_insn *insn,
392 unsigned int *data)
393{
394 struct s526_private *devpriv = dev->private;
395 unsigned int chan = CR_CHAN(insn->chanspec);
396
397 inw(dev->iobase + S526_GPCT_MODE_REG(chan));
398
399
400 switch (devpriv->gpct_config[chan]) {
401 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
402
403
404
405
406
407
408
409 if ((data[1] <= data[0]) || !data[0])
410 return -EINVAL;
411
412
413
414 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
415 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
416 s526_gpct_write(dev, chan, data[0]);
417 break;
418
419 default:
420 return -EINVAL;
421 }
422
423 return insn->n;
424}
425
426static int s526_eoc(struct comedi_device *dev,
427 struct comedi_subdevice *s,
428 struct comedi_insn *insn,
429 unsigned long context)
430{
431 unsigned int status;
432
433 status = inw(dev->iobase + S526_INT_STATUS_REG);
434 if (status & context) {
435
436 outw(context, dev->iobase + S526_INT_STATUS_REG);
437 return 0;
438 }
439 return -EBUSY;
440}
441
442static int s526_ai_insn_read(struct comedi_device *dev,
443 struct comedi_subdevice *s,
444 struct comedi_insn *insn,
445 unsigned int *data)
446{
447 struct s526_private *devpriv = dev->private;
448 unsigned int chan = CR_CHAN(insn->chanspec);
449 unsigned int ctrl;
450 unsigned int val;
451 int ret;
452 int i;
453
454 ctrl = S526_AI_CTRL_CONV(chan) | S526_AI_CTRL_READ(chan) |
455 S526_AI_CTRL_START;
456 if (ctrl != devpriv->ai_ctrl) {
457
458
459
460
461 devpriv->ai_ctrl = ctrl;
462 ctrl |= S526_AI_CTRL_DELAY;
463 }
464
465 for (i = 0; i < insn->n; i++) {
466
467 outw(ctrl, dev->iobase + S526_AI_CTRL_REG);
468 ctrl &= ~S526_AI_CTRL_DELAY;
469
470
471 ret = comedi_timeout(dev, s, insn, s526_eoc, S526_INT_AI);
472 if (ret)
473 return ret;
474
475 val = inw(dev->iobase + S526_AI_REG);
476 data[i] = comedi_offset_munge(s, val);
477 }
478
479 return insn->n;
480}
481
482static int s526_ao_insn_write(struct comedi_device *dev,
483 struct comedi_subdevice *s,
484 struct comedi_insn *insn,
485 unsigned int *data)
486{
487 unsigned int chan = CR_CHAN(insn->chanspec);
488 unsigned int ctrl = S526_AO_CTRL_CHAN(chan);
489 unsigned int val = s->readback[chan];
490 int ret;
491 int i;
492
493 outw(ctrl, dev->iobase + S526_AO_CTRL_REG);
494 ctrl |= S526_AO_CTRL_START;
495
496 for (i = 0; i < insn->n; i++) {
497 val = data[i];
498 outw(val, dev->iobase + S526_AO_REG);
499 outw(ctrl, dev->iobase + S526_AO_CTRL_REG);
500
501
502 ret = comedi_timeout(dev, s, insn, s526_eoc, S526_INT_AO);
503 if (ret)
504 return ret;
505 }
506 s->readback[chan] = val;
507
508 return insn->n;
509}
510
511static int s526_dio_insn_bits(struct comedi_device *dev,
512 struct comedi_subdevice *s,
513 struct comedi_insn *insn,
514 unsigned int *data)
515{
516 if (comedi_dio_update_state(s, data))
517 outw(s->state, dev->iobase + S526_DIO_CTRL_REG);
518
519 data[1] = inw(dev->iobase + S526_DIO_CTRL_REG) & 0xff;
520
521 return insn->n;
522}
523
524static int s526_dio_insn_config(struct comedi_device *dev,
525 struct comedi_subdevice *s,
526 struct comedi_insn *insn,
527 unsigned int *data)
528{
529 unsigned int chan = CR_CHAN(insn->chanspec);
530 unsigned int mask;
531 int ret;
532
533
534
535
536
537 if (chan < 4)
538 mask = 0x0f;
539 else
540 mask = 0xf0;
541
542 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
543 if (ret)
544 return ret;
545
546 if (s->io_bits & 0x0f)
547 s->state |= S526_DIO_CTRL_GRP1_OUT;
548 else
549 s->state &= ~S526_DIO_CTRL_GRP1_OUT;
550 if (s->io_bits & 0xf0)
551 s->state |= S526_DIO_CTRL_GRP2_OUT;
552 else
553 s->state &= ~S526_DIO_CTRL_GRP2_OUT;
554
555 outw(s->state, dev->iobase + S526_DIO_CTRL_REG);
556
557 return insn->n;
558}
559
560static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
561{
562 struct s526_private *devpriv;
563 struct comedi_subdevice *s;
564 int ret;
565
566 ret = comedi_request_region(dev, it->options[0], 0x40);
567 if (ret)
568 return ret;
569
570 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
571 if (!devpriv)
572 return -ENOMEM;
573
574 ret = comedi_alloc_subdevices(dev, 4);
575 if (ret)
576 return ret;
577
578
579 s = &dev->subdevices[0];
580 s->type = COMEDI_SUBD_COUNTER;
581 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
582 s->n_chan = 4;
583 s->maxdata = 0x00ffffff;
584 s->insn_read = s526_gpct_rinsn;
585 s->insn_config = s526_gpct_insn_config;
586 s->insn_write = s526_gpct_winsn;
587
588
589
590
591
592
593
594 s = &dev->subdevices[1];
595 s->type = COMEDI_SUBD_AI;
596 s->subdev_flags = SDF_READABLE | SDF_DIFF;
597 s->n_chan = 10;
598 s->maxdata = 0xffff;
599 s->range_table = &range_bipolar10;
600 s->len_chanlist = 16;
601 s->insn_read = s526_ai_insn_read;
602
603
604 s = &dev->subdevices[2];
605 s->type = COMEDI_SUBD_AO;
606 s->subdev_flags = SDF_WRITABLE;
607 s->n_chan = 4;
608 s->maxdata = 0xffff;
609 s->range_table = &range_bipolar10;
610 s->insn_write = s526_ao_insn_write;
611
612 ret = comedi_alloc_subdev_readback(s);
613 if (ret)
614 return ret;
615
616
617 s = &dev->subdevices[3];
618 s->type = COMEDI_SUBD_DIO;
619 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
620 s->n_chan = 8;
621 s->maxdata = 1;
622 s->range_table = &range_digital;
623 s->insn_bits = s526_dio_insn_bits;
624 s->insn_config = s526_dio_insn_config;
625
626 return 0;
627}
628
629static struct comedi_driver s526_driver = {
630 .driver_name = "s526",
631 .module = THIS_MODULE,
632 .attach = s526_attach,
633 .detach = comedi_legacy_detach,
634};
635module_comedi_driver(s526_driver);
636
637MODULE_AUTHOR("Comedi http://www.comedi.org");
638MODULE_DESCRIPTION("Comedi low-level driver");
639MODULE_LICENSE("GPL");
640