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