Staging: comedi: Add spaces after commas
[deliverable/linux.git] / drivers / staging / comedi / drivers / c6xdigio.c
1 /*
2 comedi/drivers/c6xdigio.c
3
4 Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card.
5 (http://robot0.ge.uiuc.edu/~spong/mecha/)
6
7 COMEDI - Linux Control and Measurement Device Interface
8 Copyright (C) 1999 Dan Block
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25 /*
26 Driver: c6xdigio
27 Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
28 Author: Dan Block
29 Status: unknown
30 Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
31 Updated: Sun Nov 20 20:18:34 EST 2005
32
33 This driver will not work with a 2.4 kernel.
34 http://robot0.ge.uiuc.edu/~spong/mecha/
35
36 */
37
38 #include <linux/kernel.h>
39 #include <linux/module.h>
40 #include <linux/sched.h>
41 #include <linux/mm.h>
42 #include <linux/errno.h>
43 #include <linux/ioport.h>
44 #include <linux/delay.h>
45 #include <linux/interrupt.h>
46 #include <linux/timex.h>
47 #include <linux/timer.h>
48 #include <asm/io.h>
49 #include <linux/pnp.h>
50
51 #include "../comedidev.h"
52
53 static u8 ReadByteFromHwPort(unsigned long addr)
54 {
55 u8 result = inb(addr);
56 return result;
57 }
58
59 static void WriteByteToHwPort(unsigned long addr, u8 val)
60 {
61 outb_p(val, addr);
62 }
63
64 #define C6XDIGIO_SIZE 3
65
66 /*
67 * port offsets
68 */
69 #define C6XDIGIO_PARALLEL_DATA 0
70 #define C6XDIGIO_PARALLEL_STATUS 1
71 #define C6XDIGIO_PARALLEL_CONTROL 2
72 struct pwmbitstype {
73 unsigned sb0:2;
74 unsigned sb1:2;
75 unsigned sb2:2;
76 unsigned sb3:2;
77 unsigned sb4:2;
78 };
79 union pwmcmdtype {
80 unsigned cmd; /* assuming here that int is 32bit */
81 struct pwmbitstype bits;
82 };
83 struct encbitstype {
84 unsigned sb0:3;
85 unsigned sb1:3;
86 unsigned sb2:3;
87 unsigned sb3:3;
88 unsigned sb4:3;
89 unsigned sb5:3;
90 unsigned sb6:3;
91 unsigned sb7:3;
92 };
93 union encvaluetype {
94 unsigned value;
95 struct encbitstype bits;
96 };
97
98 #define C6XDIGIO_TIME_OUT 20
99
100 static int c6xdigio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
101 static int c6xdigio_detach(struct comedi_device *dev);
102 struct comedi_driver driver_c6xdigio = {
103 driver_name:"c6xdigio",
104 module:THIS_MODULE,
105 attach:c6xdigio_attach,
106 detach:c6xdigio_detach,
107 };
108
109 static void C6X_pwmInit(unsigned long baseAddr)
110 {
111 int timeout = 0;
112
113 /* printk("Inside C6X_pwmInit\n"); */
114
115 WriteByteToHwPort(baseAddr, 0x70);
116 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
117 && (timeout < C6XDIGIO_TIME_OUT)) {
118 timeout++;
119 }
120
121 WriteByteToHwPort(baseAddr, 0x74);
122 timeout = 0;
123 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
124 && (timeout < C6XDIGIO_TIME_OUT)) {
125 timeout++;
126 }
127
128 WriteByteToHwPort(baseAddr, 0x70);
129 timeout = 0;
130 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
131 && (timeout < C6XDIGIO_TIME_OUT)) {
132 timeout++;
133 }
134
135 WriteByteToHwPort(baseAddr, 0x0);
136 timeout = 0;
137 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
138 && (timeout < C6XDIGIO_TIME_OUT)) {
139 timeout++;
140 }
141
142 }
143
144 static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value)
145 {
146 unsigned ppcmd;
147 union pwmcmdtype pwm;
148 int timeout = 0;
149 unsigned tmp;
150
151 /* printk("Inside C6X_pwmOutput\n"); */
152
153 pwm.cmd = value;
154 if (pwm.cmd > 498)
155 pwm.cmd = 498;
156 if (pwm.cmd < 2)
157 pwm.cmd = 2;
158
159 if (channel == 0) {
160 ppcmd = 0x28;
161 } else { /* if channel == 1 */
162 ppcmd = 0x30;
163 } /* endif */
164
165 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0);
166 tmp = ReadByteFromHwPort(baseAddr + 1);
167 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
168 tmp = ReadByteFromHwPort(baseAddr + 1);
169 timeout++;
170 }
171
172 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4);
173 timeout = 0;
174 tmp = ReadByteFromHwPort(baseAddr + 1);
175 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
176 tmp = ReadByteFromHwPort(baseAddr + 1);
177 timeout++;
178 }
179
180 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2);
181 tmp = ReadByteFromHwPort(baseAddr + 1);
182 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
183 tmp = ReadByteFromHwPort(baseAddr + 1);
184 timeout++;
185 }
186
187 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4);
188 timeout = 0;
189 tmp = ReadByteFromHwPort(baseAddr + 1);
190 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
191 tmp = ReadByteFromHwPort(baseAddr + 1);
192 timeout++;
193 }
194
195 WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4);
196 tmp = ReadByteFromHwPort(baseAddr + 1);
197 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
198 tmp = ReadByteFromHwPort(baseAddr + 1);
199 timeout++;
200 }
201
202 WriteByteToHwPort(baseAddr, 0x0);
203 timeout = 0;
204 tmp = ReadByteFromHwPort(baseAddr + 1);
205 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
206 tmp = ReadByteFromHwPort(baseAddr + 1);
207 timeout++;
208 }
209
210 }
211
212 static int C6X_encInput(unsigned long baseAddr, unsigned channel)
213 {
214 unsigned ppcmd;
215 union encvaluetype enc;
216 int timeout = 0;
217 int tmp;
218
219 /* printk("Inside C6X_encInput\n"); */
220
221 enc.value = 0;
222 if (channel == 0) {
223 ppcmd = 0x48;
224 } else {
225 ppcmd = 0x50;
226 }
227 WriteByteToHwPort(baseAddr, ppcmd);
228 tmp = ReadByteFromHwPort(baseAddr + 1);
229 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
230 tmp = ReadByteFromHwPort(baseAddr + 1);
231 timeout++;
232 }
233
234 enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
235 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
236 timeout = 0;
237 tmp = ReadByteFromHwPort(baseAddr + 1);
238 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
239 tmp = ReadByteFromHwPort(baseAddr + 1);
240 timeout++;
241 }
242 enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
243 WriteByteToHwPort(baseAddr, ppcmd);
244 timeout = 0;
245 tmp = ReadByteFromHwPort(baseAddr + 1);
246 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
247 tmp = ReadByteFromHwPort(baseAddr + 1);
248 timeout++;
249 }
250 enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
251 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
252 timeout = 0;
253 tmp = ReadByteFromHwPort(baseAddr + 1);
254 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
255 tmp = ReadByteFromHwPort(baseAddr + 1);
256 timeout++;
257 }
258 enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
259 WriteByteToHwPort(baseAddr, ppcmd);
260 timeout = 0;
261 tmp = ReadByteFromHwPort(baseAddr + 1);
262 while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) {
263 tmp = ReadByteFromHwPort(baseAddr + 1);
264 timeout++;
265 }
266 enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
267 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
268 timeout = 0;
269 tmp = ReadByteFromHwPort(baseAddr + 1);
270 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
271 tmp = ReadByteFromHwPort(baseAddr + 1);
272 timeout++;
273 }
274 enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
275 WriteByteToHwPort(baseAddr, ppcmd);
276 timeout = 0;
277 tmp = ReadByteFromHwPort(baseAddr + 1);
278 while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
279 tmp = ReadByteFromHwPort(baseAddr + 1);
280 timeout++;
281 }
282 enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
283 WriteByteToHwPort(baseAddr, ppcmd + 0x4);
284 timeout = 0;
285 tmp = ReadByteFromHwPort(baseAddr + 1);
286 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
287 tmp = ReadByteFromHwPort(baseAddr + 1);
288 timeout++;
289 }
290 enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7);
291 WriteByteToHwPort(baseAddr, ppcmd);
292 timeout = 0;
293 tmp = ReadByteFromHwPort(baseAddr + 1);
294 while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) {
295 tmp = ReadByteFromHwPort(baseAddr + 1);
296 timeout++;
297 }
298
299 WriteByteToHwPort(baseAddr, 0x0);
300 timeout = 0;
301 tmp = ReadByteFromHwPort(baseAddr + 1);
302 while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) {
303 tmp = ReadByteFromHwPort(baseAddr + 1);
304 timeout++;
305 }
306
307 return (enc.value ^ 0x800000);
308 }
309
310 static void C6X_encResetAll(unsigned long baseAddr)
311 {
312 unsigned timeout = 0;
313
314 /* printk("Inside C6X_encResetAll\n"); */
315
316 WriteByteToHwPort(baseAddr, 0x68);
317 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0)
318 && (timeout < C6XDIGIO_TIME_OUT)) {
319 timeout++;
320 }
321 WriteByteToHwPort(baseAddr, 0x6C);
322 timeout = 0;
323 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
324 && (timeout < C6XDIGIO_TIME_OUT)) {
325 timeout++;
326 }
327 WriteByteToHwPort(baseAddr, 0x68);
328 timeout = 0;
329 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0)
330 && (timeout < C6XDIGIO_TIME_OUT)) {
331 timeout++;
332 }
333 WriteByteToHwPort(baseAddr, 0x0);
334 timeout = 0;
335 while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80)
336 && (timeout < C6XDIGIO_TIME_OUT)) {
337 timeout++;
338 }
339 }
340
341 static int c6xdigio_pwmo_insn_read(struct comedi_device *dev,
342 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
343 {
344 printk("c6xdigio_pwmo_insn_read %x\n", insn->n);
345 return insn->n;
346 }
347
348 static int c6xdigio_pwmo_insn_write(struct comedi_device *dev,
349 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
350 {
351 int i;
352 int chan = CR_CHAN(insn->chanspec);
353
354 /* printk("c6xdigio_pwmo_insn_write %x\n", insn->n); */
355 for (i = 0; i < insn->n; i++) {
356 C6X_pwmOutput(dev->iobase, chan, data[i]);
357 /* devpriv->ao_readback[chan] = data[i]; */
358 }
359 return i;
360 }
361
362 /* static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, */
363 /* struct comedi_subdevice *s, */
364 /* struct comedi_insn *insn, */
365 /* unsigned int *data) */
366 /* { */
367 /* printk("c6xdigio_ei_init_insn_read %x\n", insn->n); */
368 /* return insn->n; */
369 /* } */
370
371 /* static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, */
372 /* struct comedi_subdevice *s, */
373 /* struct comedi_insn *insn, */
374 /* unsigned int *data) */
375 /* { */
376 /* int i; */
377 /* int chan = CR_CHAN(insn->chanspec); */
378 /* *//* C6X_encResetAll( dev->iobase ); */
379 /* *//* return insn->n; */
380 /* } */
381
382 static int c6xdigio_ei_insn_read(struct comedi_device *dev,
383 struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data)
384 {
385 /* printk("c6xdigio_ei__insn_read %x\n", insn->n); */
386 int n;
387 int chan = CR_CHAN(insn->chanspec);
388
389 for (n = 0; n < insn->n; n++) {
390 data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
391 }
392
393 return n;
394 }
395
396 static void board_init(struct comedi_device *dev)
397 {
398
399 /* printk("Inside board_init\n"); */
400
401 C6X_pwmInit(dev->iobase);
402 C6X_encResetAll(dev->iobase);
403
404 }
405
406 /* static void board_halt(struct comedi_device *dev) { */
407 /* C6X_pwmInit(dev->iobase); */
408 /* } */
409
410 /*
411 options[0] - I/O port
412 options[1] - irq
413 options[2] - number of encoder chips installed
414 */
415
416 static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
417 /* Standard LPT Printer Port */
418 {.id = "PNP0400", .driver_data = 0},
419 /* ECP Printer Port */
420 {.id = "PNP0401", .driver_data = 0},
421 {}
422 };
423
424 static struct pnp_driver c6xdigio_pnp_driver = {
425 .name = "c6xdigio",
426 .id_table = c6xdigio_pnp_tbl,
427 };
428
429 static int c6xdigio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
430 {
431 int result = 0;
432 unsigned long iobase;
433 unsigned int irq;
434 struct comedi_subdevice *s;
435
436 iobase = it->options[0];
437 printk("comedi%d: c6xdigio: 0x%04lx\n", dev->minor, iobase);
438 if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) {
439 printk("comedi%d: I/O port conflict\n", dev->minor);
440 return -EIO;
441 }
442 dev->iobase = iobase;
443 dev->board_name = "c6xdigio";
444
445 result = alloc_subdevices(dev, 2); /* 3 with encoder_init write */
446 if (result < 0)
447 return result;
448
449 /* Make sure that PnP ports gets activated */
450 pnp_register_driver(&c6xdigio_pnp_driver);
451
452 irq = it->options[1];
453 if (irq > 0) {
454 printk("comedi%d: irq = %u ignored\n", dev->minor, irq);
455 } else if (irq == 0) {
456 printk("comedi%d: no irq\n", dev->minor);
457 }
458
459 s = dev->subdevices + 0;
460 /* pwm output subdevice */
461 s->type = COMEDI_SUBD_AO; /* Not sure what to put here */
462 s->subdev_flags = SDF_WRITEABLE;
463 s->n_chan = 2;
464 /* s->trig[0] = c6xdigio_pwmo; */
465 s->insn_read = c6xdigio_pwmo_insn_read;
466 s->insn_write = c6xdigio_pwmo_insn_write;
467 s->maxdata = 500;
468 s->range_table = &range_bipolar10; /* A suitable lie */
469
470 s = dev->subdevices + 1;
471 /* encoder (counter) subdevice */
472 s->type = COMEDI_SUBD_COUNTER;
473 s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
474 s->n_chan = 2;
475 /* s->trig[0] = c6xdigio_ei; */
476 s->insn_read = c6xdigio_ei_insn_read;
477 s->maxdata = 0xffffff;
478 s->range_table = &range_unknown;
479
480 /* s = dev->subdevices + 2; */
481 /* pwm output subdevice */
482 /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */
483 /* s->subdev_flags = SDF_WRITEABLE; */
484 /* s->n_chan = 1; */
485 /* s->trig[0] = c6xdigio_ei_init; */
486 /* s->insn_read = c6xdigio_ei_init_insn_read; */
487 /* s->insn_write = c6xdigio_ei_init_insn_write; */
488 /* s->maxdata = 0xFFFF; // Really just a don't care */
489 /* s->range_table = &range_unknown; // Not sure what to put here */
490
491 /* I will call this init anyway but more than likely the DSP board will not be connect */
492 /* when device driver is loaded. */
493 board_init(dev);
494
495 return 0;
496 }
497
498 static int c6xdigio_detach(struct comedi_device *dev)
499 {
500 /* board_halt(dev); may not need this */
501
502 printk("comedi%d: c6xdigio: remove\n", dev->minor);
503
504 if (dev->iobase) {
505 release_region(dev->iobase, C6XDIGIO_SIZE);
506 }
507 if (dev->irq) {
508 free_irq(dev->irq, dev);
509 } /* Not using IRQ so I am not sure if I need this */
510 pnp_unregister_driver(&c6xdigio_pnp_driver);
511
512 return 0;
513 }
514
515 COMEDI_INITCLEANUP(driver_c6xdigio);
This page took 0.045088 seconds and 5 git commands to generate.