SERIAL: omap: fix hardware assisted flow control
[firefly-linux-kernel-4.4.55.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 skel_private {
126
127         /*  set by mpc624_attach() from driver's parameters */
128         unsigned long int ulConvertionRate;
129 };
130
131 #define devpriv ((struct skel_private *)dev->private)
132 /* -------------------------------------------------------------------------- */
133 static const struct comedi_lrange range_mpc624_bipolar1 = {
134         1,
135         {
136 /* BIP_RANGE(1.01)  this is correct, */
137          /*  but my MPC-624 actually seems to have a range of 2.02 */
138          BIP_RANGE(2.02)
139          }
140 };
141
142 static const struct comedi_lrange range_mpc624_bipolar10 = {
143         1,
144         {
145 /* BIP_RANGE(10.1)   this is correct, */
146          /*  but my MPC-624 actually seems to have a range of 20.2 */
147          BIP_RANGE(20.2)
148          }
149 };
150
151 /* Timeout 200ms */
152 #define TIMEOUT 200
153
154 static int mpc624_ai_rinsn(struct comedi_device *dev,
155                            struct comedi_subdevice *s, struct comedi_insn *insn,
156                            unsigned int *data)
157 {
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 comedi_subdevice *s;
287         unsigned long iobase;
288         int ret;
289
290         iobase = it->options[0];
291         printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
292         if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
293                 printk(KERN_ERR "I/O port(s) in use\n");
294                 return -EIO;
295         }
296
297         dev->iobase = iobase;
298         dev->board_name = "mpc624";
299
300         /*  Private structure initialization */
301         if (alloc_private(dev, sizeof(struct skel_private)) < 0)
302                 return -ENOMEM;
303
304         switch (it->options[1]) {
305         case 0:
306                 devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
307                 printk(KERN_INFO "3.52 kHz, ");
308                 break;
309         case 1:
310                 devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
311                 printk(KERN_INFO "1.76 kHz, ");
312                 break;
313         case 2:
314                 devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
315                 printk(KERN_INFO "880 Hz, ");
316                 break;
317         case 3:
318                 devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
319                 printk(KERN_INFO "440 Hz, ");
320                 break;
321         case 4:
322                 devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
323                 printk(KERN_INFO "220 Hz, ");
324                 break;
325         case 5:
326                 devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
327                 printk(KERN_INFO "110 Hz, ");
328                 break;
329         case 6:
330                 devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
331                 printk(KERN_INFO "55 Hz, ");
332                 break;
333         case 7:
334                 devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
335                 printk(KERN_INFO "27.5 Hz, ");
336                 break;
337         case 8:
338                 devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
339                 printk(KERN_INFO "13.75 Hz, ");
340                 break;
341         case 9:
342                 devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
343                 printk(KERN_INFO "6.875 Hz, ");
344                 break;
345         default:
346                 printk
347                     (KERN_ERR "illegal conversion rate setting!"
348                         " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
349                 devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
350         }
351
352         ret = comedi_alloc_subdevices(dev, 1);
353         if (ret)
354                 return ret;
355
356         s = &dev->subdevices[0];
357         s->type = COMEDI_SUBD_AI;
358         s->subdev_flags = SDF_READABLE | SDF_DIFF;
359         s->n_chan = 8;
360         switch (it->options[1]) {
361         default:
362                 s->maxdata = 0x3FFFFFFF;
363                 printk(KERN_INFO "30 bit, ");
364         }
365
366         switch (it->options[1]) {
367         case 0:
368                 s->range_table = &range_mpc624_bipolar1;
369                 printk(KERN_INFO "1.01V]: ");
370                 break;
371         default:
372                 s->range_table = &range_mpc624_bipolar10;
373                 printk(KERN_INFO "10.1V]: ");
374         }
375         s->len_chanlist = 1;
376         s->insn_read = mpc624_ai_rinsn;
377
378         printk(KERN_INFO "attached\n");
379
380         return 1;
381 }
382
383 static void mpc624_detach(struct comedi_device *dev)
384 {
385         if (dev->iobase)
386                 release_region(dev->iobase, MPC624_SIZE);
387 }
388
389 static struct comedi_driver mpc624_driver = {
390         .driver_name    = "mpc624",
391         .module         = THIS_MODULE,
392         .attach         = mpc624_attach,
393         .detach         = mpc624_detach
394 };
395 module_comedi_driver(mpc624_driver);
396
397 MODULE_AUTHOR("Comedi http://www.comedi.org");
398 MODULE_DESCRIPTION("Comedi low-level driver");
399 MODULE_LICENSE("GPL");