b7192875b0098e886ab75b8b5aa90bd8b914996e
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci2016.c
1 /**
2 @verbatim
3
4 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6         ADDI-DATA GmbH
7         Dieselstrasse 3
8         D-77833 Ottersweier
9         Tel: +19(0)7223/9493-0
10         Fax: +49(0)7223/9493-92
11         http://www.addi-data.com
12         info@addi-data.com
13
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 You should also find the complete GPL in the COPYING file accompanying this source code.
21
22 @endverbatim
23 */
24 /*
25
26   +-----------------------------------------------------------------------+
27   | (C) ADDI-DATA GmbH          Dieselstraße 3       D-77833 Ottersweier  |
28   +-----------------------------------------------------------------------+
29   | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
30   | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
31   +-------------------------------+---------------------------------------+
32   | Project     : APCI-2016       | Compiler   : GCC                      |
33   | Module name : hwdrv_apci2016.c| Version    : 2.96                     |
34   +-------------------------------+---------------------------------------+
35   | Project manager: Eric Stolz   | Date       :  02/12/2002              |
36   +-------------------------------+---------------------------------------+
37   | Description :   Hardware Layer Access For APCI-2016                   |
38   +-----------------------------------------------------------------------+
39   |                             UPDATES                                   |
40   +----------+-----------+------------------------------------------------+
41   |   Date   |   Author  |          Description of updates                |
42   +----------+-----------+------------------------------------------------+
43   |          |           |                                                |
44   |          |           |                                                |
45   |          |           |                                                |
46   +----------+-----------+------------------------------------------------+
47 */
48
49 /*********      Definitions for APCI-2016 card  *****/
50
51 #define APCI2016_ADDRESS_RANGE          8
52
53 /* DIGITAL INPUT-OUTPUT DEFINE */
54
55 #define APCI2016_DIGITAL_OP             0x04
56 #define APCI2016_DIGITAL_OP_RW          4
57
58 /* TIMER COUNTER WATCHDOG DEFINES */
59
60 #define ADDIDATA_WATCHDOG               2
61 #define APCI2016_DIGITAL_OP_WATCHDOG    0
62 #define APCI2016_WATCHDOG_ENABLEDISABLE 12
63 #define APCI2016_WATCHDOG_RELOAD_VALUE  4
64 #define APCI2016_WATCHDOG_STATUS        16
65
66 /*
67 +----------------------------------------------------------------------------+
68 | Function   Name   : int i_APCI2016_ConfigDigitalOutput                     |
69 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
70 |                      struct comedi_insn *insn,unsigned int *data)                     |
71 +----------------------------------------------------------------------------+
72 | Task              : Configures The Digital Output Subdevice.               |
73 +----------------------------------------------------------------------------+
74 | Input Parameters  : struct comedi_device *dev : Driver handle                     |
75 |                     unsigned int *data         : Data Pointer contains             |
76 |                                          configuration parameters as below |
77 |                                                                            |
78 |                         data[0]            : 1 Digital Memory On               |
79 |                                                          0 Digital Memory Off              |
80 +----------------------------------------------------------------------------+
81 | Output Parameters :   --                                                                                                       |
82 +----------------------------------------------------------------------------+
83 | Return Value      : TRUE  : No error occur                                 |
84 |                           : FALSE : Error occur. Return the error          |
85 |                                                                                |
86 +----------------------------------------------------------------------------+
87 */
88 static int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev,
89                                           struct comedi_subdevice *s,
90                                           struct comedi_insn *insn,
91                                           unsigned int *data)
92 {
93         struct addi_private *devpriv = dev->private;
94
95         if ((data[0] != 0) && (data[0] != 1)) {
96                 comedi_error(dev,
97                         "Not a valid Data !!! ,Data should be 1 or 0\n");
98                 return -EINVAL;
99         }                       /*  if  ((data[0]!=0) && (data[0]!=1)) */
100         if (data[0]) {
101                 devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
102         }                       /*  if  (data[0] */
103         else {
104                 devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
105         }                       /*  else if  (data[0] */
106         return insn->n;
107 }
108
109 /*
110 +----------------------------------------------------------------------------+
111 | Function   Name   : int i_APCI2016_WriteDigitalOutput                      |
112 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
113 |                      struct comedi_insn *insn,unsigned int *data)                     |
114 +----------------------------------------------------------------------------+
115 | Task              : Writes port value  To the selected port                |
116 +----------------------------------------------------------------------------+
117 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
118 |                     unsigned int ui_NoOfChannels    : No Of Channels To Write      |
119 |                     unsigned int *data              : Data Pointer to read status  |
120 +----------------------------------------------------------------------------+
121 | Output Parameters :   --                                                                                                       |
122 +----------------------------------------------------------------------------+
123 | Return Value      : TRUE  : No error occur                                 |
124 |                           : FALSE : Error occur. Return the error          |
125 |                                                                                |
126 +----------------------------------------------------------------------------+
127 */
128 static int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev,
129                                          struct comedi_subdevice *s,
130                                          struct comedi_insn *insn,
131                                          unsigned int *data)
132 {
133         struct addi_private *devpriv = dev->private;
134         unsigned int ui_NoOfChannel;
135         unsigned int ui_Temp, ui_Temp1;
136
137         ui_NoOfChannel = CR_CHAN(insn->chanspec);
138         if (ui_NoOfChannel > 15) {
139                 comedi_error(dev,
140                         "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
141                 return -EINVAL;
142         }                       /*  if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */
143         if (devpriv->b_OutputMemoryStatus) {
144                 ui_Temp = inw(devpriv->iobase + APCI2016_DIGITAL_OP);
145         }                       /*  if  (devpriv->b_OutputMemoryStatus ) */
146         else {
147                 ui_Temp = 0;
148         }                       /*  else if  (devpriv->b_OutputMemoryStatus ) */
149         if ((data[1] != 0) && (data[1] != 1)) {
150                 comedi_error(dev,
151                         "Invalid Data[1] value !!!, Data[1] should be 0 or 1\n");
152                 return -EINVAL;
153         }                       /*  if  ((data[1]!=0) && (data[1]!=1)) */
154
155         if (data[3] == 0) {
156                 if (data[1] == 0) {
157                         data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
158                         outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP);
159                 }               /*  if (data[1]==0) */
160                 else {
161                         if (data[1] == 1) {
162                                 switch (ui_NoOfChannel) {
163                                 case 2:
164                                         data[0] =
165                                                 (data[0] << (2 *
166                                                         data[2])) | ui_Temp;
167                                         break;
168                                 case 4:
169                                         data[0] =
170                                                 (data[0] << (4 *
171                                                         data[2])) | ui_Temp;
172                                         break;
173                                 case 8:
174                                         data[0] =
175                                                 (data[0] << (8 *
176                                                         data[2])) | ui_Temp;
177                                         break;
178                                 case 15:
179                                         data[0] = data[0] | ui_Temp;
180                                         break;
181                                 default:
182                                         comedi_error(dev, " chan spec wrong");
183                                         return -EINVAL; /*  "sorry channel spec wrong " */
184                                 }       /* switch(ui_NoOfChannels) */
185                                 outw(data[0],
186                                         devpriv->iobase + APCI2016_DIGITAL_OP);
187                         }       /*  if  (data[1]==1) */
188                         else {
189                                 printk("\nSpecified channel not supported\n");
190                         }       /*  else if  (data[1]==1) */
191                 }               /*  else if (data[1]==0) */
192         }                       /*  if (data[3]==0) */
193         else {
194                 if (data[3] == 1) {
195                         if (data[1] == 0) {
196                                 data[0] = ~data[0] & 0x1;
197                                 ui_Temp1 = 1;
198                                 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
199                                 ui_Temp = ui_Temp | ui_Temp1;
200                                 data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff;
201                                 data[0] = data[0] & ui_Temp;
202                                 outw(data[0],
203                                         devpriv->iobase + APCI2016_DIGITAL_OP);
204                         }       /*  if  (data[1]==0) */
205                         else {
206                                 if (data[1] == 1) {
207                                         switch (ui_NoOfChannel) {
208                                         case 2:
209                                                 data[0] = ~data[0] & 0x3;
210                                                 ui_Temp1 = 3;
211                                                 ui_Temp1 =
212                                                         ui_Temp1 << 2 * data[2];
213                                                 ui_Temp = ui_Temp | ui_Temp1;
214                                                 data[0] =
215                                                         ((data[0] << (2 *
216                                                                         data
217                                                                         [2])) ^
218                                                         0xffff) & ui_Temp;
219                                                 break;
220                                         case 4:
221                                                 data[0] = ~data[0] & 0xf;
222                                                 ui_Temp1 = 15;
223                                                 ui_Temp1 =
224                                                         ui_Temp1 << 4 * data[2];
225                                                 ui_Temp = ui_Temp | ui_Temp1;
226                                                 data[0] =
227                                                         ((data[0] << (4 *
228                                                                         data
229                                                                         [2])) ^
230                                                         0xffff) & ui_Temp;
231                                                 break;
232                                         case 8:
233                                                 data[0] = ~data[0] & 0xff;
234                                                 ui_Temp1 = 255;
235                                                 ui_Temp1 =
236                                                         ui_Temp1 << 8 * data[2];
237                                                 ui_Temp = ui_Temp | ui_Temp1;
238                                                 data[0] =
239                                                         ((data[0] << (8 *
240                                                                         data
241                                                                         [2])) ^
242                                                         0xffff) & ui_Temp;
243                                                 break;
244                                         case 15:
245                                                 break;
246                                         default:
247                                                 comedi_error(dev,
248                                                         " chan spec wrong");
249                                                 return -EINVAL; /*  "sorry channel spec wrong " */
250                                         }       /* switch(ui_NoOfChannels) */
251                                         outw(data[0],
252                                                 devpriv->iobase +
253                                                 APCI2016_DIGITAL_OP);
254                                 }       /*  if(data[1]==1) */
255                                 else {
256                                         printk("\nSpecified channel not supported\n");
257                                 }       /* else if(data[1]==1) */
258                         }       /* elseif(data[1]==0) */
259                 }               /* if(data[3]==1); */
260                 else {
261                         printk("\nSpecified functionality does not exist\n");
262                         return -EINVAL;
263                 }               /* if else data[3]==1) */
264         }                       /* if else data[3]==0) */
265         return insn->n;
266 }
267
268 /*
269 +----------------------------------------------------------------------------+
270 | Function   Name   : int i_APCI2016_BitsDigitalOutput                       |
271 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
272 |                      struct comedi_insn *insn,unsigned int *data)                     |
273 +----------------------------------------------------------------------------+
274 | Task              : Read  value  of the selected channel or port           |
275 +----------------------------------------------------------------------------+
276 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
277 |                     unsigned int ui_NoOfChannels    : No Of Channels To read       |
278 |                     unsigned int *data              : Data Pointer to read status  |
279 +----------------------------------------------------------------------------+
280 | Output Parameters :   --                                                                                                       |
281 +----------------------------------------------------------------------------+
282 | Return Value      : TRUE  : No error occur                                 |
283 |                           : FALSE : Error occur. Return the error          |
284 |                                                                                |
285 +----------------------------------------------------------------------------+
286 */
287 static int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev,
288                                         struct comedi_subdevice *s,
289                                         struct comedi_insn *insn,
290                                         unsigned int *data)
291 {
292         struct addi_private *devpriv = dev->private;
293         unsigned int ui_Temp;
294         unsigned int ui_NoOfChannel;
295
296         ui_NoOfChannel = CR_CHAN(insn->chanspec);
297         if (ui_NoOfChannel > 15) {
298                 comedi_error(dev,
299                         "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
300                 return -EINVAL;
301         }                       /*  if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */
302         if ((data[0] != 0) && (data[0] != 1)) {
303                 comedi_error(dev,
304                         "Invalid Data[0] value !!!, Data[0] should be 0 or 1\n");
305                 return -EINVAL;
306         }                       /*  if  ((data[0]!=0) && (data[0]!=1)) */
307         ui_Temp = data[0];
308         *data = inw(devpriv->iobase + APCI2016_DIGITAL_OP_RW);
309         if (ui_Temp == 0) {
310                 *data = (*data >> ui_NoOfChannel) & 0x1;
311         }                       /*  if  (ui_Temp==0) */
312         else {
313                 if (ui_Temp == 1) {
314                         switch (ui_NoOfChannel) {
315                         case 2:
316                                 *data = (*data >> (2 * data[1])) & 3;
317                                 break;
318
319                         case 4:
320                                 *data = (*data >> (4 * data[1])) & 15;
321                                 break;
322
323                         case 8:
324                                 *data = (*data >> (8 * data[1])) & 255;
325                                 break;
326
327                         case 15:
328                                 break;
329
330                         default:
331                                 comedi_error(dev, " chan spec wrong");
332                                 return -EINVAL; /*  "sorry channel spec wrong " */
333                         }       /* switch(ui_NoOfChannel) */
334                 }               /*  if  (ui_Temp==1) */
335                 else {
336                         printk("\nSpecified channel not supported \n");
337                 }               /*  else if  (ui_Temp==1) */
338         }                       /*  if  (ui_Temp==0) */
339         return insn->n;
340 }
341
342 /*
343 +----------------------------------------------------------------------------+
344 | Function   Name   : int i_APCI2016_ConfigWatchdog                          |
345 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
346 |                      struct comedi_insn *insn,unsigned int *data)                     |
347 +----------------------------------------------------------------------------+
348 | Task              : Configures The Watchdog                                |
349 +----------------------------------------------------------------------------+
350 | Input Parameters  :   struct comedi_device *dev      : Driver handle              |
351 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
352 |                     struct comedi_insn *insn      :pointer to insn structure      |
353 |                     unsigned int *data          : Data Pointer to read status  |
354 +----------------------------------------------------------------------------+
355 | Output Parameters :   --                                                                                                       |
356 +----------------------------------------------------------------------------+
357 | Return Value      : TRUE  : No error occur                                 |
358 |                           : FALSE : Error occur. Return the error          |
359 |                                                                                |
360 +----------------------------------------------------------------------------+
361 */
362 static int i_APCI2016_ConfigWatchdog(struct comedi_device *dev,
363                                      struct comedi_subdevice *s,
364                                      struct comedi_insn *insn,
365                                      unsigned int *data)
366 {
367         struct addi_private *devpriv = dev->private;
368
369         if (data[0] == 0) {
370                 /* Disable the watchdog */
371                 outw(0x0,
372                         devpriv->i_IobaseAddon +
373                         APCI2016_WATCHDOG_ENABLEDISABLE);
374                 /* Loading the Reload value */
375                 outw(data[1],
376                         devpriv->i_IobaseAddon +
377                         APCI2016_WATCHDOG_RELOAD_VALUE);
378                 data[1] = data[1] >> 16;
379                 outw(data[1],
380                         devpriv->i_IobaseAddon +
381                         APCI2016_WATCHDOG_RELOAD_VALUE + 2);
382         } else {
383                 printk("\nThe input parameters are wrong\n");
384         }
385         return insn->n;
386 }
387
388 /*
389 +----------------------------------------------------------------------------+
390 | Function   Name   : int i_APCI2016_StartStopWriteWatchdog                  |
391 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
392 |                      struct comedi_insn *insn,unsigned int *data)                     |
393 +----------------------------------------------------------------------------+
394 | Task              : Start / Stop The Watchdog                              |
395 +----------------------------------------------------------------------------+
396 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
397 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
398 |                     struct comedi_insn *insn      :pointer to insn structure      |
399 |                     unsigned int *data          : Data Pointer to read status  |
400 +----------------------------------------------------------------------------+
401 | Output Parameters :   --                                                                                                       |
402 +----------------------------------------------------------------------------+
403 | Return Value      : TRUE  : No error occur                                 |
404 |                           : FALSE : Error occur. Return the error          |
405 |                                                                                |
406 +----------------------------------------------------------------------------+
407 */
408 static int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev,
409                                              struct comedi_subdevice *s,
410                                              struct comedi_insn *insn,
411                                              unsigned int *data)
412 {
413         struct addi_private *devpriv = dev->private;
414
415         switch (data[0]) {
416         case 0:         /* stop the watchdog */
417                 outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);    /* disable the watchdog */
418                 break;
419         case 1:         /* start the watchdog */
420                 outw(0x0001,
421                         devpriv->i_IobaseAddon +
422                         APCI2016_WATCHDOG_ENABLEDISABLE);
423                 break;
424         case 2:         /* Software trigger */
425                 outw(0x0201,
426                         devpriv->i_IobaseAddon +
427                         APCI2016_WATCHDOG_ENABLEDISABLE);
428                 break;
429         default:
430                 printk("\nSpecified functionality does not exist\n");
431                 return -EINVAL;
432         }                       /*  switch(data[0]) */
433
434         return insn->n;
435 }
436
437 /*
438 +----------------------------------------------------------------------------+
439 | Function   Name   : int i_APCI2016_ReadWatchdog                            |
440 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
441 |                      struct comedi_insn *insn,unsigned int *data)                     |
442 +----------------------------------------------------------------------------+
443 | Task              : Read The Watchdog                                      |
444 +----------------------------------------------------------------------------+
445 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
446 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
447 |                     struct comedi_insn *insn      :pointer to insn structure      |
448 |                     unsigned int *data          : Data Pointer to read status  |
449 +----------------------------------------------------------------------------+
450 | Output Parameters :   --                                                                                                       |
451 +----------------------------------------------------------------------------+
452 | Return Value      : TRUE  : No error occur                                 |
453 |                           : FALSE : Error occur. Return the error          |
454 |                                                                                |
455 +----------------------------------------------------------------------------+
456 */
457
458 static int i_APCI2016_ReadWatchdog(struct comedi_device *dev,
459                                    struct comedi_subdevice *s,
460                                    struct comedi_insn *insn,
461                                    unsigned int *data)
462 {
463         struct addi_private *devpriv = dev->private;
464
465         udelay(5);
466         data[0] = inw(devpriv->i_IobaseAddon + APCI2016_WATCHDOG_STATUS) & 0x1;
467         return insn->n;
468 }
469
470 /*
471 +----------------------------------------------------------------------------+
472 | Function   Name   : int i_APCI2016_Reset(struct comedi_device *dev)               |                                                       |
473 +----------------------------------------------------------------------------+
474 | Task              :resets all the registers                                |
475 +----------------------------------------------------------------------------+
476 | Input Parameters  : struct comedi_device *dev
477 +----------------------------------------------------------------------------+
478 | Output Parameters :   --                                                                                                       |
479 +----------------------------------------------------------------------------+
480 | Return Value      :                                                        |
481 |                                                                                |
482 +----------------------------------------------------------------------------+
483 */
484
485 static int i_APCI2016_Reset(struct comedi_device *dev)
486 {
487         struct addi_private *devpriv = dev->private;
488
489         outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP);       /*  Resets the digital output channels */
490         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);
491         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE);
492         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE + 2);
493         return 0;
494 }