Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / pcl725.c
1 /*
2 * comedi/drivers/pcl725.c
3 * Driver for PCL725 and clones
4 * David A. Schleef
5 */
6 /*
7 Driver: pcl725
8 Description: Advantech PCL-725 (& compatibles)
9 Author: ds
10 Status: unknown
11 Devices: [Advantech] PCL-725 (pcl725)
12 */
13
14 #include "../comedidev.h"
15
16 #include <linux/ioport.h>
17
18 #define PCL725_SIZE 2
19
20 #define PCL725_DO 0
21 #define PCL725_DI 1
22
23 static int pcl725_attach(struct comedi_device *dev,
24 struct comedi_devconfig *it);
25 static int pcl725_detach(struct comedi_device *dev);
26 static struct comedi_driver driver_pcl725 = {
27 .driver_name = "pcl725",
28 .module = THIS_MODULE,
29 .attach = pcl725_attach,
30 .detach = pcl725_detach,
31 };
32
33 COMEDI_INITCLEANUP(driver_pcl725);
34
35 static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
36 struct comedi_insn *insn, unsigned int *data)
37 {
38 if (insn->n != 2)
39 return -EINVAL;
40
41 if (data[0]) {
42 s->state &= ~data[0];
43 s->state |= (data[0] & data[1]);
44 outb(s->state, dev->iobase + PCL725_DO);
45 }
46
47 data[1] = s->state;
48
49 return 2;
50 }
51
52 static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s,
53 struct comedi_insn *insn, unsigned int *data)
54 {
55 if (insn->n != 2)
56 return -EINVAL;
57
58 data[1] = inb(dev->iobase + PCL725_DI);
59
60 return 2;
61 }
62
63 static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
64 {
65 struct comedi_subdevice *s;
66 unsigned long iobase;
67
68 iobase = it->options[0];
69 printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase);
70 if (!request_region(iobase, PCL725_SIZE, "pcl725")) {
71 printk("I/O port conflict\n");
72 return -EIO;
73 }
74 dev->board_name = "pcl725";
75 dev->iobase = iobase;
76 dev->irq = 0;
77
78 if (alloc_subdevices(dev, 2) < 0)
79 return -ENOMEM;
80
81 s = dev->subdevices + 0;
82 /* do */
83 s->type = COMEDI_SUBD_DO;
84 s->subdev_flags = SDF_WRITABLE;
85 s->maxdata = 1;
86 s->n_chan = 8;
87 s->insn_bits = pcl725_do_insn;
88 s->range_table = &range_digital;
89
90 s = dev->subdevices + 1;
91 /* di */
92 s->type = COMEDI_SUBD_DI;
93 s->subdev_flags = SDF_READABLE;
94 s->maxdata = 1;
95 s->n_chan = 8;
96 s->insn_bits = pcl725_di_insn;
97 s->range_table = &range_digital;
98
99 printk(KERN_INFO "\n");
100
101 return 0;
102 }
103
104 static int pcl725_detach(struct comedi_device *dev)
105 {
106 printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
107
108 if (dev->iobase)
109 release_region(dev->iobase, PCL725_SIZE);
110
111 return 0;
112 }