]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/mpc624.c
Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[karo-tx-linux.git] / drivers / staging / comedi / drivers / mpc624.c
1 /*
2     comedi/drivers/mpc624.c
3     Hardware driver for a Micro/sys inc. MPC-624 PC/104 board
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 */
18 /*
19 Driver: mpc624
20 Description: Micro/sys MPC-624 PC/104 board
21 Devices: [Micro/sys] MPC-624 (mpc624)
22 Author: Stanislaw Raczynski <sraczynski@op.pl>
23 Updated: Thu, 15 Sep 2005 12:01:18 +0200
24 Status: working
25
26     The Micro/sys MPC-624 board is based on the LTC2440 24-bit sigma-delta
27     ADC chip.
28
29     Subdevices supported by the driver:
30     - Analog In:   supported
31     - Digital I/O: not supported
32     - LEDs:        not supported
33     - EEPROM:      not supported
34
35 Configuration Options:
36   [0] - I/O base address
37   [1] - conversion rate
38         Conversion rate  RMS noise  Effective Number Of Bits
39         0      3.52kHz        23uV                17
40         1      1.76kHz       3.5uV                20
41         2       880Hz         2uV                21.3
42         3       440Hz        1.4uV               21.8
43         4       220Hz         1uV                22.4
44         5       110Hz        750uV               22.9
45         6       55Hz         510nV               23.4
46         7      27.5Hz        375nV                24
47         8      13.75Hz       250nV               24.4
48         9      6.875Hz       200nV               24.6
49   [2] - voltage range
50         0      -1.01V .. +1.01V
51         1      -10.1V .. +10.1V
52 */
53
54 #include <linux/module.h>
55 #include "../comedidev.h"
56
57 #include <linux/delay.h>
58
59 /* Consecutive I/O port addresses */
60 #define MPC624_SIZE             16
61
62 /* Offsets of different ports */
63 #define MPC624_MASTER_CONTROL   0 /* not used */
64 #define MPC624_GNMUXCH          1 /* Gain, Mux, Channel of ADC */
65 #define MPC624_ADC              2 /* read/write to/from ADC */
66 #define MPC624_EE               3 /* read/write to/from serial EEPROM via I2C */
67 #define MPC624_LEDS             4 /* write to LEDs */
68 #define MPC624_DIO              5 /* read/write to/from digital I/O ports */
69 #define MPC624_IRQ_MASK         6 /* IRQ masking enable/disable */
70
71 /* Register bits' names */
72 #define MPC624_ADBUSY           (1<<5)
73 #define MPC624_ADSDO            (1<<4)
74 #define MPC624_ADFO             (1<<3)
75 #define MPC624_ADCS             (1<<2)
76 #define MPC624_ADSCK            (1<<1)
77 #define MPC624_ADSDI            (1<<0)
78
79 /* SDI Speed/Resolution Programming bits */
80 #define MPC624_OSR4             (1<<31)
81 #define MPC624_OSR3             (1<<30)
82 #define MPC624_OSR2             (1<<29)
83 #define MPC624_OSR1             (1<<28)
84 #define MPC624_OSR0             (1<<27)
85
86 /* 32-bit output value bits' names */
87 #define MPC624_EOC_BIT          (1<<31)
88 #define MPC624_DMY_BIT          (1<<30)
89 #define MPC624_SGN_BIT          (1<<29)
90
91 /* Conversion speeds */
92 /* OSR4 OSR3 OSR2 OSR1 OSR0  Conversion rate  RMS noise  ENOB^
93  *  X    0    0    0    1        3.52kHz        23uV      17
94  *  X    0    0    1    0        1.76kHz       3.5uV      20
95  *  X    0    0    1    1         880Hz         2uV      21.3
96  *  X    0    1    0    0         440Hz        1.4uV     21.8
97  *  X    0    1    0    1         220Hz         1uV      22.4
98  *  X    0    1    1    0         110Hz        750uV     22.9
99  *  X    0    1    1    1          55Hz        510nV     23.4
100  *  X    1    0    0    0         27.5Hz       375nV      24
101  *  X    1    0    0    1        13.75Hz       250nV     24.4
102  *  X    1    1    1    1        6.875Hz       200nV     24.6
103  *
104  * ^ - Effective Number Of Bits
105  */
106
107 #define MPC624_SPEED_3_52_kHz (MPC624_OSR4 | MPC624_OSR0)
108 #define MPC624_SPEED_1_76_kHz (MPC624_OSR4 | MPC624_OSR1)
109 #define MPC624_SPEED_880_Hz   (MPC624_OSR4 | MPC624_OSR1 | MPC624_OSR0)
110 #define MPC624_SPEED_440_Hz   (MPC624_OSR4 | MPC624_OSR2)
111 #define MPC624_SPEED_220_Hz   (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR0)
112 #define MPC624_SPEED_110_Hz   (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1)
113 #define MPC624_SPEED_55_Hz \
114         (MPC624_OSR4 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0)
115 #define MPC624_SPEED_27_5_Hz  (MPC624_OSR4 | MPC624_OSR3)
116 #define MPC624_SPEED_13_75_Hz (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR0)
117 #define MPC624_SPEED_6_875_Hz \
118         (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0)
119 /* -------------------------------------------------------------------------- */
120 struct mpc624_private {
121
122         /*  set by mpc624_attach() from driver's parameters */
123         unsigned long int ulConvertionRate;
124 };
125
126 /* -------------------------------------------------------------------------- */
127 static const struct comedi_lrange range_mpc624_bipolar1 = {
128         1,
129         {
130 /* BIP_RANGE(1.01)  this is correct, */
131          /*  but my MPC-624 actually seems to have a range of 2.02 */
132          BIP_RANGE(2.02)
133          }
134 };
135
136 static const struct comedi_lrange range_mpc624_bipolar10 = {
137         1,
138         {
139 /* BIP_RANGE(10.1)   this is correct, */
140          /*  but my MPC-624 actually seems to have a range of 20.2 */
141          BIP_RANGE(20.2)
142          }
143 };
144
145 /* Timeout 200ms */
146 #define TIMEOUT 200
147
148 static int mpc624_ai_rinsn(struct comedi_device *dev,
149                            struct comedi_subdevice *s, struct comedi_insn *insn,
150                            unsigned int *data)
151 {
152         struct mpc624_private *devpriv = dev->private;
153         int n, i;
154         unsigned long int data_in, data_out;
155         unsigned char ucPort;
156
157         /*
158          *  WARNING:
159          *  We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc
160          */
161         outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH);
162 /* printk("Channel %d:\n", insn->chanspec); */
163         if (!insn->n) {
164                 printk(KERN_INFO "MPC624: Warning, no data to acquire\n");
165                 return 0;
166         }
167
168         for (n = 0; n < insn->n; n++) {
169                 /*  Trigger the conversion */
170                 outb(MPC624_ADSCK, dev->iobase + MPC624_ADC);
171                 udelay(1);
172                 outb(MPC624_ADCS | MPC624_ADSCK, dev->iobase + MPC624_ADC);
173                 udelay(1);
174                 outb(0, dev->iobase + MPC624_ADC);
175                 udelay(1);
176
177                 /*  Wait for the conversion to end */
178                 for (i = 0; i < TIMEOUT; i++) {
179                         ucPort = inb(dev->iobase + MPC624_ADC);
180                         if (ucPort & MPC624_ADBUSY)
181                                 udelay(1000);
182                         else
183                                 break;
184                 }
185                 if (i == TIMEOUT) {
186                         printk(KERN_ERR "MPC624: timeout (%dms)\n", TIMEOUT);
187                         data[n] = 0;
188                         return -ETIMEDOUT;
189                 }
190                 /*  Start reading data */
191                 data_in = 0;
192                 data_out = devpriv->ulConvertionRate;
193                 udelay(1);
194                 for (i = 0; i < 32; i++) {
195                         /*  Set the clock low */
196                         outb(0, dev->iobase + MPC624_ADC);
197                         udelay(1);
198
199                         if (data_out & (1 << 31)) { /*  the next bit is a 1 */
200                                 /*  Set the ADSDI line (send to MPC624) */
201                                 outb(MPC624_ADSDI, dev->iobase + MPC624_ADC);
202                                 udelay(1);
203                                 /*  Set the clock high */
204                                 outb(MPC624_ADSCK | MPC624_ADSDI,
205                                      dev->iobase + MPC624_ADC);
206                         } else {        /*  the next bit is a 0 */
207
208                                 /*  Set the ADSDI line (send to MPC624) */
209                                 outb(0, dev->iobase + MPC624_ADC);
210                                 udelay(1);
211                                 /*  Set the clock high */
212                                 outb(MPC624_ADSCK, dev->iobase + MPC624_ADC);
213                         }
214                         /*  Read ADSDO on high clock (receive from MPC624) */
215                         udelay(1);
216                         data_in <<= 1;
217                         data_in |=
218                             (inb(dev->iobase + MPC624_ADC) & MPC624_ADSDO) >> 4;
219                         udelay(1);
220
221                         data_out <<= 1;
222                 }
223
224                 /*
225                  *  Received 32-bit long value consist of:
226                  *    31: EOC -
227                  *          (End Of Transmission) bit - should be 0
228                  *    30: DMY
229                  *          (Dummy) bit - should be 0
230                  *    29: SIG
231                  *          (Sign) bit- 1 if the voltage is positive,
232                  *                      0 if negative
233                  *    28: MSB
234                  *          (Most Significant Bit) - the first bit of
235                  *                                   the conversion result
236                  *    ....
237                  *    05: LSB
238                  *          (Least Significant Bit)- the last bit of the
239                  *                                   conversion result
240                  *    04-00: sub-LSB
241                  *          - sub-LSBs are basically noise, but when
242                  *            averaged properly, they can increase conversion
243                  *            precision up to 29 bits; they can be discarded
244                  *            without loss of resolution.
245                  */
246
247                 if (data_in & MPC624_EOC_BIT)
248                         printk(KERN_INFO "MPC624:EOC bit is set (data_in=%lu)!",
249                                data_in);
250                 if (data_in & MPC624_DMY_BIT)
251                         printk(KERN_INFO "MPC624:DMY bit is set (data_in=%lu)!",
252                                data_in);
253                 if (data_in & MPC624_SGN_BIT) { /* Volatge is positive */
254                         /*
255                          * comedi operates on unsigned numbers, so mask off EOC
256                          * and DMY and don't clear the SGN bit
257                          */
258                         data_in &= 0x3FFFFFFF;
259                         data[n] = data_in;
260                 } else { /*  The voltage is negative */
261                         /*
262                          * data_in contains a number in 30-bit two's complement
263                          * code and we must deal with it
264                          */
265                         data_in |= MPC624_SGN_BIT;
266                         data_in = ~data_in;
267                         data_in += 1;
268                         data_in &= ~(MPC624_EOC_BIT | MPC624_DMY_BIT);
269                         /*  clear EOC and DMY bits */
270                         data_in = 0x20000000 - data_in;
271                         data[n] = data_in;
272                 }
273         }
274
275         /*  Return the number of samples read/written */
276         return n;
277 }
278
279 static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
280 {
281         struct mpc624_private *devpriv;
282         struct comedi_subdevice *s;
283         int ret;
284
285         ret = comedi_request_region(dev, it->options[0], MPC624_SIZE);
286         if (ret)
287                 return ret;
288
289         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
290         if (!devpriv)
291                 return -ENOMEM;
292
293         switch (it->options[1]) {
294         case 0:
295                 devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
296                 break;
297         case 1:
298                 devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
299                 break;
300         case 2:
301                 devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
302                 break;
303         case 3:
304                 devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
305                 break;
306         case 4:
307                 devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
308                 break;
309         case 5:
310                 devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
311                 break;
312         case 6:
313                 devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
314                 break;
315         case 7:
316                 devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
317                 break;
318         case 8:
319                 devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
320                 break;
321         case 9:
322                 devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
323                 break;
324         default:
325                 devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
326         }
327
328         ret = comedi_alloc_subdevices(dev, 1);
329         if (ret)
330                 return ret;
331
332         s = &dev->subdevices[0];
333         s->type = COMEDI_SUBD_AI;
334         s->subdev_flags = SDF_READABLE | SDF_DIFF;
335         s->n_chan = 8;
336         switch (it->options[1]) {
337         default:
338                 s->maxdata = 0x3FFFFFFF;
339         }
340
341         switch (it->options[1]) {
342         case 0:
343                 s->range_table = &range_mpc624_bipolar1;
344                 break;
345         default:
346                 s->range_table = &range_mpc624_bipolar10;
347         }
348         s->len_chanlist = 1;
349         s->insn_read = mpc624_ai_rinsn;
350
351         return 1;
352 }
353
354 static struct comedi_driver mpc624_driver = {
355         .driver_name    = "mpc624",
356         .module         = THIS_MODULE,
357         .attach         = mpc624_attach,
358         .detach         = comedi_legacy_detach,
359 };
360 module_comedi_driver(mpc624_driver);
361
362 MODULE_AUTHOR("Comedi http://www.comedi.org");
363 MODULE_DESCRIPTION("Comedi low-level driver");
364 MODULE_LICENSE("GPL");