Staging: comedi: Remove comedi_device typedef
[GitHub/mt8127/android_kernel_alcatel_ttab.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, comedi_devconfig * it);
101 static int c6xdigio_detach(struct comedi_device * dev);
102 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 comedi_subdevice * s, 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 comedi_subdevice * s, 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 // comedi_subdevice *s,
364 // 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 // comedi_subdevice *s,
373 // comedi_insn *insn,
374 // unsigned int *data)
375 //{
376 // int i;
377 // int chan = CR_CHAN(insn->chanspec);
378 //
379 // C6X_encResetAll( dev->iobase );
380 //
381 // return insn->n;
382 //}
383
384 static int c6xdigio_ei_insn_read(struct comedi_device * dev,
385 comedi_subdevice * s, comedi_insn * insn, unsigned int * data)
386 {
387 // printk("c6xdigio_ei__insn_read %x\n", insn->n);
388 int n;
389 int chan = CR_CHAN(insn->chanspec);
390
391 for (n = 0; n < insn->n; n++) {
392 data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff);
393 }
394
395 return n;
396 }
397
398 static void board_init(struct comedi_device * dev)
399 {
400
401 //printk("Inside board_init\n");
402
403 C6X_pwmInit(dev->iobase);
404 C6X_encResetAll(dev->iobase);
405
406 }
407
408 //static void board_halt(struct comedi_device *dev) {
409 // C6X_pwmInit(dev->iobase);
410 //}
411
412 /*
413 options[0] - I/O port
414 options[1] - irq
415 options[2] - number of encoder chips installed
416 */
417
418 static const struct pnp_device_id c6xdigio_pnp_tbl[] = {
419 /* Standard LPT Printer Port */
420 {.id = "PNP0400",.driver_data = 0},
421 /* ECP Printer Port */
422 {.id = "PNP0401",.driver_data = 0},
423 {}
424 };
425
426 static struct pnp_driver c6xdigio_pnp_driver = {
427 .name = "c6xdigio",
428 .id_table = c6xdigio_pnp_tbl,
429 };
430
431 static int c6xdigio_attach(struct comedi_device * dev, comedi_devconfig * it)
432 {
433 int result = 0;
434 unsigned long iobase;
435 unsigned int irq;
436 comedi_subdevice *s;
437
438 iobase = it->options[0];
439 printk("comedi%d: c6xdigio: 0x%04lx\n", dev->minor, iobase);
440 if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) {
441 printk("comedi%d: I/O port conflict\n", dev->minor);
442 return -EIO;
443 }
444 dev->iobase = iobase;
445 dev->board_name = "c6xdigio";
446
447 result = alloc_subdevices(dev, 2); // 3 with encoder_init write
448 if (result < 0)
449 return result;
450
451 // Make sure that PnP ports gets activated
452 pnp_register_driver(&c6xdigio_pnp_driver);
453
454 irq = it->options[1];
455 if (irq > 0) {
456 printk("comedi%d: irq = %u ignored\n", dev->minor, irq);
457 } else if (irq == 0) {
458 printk("comedi%d: no irq\n", dev->minor);
459 }
460
461 s = dev->subdevices + 0;
462 /* pwm output subdevice */
463 s->type = COMEDI_SUBD_AO; // Not sure what to put here
464 s->subdev_flags = SDF_WRITEABLE;
465 s->n_chan = 2;
466 /* s->trig[0] = c6xdigio_pwmo; */
467 s->insn_read = c6xdigio_pwmo_insn_read;
468 s->insn_write = c6xdigio_pwmo_insn_write;
469 s->maxdata = 500;
470 s->range_table = &range_bipolar10; // A suitable lie
471
472 s = dev->subdevices + 1;
473 /* encoder (counter) subdevice */
474 s->type = COMEDI_SUBD_COUNTER;
475 s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
476 s->n_chan = 2;
477 /* s->trig[0] = c6xdigio_ei; */
478 s->insn_read = c6xdigio_ei_insn_read;
479 s->maxdata = 0xffffff;
480 s->range_table = &range_unknown;
481
482 // s = dev->subdevices + 2;
483 // /* pwm output subdevice */
484 // s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here
485 // s->subdev_flags = SDF_WRITEABLE;
486 // s->n_chan = 1;
487 // /* s->trig[0] = c6xdigio_ei_init; */
488 // s->insn_read = c6xdigio_ei_init_insn_read;
489 // s->insn_write = c6xdigio_ei_init_insn_write;
490 // s->maxdata = 0xFFFF; // Really just a don't care
491 // s->range_table = &range_unknown; // Not sure what to put here
492
493 // I will call this init anyway but more than likely the DSP board will not be connect
494 // when device driver is loaded.
495 board_init(dev);
496
497 return 0;
498 }
499
500 static int c6xdigio_detach(struct comedi_device * dev)
501 {
502 // board_halt(dev); // may not need this
503
504 printk("comedi%d: c6xdigio: remove\n", dev->minor);
505
506 if (dev->iobase) {
507 release_region(dev->iobase, C6XDIGIO_SIZE);
508 }
509 if (dev->irq) {
510 free_irq(dev->irq, dev);
511 } // Not using IRQ so I am not sure if I need this
512 pnp_unregister_driver(&c6xdigio_pnp_driver);
513
514 return 0;
515 }
516
517 COMEDI_INITCLEANUP(driver_c6xdigio);