Merge remote-tracking branch 'asoc/topic/max98088' into asoc-next
[cascardo/linux.git] / drivers / staging / comedi / drivers / poc.c
1 /*
2     comedi/drivers/poc.c
3     Mini-drivers for POC (Piece of Crap) boards
4     Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
5     Copyright (C) 2001 David A. Schleef <ds@schleef.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 */
17 /*
18 Driver: poc
19 Description: Generic driver for very simple devices
20 Author: ds
21 Devices: [Keithley Metrabyte] DAC-02 (dac02)
22 Updated: Sat, 16 Mar 2002 17:34:48 -0800
23 Status: unknown
24
25 This driver is indended to support very simple ISA-based devices,
26 including:
27   dac02 - Keithley DAC-02 analog output board
28
29 Configuration options:
30   [0] - I/O port base
31 */
32
33 #include <linux/module.h>
34 #include "../comedidev.h"
35
36 struct boarddef_struct {
37         const char *name;
38         unsigned int iosize;
39         int (*setup) (struct comedi_device *);
40         int type;
41         int n_chan;
42         int n_bits;
43         int (*winsn) (struct comedi_device *, struct comedi_subdevice *,
44                       struct comedi_insn *, unsigned int *);
45         int (*rinsn) (struct comedi_device *, struct comedi_subdevice *,
46                       struct comedi_insn *, unsigned int *);
47         int (*insnbits) (struct comedi_device *, struct comedi_subdevice *,
48                          struct comedi_insn *, unsigned int *);
49         const struct comedi_lrange *range;
50 };
51
52 struct poc_private {
53         unsigned int ao_readback[32];
54 };
55
56 static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
57                          struct comedi_insn *insn, unsigned int *data)
58 {
59         struct poc_private *devpriv = dev->private;
60         int chan;
61
62         chan = CR_CHAN(insn->chanspec);
63         data[0] = devpriv->ao_readback[chan];
64
65         return 1;
66 }
67
68 /* DAC-02 registers */
69 #define DAC02_LSB(a)    (2 * a)
70 #define DAC02_MSB(a)    (2 * a + 1)
71
72 static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
73                           struct comedi_insn *insn, unsigned int *data)
74 {
75         struct poc_private *devpriv = dev->private;
76         int temp;
77         int chan;
78         int output;
79
80         chan = CR_CHAN(insn->chanspec);
81         devpriv->ao_readback[chan] = data[0];
82         output = data[0];
83 #ifdef wrong
84         /*  convert to complementary binary if range is bipolar */
85         if ((CR_RANGE(insn->chanspec) & 0x2) == 0)
86                 output = ~output;
87 #endif
88         temp = (output << 4) & 0xf0;
89         outb(temp, dev->iobase + DAC02_LSB(chan));
90         temp = (output >> 4) & 0xff;
91         outb(temp, dev->iobase + DAC02_MSB(chan));
92
93         return 1;
94 }
95
96 static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
97 {
98         const struct boarddef_struct *board = comedi_board(dev);
99         struct poc_private *devpriv;
100         struct comedi_subdevice *s;
101         int ret;
102
103         ret = comedi_request_region(dev, it->options[0], board->iosize);
104         if (ret)
105                 return ret;
106
107         ret = comedi_alloc_subdevices(dev, 1);
108         if (ret)
109                 return ret;
110
111         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
112         if (!devpriv)
113                 return -ENOMEM;
114
115         /* analog output subdevice */
116         s = &dev->subdevices[0];
117         s->type = board->type;
118         s->n_chan = board->n_chan;
119         s->maxdata = (1 << board->n_bits) - 1;
120         s->range_table = board->range;
121         s->insn_write = board->winsn;
122         s->insn_read = board->rinsn;
123         s->insn_bits = board->insnbits;
124         if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
125                 s->subdev_flags = SDF_WRITABLE;
126
127         return 0;
128 }
129
130 static const struct boarddef_struct boards[] = {
131         {
132                 .name           = "dac02",
133                 .iosize         = 8,
134                 /* .setup       = dac02_setup, */
135                 .type           = COMEDI_SUBD_AO,
136                 .n_chan         = 2,
137                 .n_bits         = 12,
138                 .winsn          = dac02_ao_winsn,
139                 .rinsn          = readback_insn,
140                 .range          = &range_unknown,
141         },
142 };
143
144 static struct comedi_driver poc_driver = {
145         .driver_name    = "poc",
146         .module         = THIS_MODULE,
147         .attach         = poc_attach,
148         .detach         = comedi_legacy_detach,
149         .board_name     = &boards[0].name,
150         .num_names      = ARRAY_SIZE(boards),
151         .offset         = sizeof(boards[0]),
152 };
153 module_comedi_driver(poc_driver);
154
155 MODULE_AUTHOR("Comedi http://www.comedi.org");
156 MODULE_DESCRIPTION("Comedi low-level driver");
157 MODULE_LICENSE("GPL");