staging: comedi: comedi_test: simplify time since last AI scan
[deliverable/linux.git] / drivers / staging / comedi / drivers / pcm3724.c
CommitLineData
e30ec011 1/*
629af240
HS
2 * pcm3724.c
3 * Comedi driver for Advantech PCM-3724 Digital I/O board
4 *
5 * Drew Csillag <drew_csillag@yahoo.com>
6 */
e30ec011 7
e30ec011 8/*
629af240
HS
9 * Driver: pcm3724
10 * Description: Advantech PCM-3724
11 * Devices: [Advantech] PCM-3724 (pcm3724)
12 * Author: Drew Csillag <drew_csillag@yahoo.com>
13 * Status: tested
14 *
15 * This is driver for digital I/O boards PCM-3724 with 48 DIO.
16 * It needs 8255.o for operations and only immediate mode is supported.
17 * See the source for configuration details.
18 *
19 * Copy/pasted/hacked from pcm724.c
20 *
21 * Configuration Options:
22 * [0] - I/O port base address
e30ec011
DC
23 */
24
ce157f80 25#include <linux/module.h>
e30ec011
DC
26#include "../comedidev.h"
27
e30ec011
DC
28#include "8255.h"
29
5891b5b2
HS
30/*
31 * Register I/O Map
32 *
33 * This board has two standard 8255 devices that provide six 8-bit DIO ports
34 * (48 channels total). Six 74HCT245 chips (one for each port) buffer the
35 * I/O lines to increase driving capability. Because the 74HCT245 is a
36 * bidirectional, tri-state line buffer, two additional I/O ports are used
37 * to control the direction of data and the enable of each port.
38 */
39#define PCM3724_8255_0_BASE 0x00
40#define PCM3724_8255_1_BASE 0x04
41#define PCM3724_DIO_DIR_REG 0x08
42#define PCM3724_DIO_DIR_C0_OUT BIT(0)
43#define PCM3724_DIO_DIR_B0_OUT BIT(1)
44#define PCM3724_DIO_DIR_A0_OUT BIT(2)
45#define PCM3724_DIO_DIR_C1_OUT BIT(3)
46#define PCM3724_DIO_DIR_B1_OUT BIT(4)
47#define PCM3724_DIO_DIR_A1_OUT BIT(5)
48#define PCM3724_GATE_CTRL_REG 0x09
49#define PCM3724_GATE_CTRL_C0_ENA BIT(0)
50#define PCM3724_GATE_CTRL_B0_ENA BIT(1)
51#define PCM3724_GATE_CTRL_A0_ENA BIT(2)
52#define PCM3724_GATE_CTRL_C1_ENA BIT(3)
53#define PCM3724_GATE_CTRL_B1_ENA BIT(4)
54#define PCM3724_GATE_CTRL_A1_ENA BIT(5)
e30ec011 55
2696fb57 56/* used to track configured dios */
8e7b864b 57struct priv_pcm3724 {
e30ec011
DC
58 int dio_1;
59 int dio_2;
8e7b864b
BP
60};
61
da91b269 62static int compute_buffer(int config, int devno, struct comedi_subdevice *s)
e30ec011
DC
63{
64 /* 1 in io_bits indicates output */
65 if (s->io_bits & 0x0000ff) {
50ae2a52 66 if (devno == 0)
5891b5b2 67 config |= PCM3724_DIO_DIR_A0_OUT;
50ae2a52 68 else
5891b5b2 69 config |= PCM3724_DIO_DIR_A1_OUT;
e30ec011
DC
70 }
71 if (s->io_bits & 0x00ff00) {
50ae2a52 72 if (devno == 0)
5891b5b2 73 config |= PCM3724_DIO_DIR_B0_OUT;
50ae2a52 74 else
5891b5b2 75 config |= PCM3724_DIO_DIR_B1_OUT;
e30ec011
DC
76 }
77 if (s->io_bits & 0xff0000) {
50ae2a52 78 if (devno == 0)
5891b5b2 79 config |= PCM3724_DIO_DIR_C0_OUT;
50ae2a52 80 else
5891b5b2 81 config |= PCM3724_DIO_DIR_C1_OUT;
e30ec011
DC
82 }
83 return config;
84}
85
0a85b6f0
MT
86static void do_3724_config(struct comedi_device *dev,
87 struct comedi_subdevice *s, int chanspec)
e30ec011 88{
0a96639f
HS
89 struct comedi_subdevice *s_dio1 = &dev->subdevices[0];
90 struct comedi_subdevice *s_dio2 = &dev->subdevices[1];
e30ec011
DC
91 int config;
92 int buffer_config;
93 unsigned long port_8255_cfg;
94
f0162091 95 config = I8255_CTRL_CW;
e30ec011
DC
96 buffer_config = 0;
97
98 /* 1 in io_bits indicates output, 1 in config indicates input */
50ae2a52 99 if (!(s->io_bits & 0x0000ff))
f0162091 100 config |= I8255_CTRL_A_IO;
50ae2a52
BA
101
102 if (!(s->io_bits & 0x00ff00))
f0162091 103 config |= I8255_CTRL_B_IO;
50ae2a52
BA
104
105 if (!(s->io_bits & 0xff0000))
f0162091 106 config |= I8255_CTRL_C_HI_IO | I8255_CTRL_C_LO_IO;
e30ec011 107
0a96639f
HS
108 buffer_config = compute_buffer(0, 0, s_dio1);
109 buffer_config = compute_buffer(buffer_config, 1, s_dio2);
e30ec011 110
0a96639f 111 if (s == s_dio1)
f0162091 112 port_8255_cfg = dev->iobase + I8255_CTRL_REG;
50ae2a52 113 else
f0162091 114 port_8255_cfg = dev->iobase + I8255_SIZE + I8255_CTRL_REG;
50ae2a52 115
5891b5b2 116 outb(buffer_config, dev->iobase + PCM3724_DIO_DIR_REG);
50ae2a52 117
e30ec011
DC
118 outb(config, port_8255_cfg);
119}
120
0a85b6f0
MT
121static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s,
122 int chanspec)
e30ec011 123{
9a1a6cf8 124 struct priv_pcm3724 *priv = dev->private;
0a96639f 125 struct comedi_subdevice *s_dio1 = &dev->subdevices[0];
e30ec011
DC
126 unsigned int mask;
127 int gatecfg;
e30ec011
DC
128
129 gatecfg = 0;
e30ec011
DC
130
131 mask = 1 << CR_CHAN(chanspec);
0a96639f 132 if (s == s_dio1)
e30ec011 133 priv->dio_1 |= mask;
0a96639f 134 else
e30ec011 135 priv->dio_2 |= mask;
50ae2a52
BA
136
137 if (priv->dio_1 & 0xff0000)
5891b5b2 138 gatecfg |= PCM3724_GATE_CTRL_C0_ENA;
50ae2a52
BA
139
140 if (priv->dio_1 & 0xff00)
5891b5b2 141 gatecfg |= PCM3724_GATE_CTRL_B0_ENA;
50ae2a52
BA
142
143 if (priv->dio_1 & 0xff)
5891b5b2 144 gatecfg |= PCM3724_GATE_CTRL_A0_ENA;
50ae2a52
BA
145
146 if (priv->dio_2 & 0xff0000)
5891b5b2 147 gatecfg |= PCM3724_GATE_CTRL_C1_ENA;
50ae2a52
BA
148
149 if (priv->dio_2 & 0xff00)
5891b5b2 150 gatecfg |= PCM3724_GATE_CTRL_B1_ENA;
50ae2a52
BA
151
152 if (priv->dio_2 & 0xff)
5891b5b2 153 gatecfg |= PCM3724_GATE_CTRL_A1_ENA;
50ae2a52 154
5891b5b2 155 outb(gatecfg, dev->iobase + PCM3724_GATE_CTRL_REG);
e30ec011
DC
156}
157
158/* overriding the 8255 insn config */
0a85b6f0
MT
159static int subdev_3724_insn_config(struct comedi_device *dev,
160 struct comedi_subdevice *s,
5dacadcc
HS
161 struct comedi_insn *insn,
162 unsigned int *data)
e30ec011 163{
5dacadcc 164 unsigned int chan = CR_CHAN(insn->chanspec);
e30ec011 165 unsigned int mask;
5dacadcc
HS
166 int ret;
167
168 if (chan < 8)
169 mask = 0x0000ff;
170 else if (chan < 16)
171 mask = 0x00ff00;
172 else if (chan < 20)
173 mask = 0x0f0000;
50ae2a52 174 else
5dacadcc
HS
175 mask = 0xf00000;
176
177 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
178 if (ret)
179 return ret;
e30ec011
DC
180
181 do_3724_config(dev, s, insn->chanspec);
182 enable_chan(dev, s, insn->chanspec);
5dacadcc
HS
183
184 return insn->n;
e30ec011
DC
185}
186
0a85b6f0
MT
187static int pcm3724_attach(struct comedi_device *dev,
188 struct comedi_devconfig *it)
e30ec011 189{
9a1a6cf8 190 struct priv_pcm3724 *priv;
0a96639f 191 struct comedi_subdevice *s;
5f1514bf
HS
192 int ret, i;
193
0bdab509 194 priv = comedi_alloc_devpriv(dev, sizeof(*priv));
c34fa261
HS
195 if (!priv)
196 return -ENOMEM;
e30ec011 197
862755ec 198 ret = comedi_request_region(dev, it->options[0], 0x10);
011c131f
HS
199 if (ret)
200 return ret;
e30ec011 201
5f1514bf 202 ret = comedi_alloc_subdevices(dev, 2);
8b6c5694 203 if (ret)
e30ec011
DC
204 return ret;
205
206 for (i = 0; i < dev->n_subdevices; i++) {
0a96639f 207 s = &dev->subdevices[i];
f0162091 208 ret = subdev_8255_init(dev, s, NULL, i * I8255_SIZE);
e6439a45
HS
209 if (ret)
210 return ret;
0a96639f 211 s->insn_config = subdev_3724_insn_config;
273f4bef 212 }
e30ec011
DC
213 return 0;
214}
215
294f930d 216static struct comedi_driver pcm3724_driver = {
5f01bd51
HS
217 .driver_name = "pcm3724",
218 .module = THIS_MODULE,
219 .attach = pcm3724_attach,
588ba6dc 220 .detach = comedi_legacy_detach,
5f01bd51 221};
294f930d 222module_comedi_driver(pcm3724_driver);
5f01bd51 223
90f703d3 224MODULE_AUTHOR("Comedi http://www.comedi.org");
647d8aec 225MODULE_DESCRIPTION("Comedi driver for Advantech PCM-3724 Digital I/O board");
90f703d3 226MODULE_LICENSE("GPL");
This page took 1.074895 seconds and 5 git commands to generate.