Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelv...
[pandora-kernel.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 /*
50 +----------------------------------------------------------------------------+
51 |                               Included files                               |
52 +----------------------------------------------------------------------------+
53 */
54 #include "hwdrv_apci2016.h"
55
56 /*
57 +----------------------------------------------------------------------------+
58 | Function   Name   : int i_APCI2016_ConfigDigitalOutput                     |
59 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
60 |                      struct comedi_insn *insn,unsigned int *data)                     |
61 +----------------------------------------------------------------------------+
62 | Task              : Configures The Digital Output Subdevice.               |
63 +----------------------------------------------------------------------------+
64 | Input Parameters  : struct comedi_device *dev : Driver handle                     |
65 |                     unsigned int *data         : Data Pointer contains             |
66 |                                          configuration parameters as below |
67 |                                                                            |
68 |                         data[0]            : 1 Digital Memory On               |
69 |                                                          0 Digital Memory Off              |
70 +----------------------------------------------------------------------------+
71 | Output Parameters :   --                                                                                                       |
72 +----------------------------------------------------------------------------+
73 | Return Value      : TRUE  : No error occur                                 |
74 |                           : FALSE : Error occur. Return the error          |
75 |                                                                                |
76 +----------------------------------------------------------------------------+
77 */
78 int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
79         struct comedi_insn *insn, unsigned int *data)
80 {
81         if ((data[0] != 0) && (data[0] != 1)) {
82                 comedi_error(dev,
83                         "Not a valid Data !!! ,Data should be 1 or 0\n");
84                 return -EINVAL;
85         }                       /*  if  ((data[0]!=0) && (data[0]!=1)) */
86         if (data[0]) {
87                 devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE;
88         }                       /*  if  (data[0] */
89         else {
90                 devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE;
91         }                       /*  else if  (data[0] */
92         return insn->n;
93 }
94
95 /*
96 +----------------------------------------------------------------------------+
97 | Function   Name   : int i_APCI2016_WriteDigitalOutput                      |
98 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
99 |                      struct comedi_insn *insn,unsigned int *data)                     |
100 +----------------------------------------------------------------------------+
101 | Task              : Writes port value  To the selected port                |
102 +----------------------------------------------------------------------------+
103 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
104 |                     unsigned int ui_NoOfChannels    : No Of Channels To Write      |
105 |                     unsigned int *data              : Data Pointer to read status  |
106 +----------------------------------------------------------------------------+
107 | Output Parameters :   --                                                                                                       |
108 +----------------------------------------------------------------------------+
109 | Return Value      : TRUE  : No error occur                                 |
110 |                           : FALSE : Error occur. Return the error          |
111 |                                                                                |
112 +----------------------------------------------------------------------------+
113 */
114 int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
115         struct comedi_insn *insn, unsigned int *data)
116 {
117         unsigned int ui_NoOfChannel;
118         unsigned int ui_Temp, ui_Temp1;
119         ui_NoOfChannel = CR_CHAN(insn->chanspec);
120         if (ui_NoOfChannel > 15) {
121                 comedi_error(dev,
122                         "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
123                 return -EINVAL;
124         }                       /*  if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */
125         if (devpriv->b_OutputMemoryStatus) {
126                 ui_Temp = inw(devpriv->iobase + APCI2016_DIGITAL_OP);
127         }                       /*  if  (devpriv->b_OutputMemoryStatus ) */
128         else {
129                 ui_Temp = 0;
130         }                       /*  else if  (devpriv->b_OutputMemoryStatus ) */
131         if ((data[1] != 0) && (data[1] != 1)) {
132                 comedi_error(dev,
133                         "Invalid Data[1] value !!!, Data[1] should be 0 or 1\n");
134                 return -EINVAL;
135         }                       /*  if  ((data[1]!=0) && (data[1]!=1)) */
136
137         if (data[3] == 0) {
138                 if (data[1] == 0) {
139                         data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
140                         outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP);
141                 }               /*  if (data[1]==0) */
142                 else {
143                         if (data[1] == 1) {
144                                 switch (ui_NoOfChannel) {
145                                 case 2:
146                                         data[0] =
147                                                 (data[0] << (2 *
148                                                         data[2])) | ui_Temp;
149                                         break;
150                                 case 4:
151                                         data[0] =
152                                                 (data[0] << (4 *
153                                                         data[2])) | ui_Temp;
154                                         break;
155                                 case 8:
156                                         data[0] =
157                                                 (data[0] << (8 *
158                                                         data[2])) | ui_Temp;
159                                         break;
160                                 case 15:
161                                         data[0] = data[0] | ui_Temp;
162                                         break;
163                                 default:
164                                         comedi_error(dev, " chan spec wrong");
165                                         return -EINVAL; /*  "sorry channel spec wrong " */
166                                 }       /* switch(ui_NoOfChannels) */
167                                 outw(data[0],
168                                         devpriv->iobase + APCI2016_DIGITAL_OP);
169                         }       /*  if  (data[1]==1) */
170                         else {
171                                 printk("\nSpecified channel not supported\n");
172                         }       /*  else if  (data[1]==1) */
173                 }               /*  else if (data[1]==0) */
174         }                       /*  if (data[3]==0) */
175         else {
176                 if (data[3] == 1) {
177                         if (data[1] == 0) {
178                                 data[0] = ~data[0] & 0x1;
179                                 ui_Temp1 = 1;
180                                 ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
181                                 ui_Temp = ui_Temp | ui_Temp1;
182                                 data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff;
183                                 data[0] = data[0] & ui_Temp;
184                                 outw(data[0],
185                                         devpriv->iobase + APCI2016_DIGITAL_OP);
186                         }       /*  if  (data[1]==0) */
187                         else {
188                                 if (data[1] == 1) {
189                                         switch (ui_NoOfChannel) {
190                                         case 2:
191                                                 data[0] = ~data[0] & 0x3;
192                                                 ui_Temp1 = 3;
193                                                 ui_Temp1 =
194                                                         ui_Temp1 << 2 * data[2];
195                                                 ui_Temp = ui_Temp | ui_Temp1;
196                                                 data[0] =
197                                                         ((data[0] << (2 *
198                                                                         data
199                                                                         [2])) ^
200                                                         0xffff) & ui_Temp;
201                                                 break;
202                                         case 4:
203                                                 data[0] = ~data[0] & 0xf;
204                                                 ui_Temp1 = 15;
205                                                 ui_Temp1 =
206                                                         ui_Temp1 << 4 * data[2];
207                                                 ui_Temp = ui_Temp | ui_Temp1;
208                                                 data[0] =
209                                                         ((data[0] << (4 *
210                                                                         data
211                                                                         [2])) ^
212                                                         0xffff) & ui_Temp;
213                                                 break;
214                                         case 8:
215                                                 data[0] = ~data[0] & 0xff;
216                                                 ui_Temp1 = 255;
217                                                 ui_Temp1 =
218                                                         ui_Temp1 << 8 * data[2];
219                                                 ui_Temp = ui_Temp | ui_Temp1;
220                                                 data[0] =
221                                                         ((data[0] << (8 *
222                                                                         data
223                                                                         [2])) ^
224                                                         0xffff) & ui_Temp;
225                                                 break;
226                                         case 15:
227                                                 break;
228                                         default:
229                                                 comedi_error(dev,
230                                                         " chan spec wrong");
231                                                 return -EINVAL; /*  "sorry channel spec wrong " */
232                                         }       /* switch(ui_NoOfChannels) */
233                                         outw(data[0],
234                                                 devpriv->iobase +
235                                                 APCI2016_DIGITAL_OP);
236                                 }       /*  if(data[1]==1) */
237                                 else {
238                                         printk("\nSpecified channel not supported\n");
239                                 }       /* else if(data[1]==1) */
240                         }       /* elseif(data[1]==0) */
241                 }               /* if(data[3]==1); */
242                 else {
243                         printk("\nSpecified functionality does not exist\n");
244                         return -EINVAL;
245                 }               /* if else data[3]==1) */
246         }                       /* if else data[3]==0) */
247         return insn->n;
248 }
249
250 /*
251 +----------------------------------------------------------------------------+
252 | Function   Name   : int i_APCI2016_BitsDigitalOutput                       |
253 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
254 |                      struct comedi_insn *insn,unsigned int *data)                     |
255 +----------------------------------------------------------------------------+
256 | Task              : Read  value  of the selected channel or port           |
257 +----------------------------------------------------------------------------+
258 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
259 |                     unsigned int ui_NoOfChannels    : No Of Channels To read       |
260 |                     unsigned int *data              : Data Pointer to read status  |
261 +----------------------------------------------------------------------------+
262 | Output Parameters :   --                                                                                                       |
263 +----------------------------------------------------------------------------+
264 | Return Value      : TRUE  : No error occur                                 |
265 |                           : FALSE : Error occur. Return the error          |
266 |                                                                                |
267 +----------------------------------------------------------------------------+
268 */
269 int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s,
270         struct comedi_insn *insn, unsigned int *data)
271 {
272         unsigned int ui_Temp;
273         unsigned int ui_NoOfChannel;
274         ui_NoOfChannel = CR_CHAN(insn->chanspec);
275         if (ui_NoOfChannel > 15) {
276                 comedi_error(dev,
277                         "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n");
278                 return -EINVAL;
279         }                       /*  if  ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */
280         if ((data[0] != 0) && (data[0] != 1)) {
281                 comedi_error(dev,
282                         "Invalid Data[0] value !!!, Data[0] should be 0 or 1\n");
283                 return -EINVAL;
284         }                       /*  if  ((data[0]!=0) && (data[0]!=1)) */
285         ui_Temp = data[0];
286         *data = inw(devpriv->iobase + APCI2016_DIGITAL_OP_RW);
287         if (ui_Temp == 0) {
288                 *data = (*data >> ui_NoOfChannel) & 0x1;
289         }                       /*  if  (ui_Temp==0) */
290         else {
291                 if (ui_Temp == 1) {
292                         switch (ui_NoOfChannel) {
293                         case 2:
294                                 *data = (*data >> (2 * data[1])) & 3;
295                                 break;
296
297                         case 4:
298                                 *data = (*data >> (4 * data[1])) & 15;
299                                 break;
300
301                         case 8:
302                                 *data = (*data >> (8 * data[1])) & 255;
303                                 break;
304
305                         case 15:
306                                 break;
307
308                         default:
309                                 comedi_error(dev, " chan spec wrong");
310                                 return -EINVAL; /*  "sorry channel spec wrong " */
311                         }       /* switch(ui_NoOfChannel) */
312                 }               /*  if  (ui_Temp==1) */
313                 else {
314                         printk("\nSpecified channel not supported \n");
315                 }               /*  else if  (ui_Temp==1) */
316         }                       /*  if  (ui_Temp==0) */
317         return insn->n;
318 }
319
320 /*
321 +----------------------------------------------------------------------------+
322 | Function   Name   : int i_APCI2016_ConfigWatchdog                          |
323 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
324 |                      struct comedi_insn *insn,unsigned int *data)                     |
325 +----------------------------------------------------------------------------+
326 | Task              : Configures The Watchdog                                |
327 +----------------------------------------------------------------------------+
328 | Input Parameters  :   struct comedi_device *dev      : Driver handle              |
329 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
330 |                     struct comedi_insn *insn      :pointer to insn structure      |
331 |                     unsigned int *data          : Data Pointer to read status  |
332 +----------------------------------------------------------------------------+
333 | Output Parameters :   --                                                                                                       |
334 +----------------------------------------------------------------------------+
335 | Return Value      : TRUE  : No error occur                                 |
336 |                           : FALSE : Error occur. Return the error          |
337 |                                                                                |
338 +----------------------------------------------------------------------------+
339 */
340 int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
341         struct comedi_insn *insn, unsigned int *data)
342 {
343
344         if (data[0] == 0) {
345                 /* Disable the watchdog */
346                 outw(0x0,
347                         devpriv->i_IobaseAddon +
348                         APCI2016_WATCHDOG_ENABLEDISABLE);
349                 /* Loading the Reload value */
350                 outw(data[1],
351                         devpriv->i_IobaseAddon +
352                         APCI2016_WATCHDOG_RELOAD_VALUE);
353                 data[1] = data[1] >> 16;
354                 outw(data[1],
355                         devpriv->i_IobaseAddon +
356                         APCI2016_WATCHDOG_RELOAD_VALUE + 2);
357         } else {
358                 printk("\nThe input parameters are wrong\n");
359         }
360         return insn->n;
361 }
362
363 /*
364 +----------------------------------------------------------------------------+
365 | Function   Name   : int i_APCI2016_StartStopWriteWatchdog                  |
366 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
367 |                      struct comedi_insn *insn,unsigned int *data)                     |
368 +----------------------------------------------------------------------------+
369 | Task              : Start / Stop The Watchdog                              |
370 +----------------------------------------------------------------------------+
371 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
372 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
373 |                     struct comedi_insn *insn      :pointer to insn structure      |
374 |                     unsigned int *data          : Data Pointer to read status  |
375 +----------------------------------------------------------------------------+
376 | Output Parameters :   --                                                                                                       |
377 +----------------------------------------------------------------------------+
378 | Return Value      : TRUE  : No error occur                                 |
379 |                           : FALSE : Error occur. Return the error          |
380 |                                                                                |
381 +----------------------------------------------------------------------------+
382 */
383 int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
384         struct comedi_insn *insn, unsigned int *data)
385 {
386
387         switch (data[0]) {
388         case 0:         /* stop the watchdog */
389                 outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);    /* disable the watchdog */
390                 break;
391         case 1:         /* start the watchdog */
392                 outw(0x0001,
393                         devpriv->i_IobaseAddon +
394                         APCI2016_WATCHDOG_ENABLEDISABLE);
395                 break;
396         case 2:         /* Software trigger */
397                 outw(0x0201,
398                         devpriv->i_IobaseAddon +
399                         APCI2016_WATCHDOG_ENABLEDISABLE);
400                 break;
401         default:
402                 printk("\nSpecified functionality does not exist\n");
403                 return -EINVAL;
404         }                       /*  switch(data[0]) */
405
406         return insn->n;
407 }
408
409 /*
410 +----------------------------------------------------------------------------+
411 | Function   Name   : int i_APCI2016_ReadWatchdog                            |
412 |                         (struct comedi_device *dev,struct comedi_subdevice *s,               |
413 |                      struct comedi_insn *insn,unsigned int *data)                     |
414 +----------------------------------------------------------------------------+
415 | Task              : Read The Watchdog                                      |
416 +----------------------------------------------------------------------------+
417 | Input Parameters  : struct comedi_device *dev      : Driver handle                |
418 |                     struct comedi_subdevice *s,   :pointer to subdevice structure |
419 |                     struct comedi_insn *insn      :pointer to insn structure      |
420 |                     unsigned int *data          : Data Pointer to read status  |
421 +----------------------------------------------------------------------------+
422 | Output Parameters :   --                                                                                                       |
423 +----------------------------------------------------------------------------+
424 | Return Value      : TRUE  : No error occur                                 |
425 |                           : FALSE : Error occur. Return the error          |
426 |                                                                                |
427 +----------------------------------------------------------------------------+
428 */
429
430 int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s,
431         struct comedi_insn *insn, unsigned int *data)
432 {
433         udelay(5);
434         data[0] = inw(devpriv->i_IobaseAddon + APCI2016_WATCHDOG_STATUS) & 0x1;
435         return insn->n;
436 }
437
438 /*
439 +----------------------------------------------------------------------------+
440 | Function   Name   : int i_APCI2016_Reset(struct comedi_device *dev)               |                                                       |
441 +----------------------------------------------------------------------------+
442 | Task              :resets all the registers                                |
443 +----------------------------------------------------------------------------+
444 | Input Parameters  : struct comedi_device *dev
445 +----------------------------------------------------------------------------+
446 | Output Parameters :   --                                                                                                       |
447 +----------------------------------------------------------------------------+
448 | Return Value      :                                                        |
449 |                                                                                |
450 +----------------------------------------------------------------------------+
451 */
452
453 int i_APCI2016_Reset(struct comedi_device *dev)
454 {
455         outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP);       /*  Resets the digital output channels */
456         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE);
457         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE);
458         outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE + 2);
459         return 0;
460 }