staging: comedi: addi_apci_2200: use addi_watchdog module
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / addi_apci_2200.c
1 #include "../comedidev.h"
2 #include "addi_watchdog.h"
3 #include "comedi_fc.h"
4
5 #include "addi-data/addi_common.h"
6
7 /*
8  * I/O Register Map
9  */
10 #define APCI2200_DI_REG                 0x00
11 #define APCI2200_DO_REG                 0x04
12 #define APCI2200_WDOG_REG               0x08
13
14 static const struct addi_board apci2200_boardtypes[] = {
15         {
16                 .pc_DriverName          = "apci2200",
17                 .i_VendorId             = PCI_VENDOR_ID_ADDIDATA,
18                 .i_DeviceId             = 0x1005,
19         },
20 };
21
22 static int apci2200_di_insn_bits(struct comedi_device *dev,
23                                  struct comedi_subdevice *s,
24                                  struct comedi_insn *insn,
25                                  unsigned int *data)
26 {
27         data[1] = inw(dev->iobase + APCI2200_DI_REG);
28
29         return insn->n;
30 }
31
32 static int apci2200_do_insn_bits(struct comedi_device *dev,
33                                  struct comedi_subdevice *s,
34                                  struct comedi_insn *insn,
35                                  unsigned int *data)
36 {
37         unsigned int mask = data[0];
38         unsigned int bits = data[1];
39
40         s->state = inw(dev->iobase + APCI2200_DO_REG);
41         if (mask) {
42                 s->state &= ~mask;
43                 s->state |= (bits & mask);
44
45                 outw(s->state, dev->iobase + APCI2200_DO_REG);
46         }
47
48         data[1] = s->state;
49
50         return insn->n;
51 }
52
53 static int apci2200_reset(struct comedi_device *dev)
54 {
55         outw(0x0, dev->iobase + APCI2200_DO_REG);
56
57         addi_watchdog_reset(dev->iobase + APCI2200_WDOG_REG);
58
59         return 0;
60 }
61
62 static const void *addi_find_boardinfo(struct comedi_device *dev,
63                                        struct pci_dev *pcidev)
64 {
65         const void *p = dev->driver->board_name;
66         const struct addi_board *this_board;
67         int i;
68
69         for (i = 0; i < dev->driver->num_names; i++) {
70                 this_board = p;
71                 if (this_board->i_VendorId == pcidev->vendor &&
72                     this_board->i_DeviceId == pcidev->device)
73                         return this_board;
74                 p += dev->driver->offset;
75         }
76         return NULL;
77 }
78
79 static int apci2200_auto_attach(struct comedi_device *dev,
80                                 unsigned long context_unused)
81 {
82         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
83         const struct addi_board *this_board;
84         struct addi_private *devpriv;
85         struct comedi_subdevice *s;
86         int ret, n_subdevices;
87
88         this_board = addi_find_boardinfo(dev, pcidev);
89         if (!this_board)
90                 return -ENODEV;
91         dev->board_ptr = this_board;
92         dev->board_name = this_board->pc_DriverName;
93
94         devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
95         if (!devpriv)
96                 return -ENOMEM;
97         dev->private = devpriv;
98
99         ret = comedi_pci_enable(pcidev, dev->board_name);
100         if (ret)
101                 return ret;
102
103         dev->iobase = pci_resource_start(pcidev, 1);
104
105         n_subdevices = 7;
106         ret = comedi_alloc_subdevices(dev, n_subdevices);
107         if (ret)
108                 return ret;
109
110         /*  Allocate and Initialise AI Subdevice Structures */
111         s = &dev->subdevices[0];
112         s->type = COMEDI_SUBD_UNUSED;
113
114         /*  Allocate and Initialise AO Subdevice Structures */
115         s = &dev->subdevices[1];
116         s->type = COMEDI_SUBD_UNUSED;
117
118         /*  Allocate and Initialise DI Subdevice Structures */
119         s = &dev->subdevices[2];
120         s->type         = COMEDI_SUBD_DI;
121         s->subdev_flags = SDF_READABLE;
122         s->n_chan       = 8;
123         s->maxdata      = 1;
124         s->range_table  = &range_digital;
125         s->insn_bits    = apci2200_di_insn_bits;
126
127         /*  Allocate and Initialise DO Subdevice Structures */
128         s = &dev->subdevices[3];
129         s->type         = COMEDI_SUBD_DO;
130         s->subdev_flags = SDF_WRITEABLE;
131         s->n_chan       = 16;
132         s->maxdata      = 1;
133         s->range_table  = &range_digital;
134         s->insn_bits    = apci2200_do_insn_bits;
135
136         /*  Allocate and Initialise Timer Subdevice Structures */
137         s = &dev->subdevices[4];
138         ret = addi_watchdog_init(s, dev->iobase + APCI2200_WDOG_REG);
139         if (ret)
140                 return ret;
141
142         /*  Allocate and Initialise TTL */
143         s = &dev->subdevices[5];
144         s->type = COMEDI_SUBD_UNUSED;
145
146         /* EEPROM */
147         s = &dev->subdevices[6];
148         s->type = COMEDI_SUBD_UNUSED;
149
150         apci2200_reset(dev);
151         return 0;
152 }
153
154 static void apci2200_detach(struct comedi_device *dev)
155 {
156         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
157         struct addi_private *devpriv = dev->private;
158
159         if (devpriv) {
160                 if (dev->iobase)
161                         apci2200_reset(dev);
162         }
163         if (dev->subdevices)
164                 addi_watchdog_cleanup(&dev->subdevices[4]);
165         if (pcidev) {
166                 if (dev->iobase)
167                         comedi_pci_disable(pcidev);
168         }
169 }
170
171 static struct comedi_driver apci2200_driver = {
172         .driver_name    = "addi_apci_2200",
173         .module         = THIS_MODULE,
174         .auto_attach    = apci2200_auto_attach,
175         .detach         = apci2200_detach,
176         .num_names      = ARRAY_SIZE(apci2200_boardtypes),
177         .board_name     = &apci2200_boardtypes[0].pc_DriverName,
178         .offset         = sizeof(struct addi_board),
179 };
180
181 static int apci2200_pci_probe(struct pci_dev *dev,
182                                         const struct pci_device_id *ent)
183 {
184         return comedi_pci_auto_config(dev, &apci2200_driver);
185 }
186
187 static void apci2200_pci_remove(struct pci_dev *dev)
188 {
189         comedi_pci_auto_unconfig(dev);
190 }
191
192 static DEFINE_PCI_DEVICE_TABLE(apci2200_pci_table) = {
193         { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) },
194         { 0 }
195 };
196 MODULE_DEVICE_TABLE(pci, apci2200_pci_table);
197
198 static struct pci_driver apci2200_pci_driver = {
199         .name           = "addi_apci_2200",
200         .id_table       = apci2200_pci_table,
201         .probe          = apci2200_pci_probe,
202         .remove         = apci2200_pci_remove,
203 };
204 module_comedi_pci_driver(apci2200_driver, apci2200_pci_driver);
205
206 MODULE_AUTHOR("Comedi http://www.comedi.org");
207 MODULE_DESCRIPTION("Comedi low-level driver");
208 MODULE_LICENSE("GPL");