d5eb68b4f00f594583d69e57be9153e1627ee1c7
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / adl_pci8164.c
1 /*
2     comedi/drivers/adl_pci8164.c
3
4     Hardware comedi driver fot PCI-8164 Adlink card
5     Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22 /*
23 Driver: adl_pci8164
24 Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
25 Devices: [ADLink] PCI-8164 (adl_pci8164)
26 Author: Michel Lachaine <mike@mikelachaine.ca>
27 Status: experimental
28 Updated: Mon, 14 Apr 2008 15:10:32 +0100
29
30 Configuration Options: not applicable, uses PCI auto config
31 */
32
33 #include "../comedidev.h"
34 #include <linux/kernel.h>
35 #include <linux/delay.h>
36 #include "comedi_fc.h"
37 #include "8253.h"
38
39 #define PCI8164_AXIS_X  0x00
40 #define PCI8164_AXIS_Y  0x08
41 #define PCI8164_AXIS_Z  0x10
42 #define PCI8164_AXIS_U  0x18
43
44 #define PCI8164_MSTS    0x00
45 #define PCI8164_SSTS    0x02
46 #define PCI8164_BUF0    0x04
47 #define PCI8164_BUF1    0x06
48
49 #define PCI8164_CMD     0x00
50 #define PCI8164_OTP     0x02
51
52 #define PCI_DEVICE_ID_PCI8164 0x8164
53
54 /*
55  all the read commands are the same except for the addition a constant
56  * const to the data for inw()
57  */
58 static void adl_pci8164_insn_read(struct comedi_device *dev,
59                                   struct comedi_subdevice *s,
60                                   struct comedi_insn *insn,
61                                   unsigned int *data,
62                                   char *action, unsigned short offset)
63 {
64         int axis, axis_reg;
65         char *axisname;
66
67         axis = CR_CHAN(insn->chanspec);
68
69         switch (axis) {
70         case 0:
71                 axis_reg = PCI8164_AXIS_X;
72                 axisname = "X";
73                 break;
74         case 1:
75                 axis_reg = PCI8164_AXIS_Y;
76                 axisname = "Y";
77                 break;
78         case 2:
79                 axis_reg = PCI8164_AXIS_Z;
80                 axisname = "Z";
81                 break;
82         case 3:
83                 axis_reg = PCI8164_AXIS_U;
84                 axisname = "U";
85                 break;
86         default:
87                 axis_reg = PCI8164_AXIS_X;
88                 axisname = "X";
89         }
90
91         data[0] = inw(dev->iobase + axis_reg + offset);
92         dev_dbg(dev->class_dev,
93                 "pci8164 %s read -> %04X:%04X on axis %s\n",
94                 action, data[0], data[1], axisname);
95 }
96
97 static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
98                                       struct comedi_subdevice *s,
99                                       struct comedi_insn *insn,
100                                       unsigned int *data)
101 {
102         adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
103         return 2;
104 }
105
106 static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
107                                       struct comedi_subdevice *s,
108                                       struct comedi_insn *insn,
109                                       unsigned int *data)
110 {
111         adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
112         return 2;
113 }
114
115 static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
116                                       struct comedi_subdevice *s,
117                                       struct comedi_insn *insn,
118                                       unsigned int *data)
119 {
120         adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
121         return 2;
122 }
123
124 static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
125                                       struct comedi_subdevice *s,
126                                       struct comedi_insn *insn,
127                                       unsigned int *data)
128 {
129         adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
130         return 2;
131 }
132
133 /*
134  all the write commands are the same except for the addition a constant
135  * const to the data for outw()
136  */
137 static void adl_pci8164_insn_out(struct comedi_device *dev,
138                                  struct comedi_subdevice *s,
139                                  struct comedi_insn *insn,
140                                  unsigned int *data,
141                                  char *action, unsigned short offset)
142 {
143         unsigned int axis, axis_reg;
144
145         char *axisname;
146
147         axis = CR_CHAN(insn->chanspec);
148
149         switch (axis) {
150         case 0:
151                 axis_reg = PCI8164_AXIS_X;
152                 axisname = "X";
153                 break;
154         case 1:
155                 axis_reg = PCI8164_AXIS_Y;
156                 axisname = "Y";
157                 break;
158         case 2:
159                 axis_reg = PCI8164_AXIS_Z;
160                 axisname = "Z";
161                 break;
162         case 3:
163                 axis_reg = PCI8164_AXIS_U;
164                 axisname = "U";
165                 break;
166         default:
167                 axis_reg = PCI8164_AXIS_X;
168                 axisname = "X";
169         }
170
171         outw(data[0], dev->iobase + axis_reg + offset);
172
173         dev_dbg(dev->class_dev,
174                 "pci8164 %s write -> %04X:%04X on axis %s\n",
175                 action, data[0], data[1], axisname);
176
177 }
178
179 static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
180                                       struct comedi_subdevice *s,
181                                       struct comedi_insn *insn,
182                                       unsigned int *data)
183 {
184         adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
185         return 2;
186 }
187
188 static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
189                                       struct comedi_subdevice *s,
190                                       struct comedi_insn *insn,
191                                       unsigned int *data)
192 {
193         adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
194         return 2;
195 }
196
197 static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
198                                        struct comedi_subdevice *s,
199                                        struct comedi_insn *insn,
200                                        unsigned int *data)
201 {
202         adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
203         return 2;
204 }
205
206 static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
207                                        struct comedi_subdevice *s,
208                                        struct comedi_insn *insn,
209                                        unsigned int *data)
210 {
211         adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
212         return 2;
213 }
214
215 static int __devinit adl_pci8164_auto_attach(struct comedi_device *dev,
216                                              unsigned long context_unused)
217 {
218         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
219         struct comedi_subdevice *s;
220         int ret;
221
222         dev->board_name = dev->driver->driver_name;
223
224         ret = comedi_pci_enable(pcidev, dev->board_name);
225         if (ret)
226                 return ret;
227         dev->iobase = pci_resource_start(pcidev, 2);
228
229         ret = comedi_alloc_subdevices(dev, 4);
230         if (ret)
231                 return ret;
232
233         s = &dev->subdevices[0];
234         s->type = COMEDI_SUBD_PROC;
235         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
236         s->n_chan = 4;
237         s->maxdata = 0xffff;
238         s->len_chanlist = 4;
239         /* s->range_table = &range_axis; */
240         s->insn_read = adl_pci8164_insn_read_msts;
241         s->insn_write = adl_pci8164_insn_write_cmd;
242
243         s = &dev->subdevices[1];
244         s->type = COMEDI_SUBD_PROC;
245         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
246         s->n_chan = 4;
247         s->maxdata = 0xffff;
248         s->len_chanlist = 4;
249         /* s->range_table = &range_axis; */
250         s->insn_read = adl_pci8164_insn_read_ssts;
251         s->insn_write = adl_pci8164_insn_write_otp;
252
253         s = &dev->subdevices[2];
254         s->type = COMEDI_SUBD_PROC;
255         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
256         s->n_chan = 4;
257         s->maxdata = 0xffff;
258         s->len_chanlist = 4;
259         /* s->range_table = &range_axis; */
260         s->insn_read = adl_pci8164_insn_read_buf0;
261         s->insn_write = adl_pci8164_insn_write_buf0;
262
263         s = &dev->subdevices[3];
264         s->type = COMEDI_SUBD_PROC;
265         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
266         s->n_chan = 4;
267         s->maxdata = 0xffff;
268         s->len_chanlist = 4;
269         /* s->range_table = &range_axis; */
270         s->insn_read = adl_pci8164_insn_read_buf1;
271         s->insn_write = adl_pci8164_insn_write_buf1;
272
273         dev_info(dev->class_dev, "%s attached\n", dev->board_name);
274
275         return 0;
276 }
277
278 static void adl_pci8164_detach(struct comedi_device *dev)
279 {
280         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
281
282         if (pcidev) {
283                 if (dev->iobase)
284                         comedi_pci_disable(pcidev);
285         }
286 }
287
288 static struct comedi_driver adl_pci8164_driver = {
289         .driver_name    = "adl_pci8164",
290         .module         = THIS_MODULE,
291         .auto_attach    = adl_pci8164_auto_attach,
292         .detach         = adl_pci8164_detach,
293 };
294
295 static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev,
296                                            const struct pci_device_id *ent)
297 {
298         return comedi_pci_auto_config(dev, &adl_pci8164_driver);
299 }
300
301 static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev)
302 {
303         comedi_pci_auto_unconfig(dev);
304 }
305
306 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
307         { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
308         {0}
309 };
310 MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
311
312 static struct pci_driver adl_pci8164_pci_driver = {
313         .name           = "adl_pci8164",
314         .id_table       = adl_pci8164_pci_table,
315         .probe          = adl_pci8164_pci_probe,
316         .remove         = adl_pci8164_pci_remove,
317 };
318 module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
319
320 MODULE_AUTHOR("Comedi http://www.comedi.org");
321 MODULE_DESCRIPTION("Comedi low-level driver");
322 MODULE_LICENSE("GPL");