This source file includes following definitions.
- ni_670x_ao_insn_write
- ni_670x_dio_insn_bits
- ni_670x_dio_insn_config
- ni_670x_mite_init
- ni_670x_auto_attach
- ni_670x_detach
- ni_670x_pci_probe
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 #include <linux/module.h>
25 #include <linux/interrupt.h>
26 #include <linux/slab.h>
27
28 #include "../comedi_pci.h"
29
30 #define AO_VALUE_OFFSET 0x00
31 #define AO_CHAN_OFFSET 0x0c
32 #define AO_STATUS_OFFSET 0x10
33 #define AO_CONTROL_OFFSET 0x10
34 #define DIO_PORT0_DIR_OFFSET 0x20
35 #define DIO_PORT0_DATA_OFFSET 0x24
36 #define DIO_PORT1_DIR_OFFSET 0x28
37 #define DIO_PORT1_DATA_OFFSET 0x2c
38 #define MISC_STATUS_OFFSET 0x14
39 #define MISC_CONTROL_OFFSET 0x14
40
41 enum ni_670x_boardid {
42 BOARD_PCI6703,
43 BOARD_PXI6704,
44 BOARD_PCI6704,
45 };
46
47 struct ni_670x_board {
48 const char *name;
49 unsigned short ao_chans;
50 };
51
52 static const struct ni_670x_board ni_670x_boards[] = {
53 [BOARD_PCI6703] = {
54 .name = "PCI-6703",
55 .ao_chans = 16,
56 },
57 [BOARD_PXI6704] = {
58 .name = "PXI-6704",
59 .ao_chans = 32,
60 },
61 [BOARD_PCI6704] = {
62 .name = "PCI-6704",
63 .ao_chans = 32,
64 },
65 };
66
67 struct ni_670x_private {
68 int boardtype;
69 int dio;
70 };
71
72 static int ni_670x_ao_insn_write(struct comedi_device *dev,
73 struct comedi_subdevice *s,
74 struct comedi_insn *insn,
75 unsigned int *data)
76 {
77 unsigned int chan = CR_CHAN(insn->chanspec);
78 unsigned int val = s->readback[chan];
79 int i;
80
81
82
83
84
85
86
87
88
89
90
91 for (i = 0; i < insn->n; i++) {
92 val = data[i];
93
94 writel(((chan & 15) << 1) | ((chan & 16) >> 4),
95 dev->mmio + AO_CHAN_OFFSET);
96
97 writel(val, dev->mmio + AO_VALUE_OFFSET);
98 }
99 s->readback[chan] = val;
100
101 return insn->n;
102 }
103
104 static int ni_670x_dio_insn_bits(struct comedi_device *dev,
105 struct comedi_subdevice *s,
106 struct comedi_insn *insn,
107 unsigned int *data)
108 {
109 if (comedi_dio_update_state(s, data))
110 writel(s->state, dev->mmio + DIO_PORT0_DATA_OFFSET);
111
112 data[1] = readl(dev->mmio + DIO_PORT0_DATA_OFFSET);
113
114 return insn->n;
115 }
116
117 static int ni_670x_dio_insn_config(struct comedi_device *dev,
118 struct comedi_subdevice *s,
119 struct comedi_insn *insn,
120 unsigned int *data)
121 {
122 int ret;
123
124 ret = comedi_dio_insn_config(dev, s, insn, data, 0);
125 if (ret)
126 return ret;
127
128 writel(s->io_bits, dev->mmio + DIO_PORT0_DIR_OFFSET);
129
130 return insn->n;
131 }
132
133
134 #define MITE_IODWBSR 0xc0
135 #define WENAB BIT(7)
136
137 static int ni_670x_mite_init(struct pci_dev *pcidev)
138 {
139 void __iomem *mite_base;
140 u32 main_phys_addr;
141
142
143 mite_base = pci_ioremap_bar(pcidev, 0);
144 if (!mite_base)
145 return -ENOMEM;
146
147
148 main_phys_addr = pci_resource_start(pcidev, 1);
149 writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR);
150
151
152 iounmap(mite_base);
153 return 0;
154 }
155
156 static int ni_670x_auto_attach(struct comedi_device *dev,
157 unsigned long context)
158 {
159 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
160 const struct ni_670x_board *board = NULL;
161 struct ni_670x_private *devpriv;
162 struct comedi_subdevice *s;
163 int ret;
164 int i;
165
166 if (context < ARRAY_SIZE(ni_670x_boards))
167 board = &ni_670x_boards[context];
168 if (!board)
169 return -ENODEV;
170 dev->board_ptr = board;
171 dev->board_name = board->name;
172
173 ret = comedi_pci_enable(dev);
174 if (ret)
175 return ret;
176
177 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
178 if (!devpriv)
179 return -ENOMEM;
180
181 ret = ni_670x_mite_init(pcidev);
182 if (ret)
183 return ret;
184
185 dev->mmio = pci_ioremap_bar(pcidev, 1);
186 if (!dev->mmio)
187 return -ENOMEM;
188
189 ret = comedi_alloc_subdevices(dev, 2);
190 if (ret)
191 return ret;
192
193 s = &dev->subdevices[0];
194
195 s->type = COMEDI_SUBD_AO;
196 s->subdev_flags = SDF_WRITABLE;
197 s->n_chan = board->ao_chans;
198 s->maxdata = 0xffff;
199 if (s->n_chan == 32) {
200 const struct comedi_lrange **range_table_list;
201
202 range_table_list = kmalloc_array(32,
203 sizeof(struct comedi_lrange *),
204 GFP_KERNEL);
205 if (!range_table_list)
206 return -ENOMEM;
207 s->range_table_list = range_table_list;
208 for (i = 0; i < 16; i++) {
209 range_table_list[i] = &range_bipolar10;
210 range_table_list[16 + i] = &range_0_20mA;
211 }
212 } else {
213 s->range_table = &range_bipolar10;
214 }
215 s->insn_write = ni_670x_ao_insn_write;
216
217 ret = comedi_alloc_subdev_readback(s);
218 if (ret)
219 return ret;
220
221 s = &dev->subdevices[1];
222
223 s->type = COMEDI_SUBD_DIO;
224 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
225 s->n_chan = 8;
226 s->maxdata = 1;
227 s->range_table = &range_digital;
228 s->insn_bits = ni_670x_dio_insn_bits;
229 s->insn_config = ni_670x_dio_insn_config;
230
231
232 writel(0x10, dev->mmio + MISC_CONTROL_OFFSET);
233
234 writel(0x00, dev->mmio + AO_CONTROL_OFFSET);
235
236 return 0;
237 }
238
239 static void ni_670x_detach(struct comedi_device *dev)
240 {
241 struct comedi_subdevice *s;
242
243 comedi_pci_detach(dev);
244 if (dev->n_subdevices) {
245 s = &dev->subdevices[0];
246 if (s)
247 kfree(s->range_table_list);
248 }
249 }
250
251 static struct comedi_driver ni_670x_driver = {
252 .driver_name = "ni_670x",
253 .module = THIS_MODULE,
254 .auto_attach = ni_670x_auto_attach,
255 .detach = ni_670x_detach,
256 };
257
258 static int ni_670x_pci_probe(struct pci_dev *dev,
259 const struct pci_device_id *id)
260 {
261 return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data);
262 }
263
264 static const struct pci_device_id ni_670x_pci_table[] = {
265 { PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 },
266 { PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 },
267 { PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 },
268 { 0 }
269 };
270 MODULE_DEVICE_TABLE(pci, ni_670x_pci_table);
271
272 static struct pci_driver ni_670x_pci_driver = {
273 .name = "ni_670x",
274 .id_table = ni_670x_pci_table,
275 .probe = ni_670x_pci_probe,
276 .remove = comedi_pci_auto_unconfig,
277 };
278 module_comedi_pci_driver(ni_670x_driver, ni_670x_pci_driver);
279
280 MODULE_AUTHOR("Comedi http://www.comedi.org");
281 MODULE_DESCRIPTION("Comedi low-level driver");
282 MODULE_LICENSE("GPL");