staging: comedi: 8255: use __comedi_request_region()
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / comedi / drivers / 8255.c
1 /*
2     comedi/drivers/8255.c
3     Driver for 8255
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1998 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23 /*
24 Driver: 8255
25 Description: generic 8255 support
26 Devices: [standard] 8255 (8255)
27 Author: ds
28 Status: works
29 Updated: Fri,  7 Jun 2002 12:56:45 -0700
30
31 The classic in digital I/O.  The 8255 appears in Comedi as a single
32 digital I/O subdevice with 24 channels.  The channel 0 corresponds
33 to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
34 7.  Direction configuration is done in blocks, with channels 0-7,
35 8-15, 16-19, and 20-23 making up the 4 blocks.  The only 8255 mode
36 supported is mode 0.
37
38 You should enable compilation this driver if you plan to use a board
39 that has an 8255 chip.  For multifunction boards, the main driver will
40 configure the 8255 subdevice automatically.
41
42 This driver also works independently with ISA and PCI cards that
43 directly map the 8255 registers to I/O ports, including cards with
44 multiple 8255 chips.  To configure the driver for such a card, the
45 option list should be a list of the I/O port bases for each of the
46 8255 chips.  For example,
47
48   comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
49
50 Note that most PCI 8255 boards do NOT work with this driver, and
51 need a separate driver as a wrapper.  For those that do work, the
52 I/O port base address can be found in the output of 'lspci -v'.
53
54 */
55
56 /*
57    This file contains an exported subdevice for driving an 8255.
58
59    To use this subdevice as part of another driver, you need to
60    set up the subdevice in the attach function of the driver by
61    calling:
62
63      subdev_8255_init(device, subdevice, io_function, iobase)
64
65    device and subdevice are pointers to the device and subdevice
66    structures.  io_function will be called to provide the
67    low-level input/output to the device, i.e., actual register
68    access.  io_function will be called with the value of iobase
69    as the last parameter.  If the 8255 device is mapped as 4
70    consecutive I/O ports, you can use NULL for io_function
71    and the I/O port base for iobase, and an internal function will
72    handle the register access.
73
74    In addition, if the main driver handles interrupts, you can
75    enable commands on the subdevice by calling subdev_8255_init_irq()
76    instead.  Then, when you get an interrupt that is likely to be
77    from the 8255, you should call subdev_8255_interrupt(), which
78    will copy the latched value to a Comedi buffer.
79  */
80
81 #include "../comedidev.h"
82
83 #include <linux/ioport.h>
84 #include <linux/slab.h>
85
86 #include "comedi_fc.h"
87 #include "8255.h"
88
89 #define _8255_SIZE      4
90
91 #define _8255_DATA      0
92 #define _8255_CR        3
93
94 #define CR_C_LO_IO      0x01
95 #define CR_B_IO         0x02
96 #define CR_B_MODE       0x04
97 #define CR_C_HI_IO      0x08
98 #define CR_A_IO         0x10
99 #define CR_A_MODE(a)    ((a)<<5)
100 #define CR_CW           0x80
101
102 struct subdev_8255_private {
103         unsigned long iobase;
104         int (*io) (int, int, int, unsigned long);
105 };
106
107 static int subdev_8255_io(int dir, int port, int data, unsigned long iobase)
108 {
109         if (dir) {
110                 outb(data, iobase + port);
111                 return 0;
112         } else {
113                 return inb(iobase + port);
114         }
115 }
116
117 void subdev_8255_interrupt(struct comedi_device *dev,
118                            struct comedi_subdevice *s)
119 {
120         struct subdev_8255_private *spriv = s->private;
121         unsigned long iobase = spriv->iobase;
122         short d;
123
124         d = spriv->io(0, _8255_DATA, 0, iobase);
125         d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
126
127         comedi_buf_put(s->async, d);
128         s->async->events |= COMEDI_CB_EOS;
129
130         comedi_event(dev, s);
131 }
132 EXPORT_SYMBOL(subdev_8255_interrupt);
133
134 static int subdev_8255_insn(struct comedi_device *dev,
135                             struct comedi_subdevice *s,
136                             struct comedi_insn *insn, unsigned int *data)
137 {
138         struct subdev_8255_private *spriv = s->private;
139         unsigned long iobase = spriv->iobase;
140         unsigned int mask;
141         unsigned int bits;
142         unsigned int v;
143
144         mask = data[0];
145         bits = data[1];
146
147         if (mask) {
148                 v = s->state;
149                 v &= ~mask;
150                 v |= (bits & mask);
151
152                 if (mask & 0xff)
153                         spriv->io(1, _8255_DATA, v & 0xff, iobase);
154                 if (mask & 0xff00)
155                         spriv->io(1, _8255_DATA + 1, (v >> 8) & 0xff, iobase);
156                 if (mask & 0xff0000)
157                         spriv->io(1, _8255_DATA + 2, (v >> 16) & 0xff, iobase);
158
159                 s->state = v;
160         }
161
162         v = spriv->io(0, _8255_DATA, 0, iobase);
163         v |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8);
164         v |= (spriv->io(0, _8255_DATA + 2, 0, iobase) << 16);
165
166         data[1] = v;
167
168         return insn->n;
169 }
170
171 static void subdev_8255_do_config(struct comedi_device *dev,
172                                   struct comedi_subdevice *s)
173 {
174         struct subdev_8255_private *spriv = s->private;
175         unsigned long iobase = spriv->iobase;
176         int config;
177
178         config = CR_CW;
179         /* 1 in io_bits indicates output, 1 in config indicates input */
180         if (!(s->io_bits & 0x0000ff))
181                 config |= CR_A_IO;
182         if (!(s->io_bits & 0x00ff00))
183                 config |= CR_B_IO;
184         if (!(s->io_bits & 0x0f0000))
185                 config |= CR_C_LO_IO;
186         if (!(s->io_bits & 0xf00000))
187                 config |= CR_C_HI_IO;
188
189         spriv->io(1, _8255_CR, config, iobase);
190 }
191
192 static int subdev_8255_insn_config(struct comedi_device *dev,
193                                    struct comedi_subdevice *s,
194                                    struct comedi_insn *insn, unsigned int *data)
195 {
196         unsigned int mask;
197         unsigned int bits;
198
199         mask = 1 << CR_CHAN(insn->chanspec);
200         if (mask & 0x0000ff)
201                 bits = 0x0000ff;
202         else if (mask & 0x00ff00)
203                 bits = 0x00ff00;
204         else if (mask & 0x0f0000)
205                 bits = 0x0f0000;
206         else
207                 bits = 0xf00000;
208
209         switch (data[0]) {
210         case INSN_CONFIG_DIO_INPUT:
211                 s->io_bits &= ~bits;
212                 break;
213         case INSN_CONFIG_DIO_OUTPUT:
214                 s->io_bits |= bits;
215                 break;
216         case INSN_CONFIG_DIO_QUERY:
217                 data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
218                 return insn->n;
219                 break;
220         default:
221                 return -EINVAL;
222         }
223
224         subdev_8255_do_config(dev, s);
225
226         return 1;
227 }
228
229 static int subdev_8255_cmdtest(struct comedi_device *dev,
230                                struct comedi_subdevice *s,
231                                struct comedi_cmd *cmd)
232 {
233         int err = 0;
234
235         /* Step 1 : check if triggers are trivially valid */
236
237         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
238         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
239         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
240         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
241         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
242
243         if (err)
244                 return 1;
245
246         /* Step 2a : make sure trigger sources are unique */
247         /* Step 2b : and mutually compatible */
248
249         if (err)
250                 return 2;
251
252         /* Step 3: check if arguments are trivially valid */
253
254         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
255         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
256         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
257         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
258         err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
259
260         if (err)
261                 return 3;
262
263         /* step 4 */
264
265         if (err)
266                 return 4;
267
268         return 0;
269 }
270
271 static int subdev_8255_cmd(struct comedi_device *dev,
272                            struct comedi_subdevice *s)
273 {
274         /* FIXME */
275
276         return 0;
277 }
278
279 static int subdev_8255_cancel(struct comedi_device *dev,
280                               struct comedi_subdevice *s)
281 {
282         /* FIXME */
283
284         return 0;
285 }
286
287 int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
288                      int (*io) (int, int, int, unsigned long),
289                      unsigned long iobase)
290 {
291         struct subdev_8255_private *spriv;
292
293         spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);
294         if (!spriv)
295                 return -ENOMEM;
296
297         spriv->iobase   = iobase;
298         spriv->io       = io ? io : subdev_8255_io;
299
300         s->private      = spriv;
301
302         s->type         = COMEDI_SUBD_DIO;
303         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
304         s->n_chan       = 24;
305         s->range_table  = &range_digital;
306         s->maxdata      = 1;
307         s->insn_bits    = subdev_8255_insn;
308         s->insn_config  = subdev_8255_insn_config;
309
310         s->state        = 0;
311         s->io_bits      = 0;
312
313         subdev_8255_do_config(dev, s);
314
315         return 0;
316 }
317 EXPORT_SYMBOL(subdev_8255_init);
318
319 int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s,
320                          int (*io) (int, int, int, unsigned long),
321                          unsigned long iobase)
322 {
323         int ret;
324
325         ret = subdev_8255_init(dev, s, io, iobase);
326         if (ret)
327                 return ret;
328
329         s->do_cmdtest   = subdev_8255_cmdtest;
330         s->do_cmd       = subdev_8255_cmd;
331         s->cancel       = subdev_8255_cancel;
332
333         return 0;
334 }
335 EXPORT_SYMBOL(subdev_8255_init_irq);
336
337 void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s)
338 {
339         kfree(s->private);
340 }
341 EXPORT_SYMBOL(subdev_8255_cleanup);
342
343 /*
344
345    Start of the 8255 standalone device
346
347  */
348
349 static int dev_8255_attach(struct comedi_device *dev,
350                            struct comedi_devconfig *it)
351 {
352         struct comedi_subdevice *s;
353         int ret;
354         unsigned long iobase;
355         int i;
356
357         for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) {
358                 iobase = it->options[i];
359                 if (!iobase)
360                         break;
361         }
362         if (i == 0) {
363                 dev_warn(dev->class_dev, "no devices specified\n");
364                 return -EINVAL;
365         }
366
367         ret = comedi_alloc_subdevices(dev, i);
368         if (ret)
369                 return ret;
370
371         for (i = 0; i < dev->n_subdevices; i++) {
372                 s = &dev->subdevices[i];
373                 iobase = it->options[i];
374
375                 ret = __comedi_request_region(dev, iobase, _8255_SIZE);
376                 if (ret) {
377                         s->type = COMEDI_SUBD_UNUSED;
378                 } else {
379                         ret = subdev_8255_init(dev, s, NULL, iobase);
380                         if (ret)
381                                 return ret;
382                 }
383         }
384
385         return 0;
386 }
387
388 static void dev_8255_detach(struct comedi_device *dev)
389 {
390         struct comedi_subdevice *s;
391         struct subdev_8255_private *spriv;
392         int i;
393
394         for (i = 0; i < dev->n_subdevices; i++) {
395                 s = &dev->subdevices[i];
396                 if (s->type != COMEDI_SUBD_UNUSED) {
397                         spriv = s->private;
398                         release_region(spriv->iobase, _8255_SIZE);
399                 }
400                 subdev_8255_cleanup(dev, s);
401         }
402 }
403
404 static struct comedi_driver dev_8255_driver = {
405         .driver_name    = "8255",
406         .module         = THIS_MODULE,
407         .attach         = dev_8255_attach,
408         .detach         = dev_8255_detach,
409 };
410 module_comedi_driver(dev_8255_driver);
411
412 MODULE_AUTHOR("Comedi http://www.comedi.org");
413 MODULE_DESCRIPTION("Comedi low-level driver");
414 MODULE_LICENSE("GPL");