Merge tag 'hsi-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi
[cascardo/linux.git] / drivers / staging / comedi / drivers / das6402.c
1 /*
2  * das6402.c
3  * Comedi driver for DAS6402 compatible boards
4  * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
5  *
6  * Rewrite of an experimental driver by:
7  * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19
20 /*
21  * Driver: das6402
22  * Description: Keithley Metrabyte DAS6402 (& compatibles)
23  * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12)
24  *          (Keithley Metrabyte) DAS6402-16 (das6402-16)
25  * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
26  * Updated: Fri, 14 Mar 2014 10:18:43 -0700
27  * Status: unknown
28  *
29  * Configuration Options:
30  *   [0] - I/O base address
31  *   [1] - IRQ (optional, needed for async command support)
32  */
33
34 #include <linux/module.h>
35 #include <linux/interrupt.h>
36
37 #include "../comedidev.h"
38 #include "8253.h"
39
40 /*
41  * Register I/O map
42  */
43 #define DAS6402_AI_DATA_REG             0x00
44 #define DAS6402_AI_MUX_REG              0x02
45 #define DAS6402_AI_MUX_LO(x)            (((x) & 0x3f) << 0)
46 #define DAS6402_AI_MUX_HI(x)            (((x) & 0x3f) << 8)
47 #define DAS6402_DI_DO_REG               0x03
48 #define DAS6402_AO_DATA_REG(x)          (0x04 + ((x) * 2))
49 #define DAS6402_AO_LSB_REG(x)           (0x04 + ((x) * 2))
50 #define DAS6402_AO_MSB_REG(x)           (0x05 + ((x) * 2))
51 #define DAS6402_STATUS_REG              0x08
52 #define DAS6402_STATUS_FFNE             (1 << 0)
53 #define DAS6402_STATUS_FHALF            (1 << 1)
54 #define DAS6402_STATUS_FFULL            (1 << 2)
55 #define DAS6402_STATUS_XINT             (1 << 3)
56 #define DAS6402_STATUS_INT              (1 << 4)
57 #define DAS6402_STATUS_XTRIG            (1 << 5)
58 #define DAS6402_STATUS_INDGT            (1 << 6)
59 #define DAS6402_STATUS_10MHZ            (1 << 7)
60 #define DAS6402_STATUS_W_CLRINT         (1 << 0)
61 #define DAS6402_STATUS_W_CLRXTR         (1 << 1)
62 #define DAS6402_STATUS_W_CLRXIN         (1 << 2)
63 #define DAS6402_STATUS_W_EXTEND         (1 << 4)
64 #define DAS6402_STATUS_W_ARMED          (1 << 5)
65 #define DAS6402_STATUS_W_POSTMODE       (1 << 6)
66 #define DAS6402_STATUS_W_10MHZ          (1 << 7)
67 #define DAS6402_CTRL_REG                0x09
68 #define DAS6402_CTRL_SOFT_TRIG          (0 << 0)
69 #define DAS6402_CTRL_EXT_FALL_TRIG      (1 << 0)
70 #define DAS6402_CTRL_EXT_RISE_TRIG      (2 << 0)
71 #define DAS6402_CTRL_PACER_TRIG         (3 << 0)
72 #define DAS6402_CTRL_BURSTEN            (1 << 2)
73 #define DAS6402_CTRL_XINTE              (1 << 3)
74 #define DAS6402_CTRL_IRQ(x)             ((x) << 4)
75 #define DAS6402_CTRL_INTE               (1 << 7)
76 #define DAS6402_TRIG_REG                0x0a
77 #define DAS6402_TRIG_TGEN               (1 << 0)
78 #define DAS6402_TRIG_TGSEL              (1 << 1)
79 #define DAS6402_TRIG_TGPOL              (1 << 2)
80 #define DAS6402_TRIG_PRETRIG            (1 << 3)
81 #define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4))
82 #define DAS6402_AO_RANGE_MASK(_chan)    (3 << ((_chan) ? 6 : 4))
83 #define DAS6402_MODE_REG                0x0b
84 #define DAS6402_MODE_RANGE(x)           ((x) << 0)
85 #define DAS6402_MODE_POLLED             (0 << 2)
86 #define DAS6402_MODE_FIFONEPTY          (1 << 2)
87 #define DAS6402_MODE_FIFOHFULL          (2 << 2)
88 #define DAS6402_MODE_EOB                (3 << 2)
89 #define DAS6402_MODE_ENHANCED           (1 << 4)
90 #define DAS6402_MODE_SE                 (1 << 5)
91 #define DAS6402_MODE_UNI                (1 << 6)
92 #define DAS6402_MODE_DMA1               (0 << 7)
93 #define DAS6402_MODE_DMA3               (1 << 7)
94 #define DAS6402_TIMER_BASE              0x0c
95
96 static const struct comedi_lrange das6402_ai_ranges = {
97         8, {
98                 BIP_RANGE(10),
99                 BIP_RANGE(5),
100                 BIP_RANGE(2.5),
101                 BIP_RANGE(1.25),
102                 UNI_RANGE(10),
103                 UNI_RANGE(5),
104                 UNI_RANGE(2.5),
105                 UNI_RANGE(1.25)
106         }
107 };
108
109 /*
110  * Analog output ranges are programmable on the DAS6402/12.
111  * For the DAS6402/16 the range bits have no function, the
112  * DAC ranges are selected by switches on the board.
113  */
114 static const struct comedi_lrange das6402_ao_ranges = {
115         4, {
116                 BIP_RANGE(5),
117                 BIP_RANGE(10),
118                 UNI_RANGE(5),
119                 UNI_RANGE(10)
120         }
121 };
122
123 struct das6402_boardinfo {
124         const char *name;
125         unsigned int maxdata;
126 };
127
128 static struct das6402_boardinfo das6402_boards[] = {
129         {
130                 .name           = "das6402-12",
131                 .maxdata        = 0x0fff,
132         }, {
133                 .name           = "das6402-16",
134                 .maxdata        = 0xffff,
135         },
136 };
137
138 struct das6402_private {
139         unsigned int irq;
140
141         unsigned int count;
142         unsigned int divider1;
143         unsigned int divider2;
144
145         unsigned int ao_range;
146         unsigned int ao_readback[2];
147 };
148
149 static void das6402_set_mode(struct comedi_device *dev,
150                              unsigned int mode)
151 {
152         outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG);
153 }
154
155 static void das6402_set_extended(struct comedi_device *dev,
156                                  unsigned int val)
157 {
158         outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG);
159         outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG);
160         outb(val, dev->iobase + DAS6402_STATUS_REG);
161 }
162
163 static void das6402_clear_all_interrupts(struct comedi_device *dev)
164 {
165         outb(DAS6402_STATUS_W_CLRINT |
166              DAS6402_STATUS_W_CLRXTR |
167              DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG);
168 }
169
170 static void das6402_ai_clear_eoc(struct comedi_device *dev)
171 {
172         outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG);
173 }
174
175 static void das6402_enable_counter(struct comedi_device *dev, bool load)
176 {
177         struct das6402_private *devpriv = dev->private;
178         unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE;
179
180         if (load) {
181                 i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
182                 i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY);
183                 i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY);
184
185                 i8254_write(timer_iobase, 0, 0, devpriv->count);
186                 i8254_write(timer_iobase, 0, 1, devpriv->divider1);
187                 i8254_write(timer_iobase, 0, 2, devpriv->divider2);
188
189         } else {
190                 i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY);
191                 i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY);
192                 i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY);
193         }
194 }
195
196 static irqreturn_t das6402_interrupt(int irq, void *d)
197 {
198         struct comedi_device *dev = d;
199
200         das6402_clear_all_interrupts(dev);
201
202         return IRQ_HANDLED;
203 }
204
205 static int das6402_ai_cmd(struct comedi_device *dev,
206                           struct comedi_subdevice *s)
207 {
208         return -EINVAL;
209 }
210
211 static int das6402_ai_cmdtest(struct comedi_device *dev,
212                               struct comedi_subdevice *s,
213                               struct comedi_cmd *cmd)
214 {
215         return -EINVAL;
216 }
217
218 static int das6402_ai_cancel(struct comedi_device *dev,
219                              struct comedi_subdevice *s)
220 {
221         outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
222
223         return 0;
224 }
225
226 static void das6402_ai_soft_trig(struct comedi_device *dev)
227 {
228         outw(0, dev->iobase + DAS6402_AI_DATA_REG);
229 }
230
231 static int das6402_ai_eoc(struct comedi_device *dev,
232                           struct comedi_subdevice *s,
233                           struct comedi_insn *insn,
234                           unsigned long context)
235 {
236         unsigned int status;
237
238         status = inb(dev->iobase + DAS6402_STATUS_REG);
239         if (status & DAS6402_STATUS_FFNE)
240                 return 0;
241         return -EBUSY;
242 }
243
244 static int das6402_ai_insn_read(struct comedi_device *dev,
245                                 struct comedi_subdevice *s,
246                                 struct comedi_insn *insn,
247                                 unsigned int *data)
248 {
249         unsigned int chan = CR_CHAN(insn->chanspec);
250         unsigned int range = CR_RANGE(insn->chanspec);
251         unsigned int aref = CR_AREF(insn->chanspec);
252         unsigned int val;
253         int ret;
254         int i;
255
256         val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED;
257         if (aref == AREF_DIFF) {
258                 if (chan > s->n_chan / 2)
259                         return -EINVAL;
260         } else {
261                 val |= DAS6402_MODE_SE;
262         }
263         if (comedi_range_is_unipolar(s, range))
264                 val |= DAS6402_MODE_UNI;
265
266         /* enable software conversion trigger */
267         outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
268
269         das6402_set_mode(dev, val);
270
271         /* load the mux for single channel conversion */
272         outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan),
273              dev->iobase + DAS6402_AI_MUX_REG);
274
275         for (i = 0; i < insn->n; i++) {
276                 das6402_ai_clear_eoc(dev);
277                 das6402_ai_soft_trig(dev);
278
279                 ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0);
280                 if (ret)
281                         break;
282
283                 val = inw(dev->iobase + DAS6402_AI_DATA_REG);
284
285                 if (s->maxdata == 0x0fff)
286                         val >>= 4;
287
288                 data[i] = val;
289         }
290
291         das6402_ai_clear_eoc(dev);
292
293         return insn->n;
294 }
295
296 static int das6402_ao_insn_write(struct comedi_device *dev,
297                                  struct comedi_subdevice *s,
298                                  struct comedi_insn *insn,
299                                  unsigned int *data)
300 {
301         struct das6402_private *devpriv = dev->private;
302         unsigned int chan = CR_CHAN(insn->chanspec);
303         unsigned int range = CR_RANGE(insn->chanspec);
304         unsigned int val;
305         int i;
306
307         /* set the range for this channel */
308         val = devpriv->ao_range;
309         val &= ~DAS6402_AO_RANGE_MASK(chan);
310         val |= DAS6402_AO_RANGE(chan, range);
311         if (val != devpriv->ao_range) {
312                 devpriv->ao_range = val;
313                 outb(val, dev->iobase + DAS6402_TRIG_REG);
314         }
315
316         /*
317          * The DAS6402/16 has a jumper to select either individual
318          * update (UPDATE) or simultaneous updating (XFER) of both
319          * DAC's. In UPDATE mode, when the MSB is written, that DAC
320          * is updated. In XFER mode, after both DAC's are loaded,
321          * a read cycle of any DAC register will update both DAC's
322          * simultaneously.
323          *
324          * If you have XFER mode enabled a (*insn_read) will need
325          * to be performed in order to update the DAC's with the
326          * last value written.
327          */
328         for (i = 0; i < insn->n; i++) {
329                 val = data[i];
330
331                 devpriv->ao_readback[chan] = val;
332
333                 if (s->maxdata == 0x0fff) {
334                         /*
335                          * DAS6402/12 has the two 8-bit DAC registers, left
336                          * justified (the 4 LSB bits are don't care). Data
337                          * can be written as one word.
338                          */
339                         val <<= 4;
340                         outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan));
341                 } else {
342                         /*
343                          * DAS6402/16 uses both 8-bit DAC registers and needs
344                          * to be written LSB then MSB.
345                          */
346                         outb(val & 0xff,
347                              dev->iobase + DAS6402_AO_LSB_REG(chan));
348                         outb((val >> 8) & 0xff,
349                              dev->iobase + DAS6402_AO_LSB_REG(chan));
350                 }
351         }
352
353         return insn->n;
354 }
355
356 static int das6402_ao_insn_read(struct comedi_device *dev,
357                                 struct comedi_subdevice *s,
358                                 struct comedi_insn *insn,
359                                 unsigned int *data)
360 {
361         struct das6402_private *devpriv = dev->private;
362         unsigned int chan = CR_CHAN(insn->chanspec);
363         int i;
364
365         /*
366          * If XFER mode is enabled, reading any DAC register
367          * will update both DAC's simultaneously.
368          */
369         inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
370
371         for (i = 0; i < insn->n; i++)
372                 data[i] = devpriv->ao_readback[chan];
373
374         return insn->n;
375 }
376
377 static int das6402_di_insn_bits(struct comedi_device *dev,
378                                 struct comedi_subdevice *s,
379                                 struct comedi_insn *insn,
380                                 unsigned int *data)
381 {
382         data[1] = inb(dev->iobase + DAS6402_DI_DO_REG);
383
384         return insn->n;
385 }
386
387 static int das6402_do_insn_bits(struct comedi_device *dev,
388                                 struct comedi_subdevice *s,
389                                 struct comedi_insn *insn,
390                                 unsigned int *data)
391 {
392         if (comedi_dio_update_state(s, data))
393                 outb(s->state, dev->iobase + DAS6402_DI_DO_REG);
394
395         data[1] = s->state;
396
397         return insn->n;
398 }
399
400 static void das6402_reset(struct comedi_device *dev)
401 {
402         struct das6402_private *devpriv = dev->private;
403
404         /* enable "Enhanced" mode */
405         outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG);
406
407         /* enable 10MHz pacer clock */
408         das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ);
409
410         /* enable software conversion trigger */
411         outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
412
413         /* default ADC to single-ended unipolar 10V inputs */
414         das6402_set_mode(dev, DAS6402_MODE_RANGE(0) |
415                               DAS6402_MODE_POLLED |
416                               DAS6402_MODE_SE |
417                               DAS6402_MODE_UNI);
418
419         /* default mux for single channel conversion (channel 0) */
420         outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0),
421              dev->iobase + DAS6402_AI_MUX_REG);
422
423         /* set both DAC's for unipolar 5V output range */
424         devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2);
425         outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG);
426
427         /* set both DAC's to 0V */
428         outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
429         outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
430         inw(dev->iobase + DAS6402_AO_LSB_REG(0));
431
432         das6402_enable_counter(dev, false);
433
434         /* set all digital outputs low */
435         outb(0, dev->iobase + DAS6402_DI_DO_REG);
436
437         das6402_clear_all_interrupts(dev);
438 }
439
440 static int das6402_attach(struct comedi_device *dev,
441                           struct comedi_devconfig *it)
442 {
443         const struct das6402_boardinfo *board = comedi_board(dev);
444         struct das6402_private *devpriv;
445         struct comedi_subdevice *s;
446         int ret;
447
448         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
449         if (!devpriv)
450                 return -ENOMEM;
451
452         ret = comedi_request_region(dev, it->options[0], 0x10);
453         if (ret)
454                 return ret;
455
456         das6402_reset(dev);
457
458         /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */
459         if ((1 << it->options[1]) & 0x8cec) {
460                 ret = request_irq(it->options[1], das6402_interrupt, 0,
461                                   dev->board_name, dev);
462                 if (ret == 0) {
463                         dev->irq = it->options[1];
464
465                         switch (dev->irq) {
466                         case 10:
467                                 devpriv->irq = 4;
468                                 break;
469                         case 11:
470                                 devpriv->irq = 1;
471                                 break;
472                         case 15:
473                                 devpriv->irq = 6;
474                                 break;
475                         default:
476                                 devpriv->irq = dev->irq;
477                                 break;
478                         }
479                 }
480         }
481
482         ret = comedi_alloc_subdevices(dev, 4);
483         if (ret)
484                 return ret;
485
486         /* Analog Input subdevice */
487         s = &dev->subdevices[0];
488         s->type         = COMEDI_SUBD_AI;
489         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
490         s->n_chan       = 64;
491         s->maxdata      = board->maxdata;
492         s->range_table  = &das6402_ai_ranges;
493         s->insn_read    = das6402_ai_insn_read;
494         if (dev->irq) {
495                 dev->read_subdev = s;
496                 s->subdev_flags |= SDF_CMD_READ;
497                 s->len_chanlist = s->n_chan;
498                 s->do_cmdtest   = das6402_ai_cmdtest;
499                 s->do_cmd       = das6402_ai_cmd;
500                 s->cancel       = das6402_ai_cancel;
501         }
502
503         /* Analog Output subdevice */
504         s = &dev->subdevices[1];
505         s->type         = COMEDI_SUBD_AO;
506         s->subdev_flags = SDF_WRITEABLE;
507         s->n_chan       = 2;
508         s->maxdata      = board->maxdata;
509         s->range_table  = &das6402_ao_ranges;
510         s->insn_write   = das6402_ao_insn_write;
511         s->insn_read    = das6402_ao_insn_read;
512
513         /* Digital Input subdevice */
514         s = &dev->subdevices[2];
515         s->type         = COMEDI_SUBD_DI;
516         s->subdev_flags = SDF_READABLE;
517         s->n_chan       = 8;
518         s->maxdata      = 1;
519         s->range_table  = &range_digital;
520         s->insn_bits    = das6402_di_insn_bits;
521
522         /* Digital Input subdevice */
523         s = &dev->subdevices[3];
524         s->type         = COMEDI_SUBD_DO;
525         s->subdev_flags = SDF_WRITEABLE;
526         s->n_chan       = 8;
527         s->maxdata      = 1;
528         s->range_table  = &range_digital;
529         s->insn_bits    = das6402_do_insn_bits;
530
531         return 0;
532 }
533
534 static struct comedi_driver das6402_driver = {
535         .driver_name    = "das6402",
536         .module         = THIS_MODULE,
537         .attach         = das6402_attach,
538         .detach         = comedi_legacy_detach,
539         .board_name     = &das6402_boards[0].name,
540         .num_names      = ARRAY_SIZE(das6402_boards),
541         .offset         = sizeof(struct das6402_boardinfo),
542 };
543 module_comedi_driver(das6402_driver)
544
545 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
546 MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards");
547 MODULE_LICENSE("GPL");