]>
Commit | Line | Data |
---|---|---|
1 | // SPDX-License-Identifier: GPL-2.0+ | |
2 | /* | |
3 | * comedi/drivers/jr3_pci.c | |
4 | * hardware driver for JR3/PCI force sensor board | |
5 | * | |
6 | * COMEDI - Linux Control and Measurement Device Interface | |
7 | * Copyright (C) 2007 Anders Blomdell <anders.blomdell@control.lth.se> | |
8 | */ | |
9 | /* | |
10 | * Driver: jr3_pci | |
11 | * Description: JR3/PCI force sensor board | |
12 | * Author: Anders Blomdell <anders.blomdell@control.lth.se> | |
13 | * Updated: Thu, 01 Nov 2012 17:34:55 +0000 | |
14 | * Status: works | |
15 | * Devices: [JR3] PCI force sensor board (jr3_pci) | |
16 | * | |
17 | * Configuration options: | |
18 | * None | |
19 | * | |
20 | * Manual configuration of comedi devices is not supported by this | |
21 | * driver; supported PCI devices are configured as comedi devices | |
22 | * automatically. | |
23 | * | |
24 | * The DSP on the board requires initialization code, which can be | |
25 | * loaded by placing it in /lib/firmware/comedi. The initialization | |
26 | * code should be somewhere on the media you got with your card. One | |
27 | * version is available from https://www.comedi.org in the | |
28 | * comedi_nonfree_firmware tarball. The file is called "jr3pci.idm". | |
29 | */ | |
30 | ||
31 | #include <linux/kernel.h> | |
32 | #include <linux/module.h> | |
33 | #include <linux/delay.h> | |
34 | #include <linux/ctype.h> | |
35 | #include <linux/jiffies.h> | |
36 | #include <linux/slab.h> | |
37 | #include <linux/timer.h> | |
38 | ||
39 | #include "../comedi_pci.h" | |
40 | ||
41 | #include "jr3_pci.h" | |
42 | ||
43 | #define PCI_VENDOR_ID_JR3 0x1762 | |
44 | ||
45 | enum jr3_pci_boardid { | |
46 | BOARD_JR3_1, | |
47 | BOARD_JR3_2, | |
48 | BOARD_JR3_3, | |
49 | BOARD_JR3_4, | |
50 | }; | |
51 | ||
52 | struct jr3_pci_board { | |
53 | const char *name; | |
54 | int n_subdevs; | |
55 | }; | |
56 | ||
57 | static const struct jr3_pci_board jr3_pci_boards[] = { | |
58 | [BOARD_JR3_1] = { | |
59 | .name = "jr3_pci_1", | |
60 | .n_subdevs = 1, | |
61 | }, | |
62 | [BOARD_JR3_2] = { | |
63 | .name = "jr3_pci_2", | |
64 | .n_subdevs = 2, | |
65 | }, | |
66 | [BOARD_JR3_3] = { | |
67 | .name = "jr3_pci_3", | |
68 | .n_subdevs = 3, | |
69 | }, | |
70 | [BOARD_JR3_4] = { | |
71 | .name = "jr3_pci_4", | |
72 | .n_subdevs = 4, | |
73 | }, | |
74 | }; | |
75 | ||
76 | struct jr3_pci_transform { | |
77 | struct { | |
78 | u16 link_type; | |
79 | s16 link_amount; | |
80 | } link[8]; | |
81 | }; | |
82 | ||
83 | struct jr3_pci_poll_delay { | |
84 | int min; | |
85 | int max; | |
86 | }; | |
87 | ||
88 | struct jr3_pci_dev_private { | |
89 | struct timer_list timer; | |
90 | struct comedi_device *dev; | |
91 | }; | |
92 | ||
93 | union jr3_pci_single_range { | |
94 | struct comedi_lrange l; | |
95 | char _reserved[offsetof(struct comedi_lrange, range[1])]; | |
96 | }; | |
97 | ||
98 | enum jr3_pci_poll_state { | |
99 | state_jr3_poll, | |
100 | state_jr3_init_wait_for_offset, | |
101 | state_jr3_init_transform_complete, | |
102 | state_jr3_init_set_full_scale_complete, | |
103 | state_jr3_init_use_offset_complete, | |
104 | state_jr3_done | |
105 | }; | |
106 | ||
107 | struct jr3_pci_subdev_private { | |
108 | struct jr3_sensor __iomem *sensor; | |
109 | unsigned long next_time_min; | |
110 | enum jr3_pci_poll_state state; | |
111 | int serial_no; | |
112 | int model_no; | |
113 | union jr3_pci_single_range range[9]; | |
114 | const struct comedi_lrange *range_table_list[8 * 7 + 2]; | |
115 | unsigned int maxdata_list[8 * 7 + 2]; | |
116 | u16 errors; | |
117 | int retries; | |
118 | }; | |
119 | ||
120 | static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) | |
121 | { | |
122 | struct jr3_pci_poll_delay result; | |
123 | ||
124 | result.min = min; | |
125 | result.max = max; | |
126 | return result; | |
127 | } | |
128 | ||
129 | static int is_complete(struct jr3_sensor __iomem *sensor) | |
130 | { | |
131 | return get_s16(&sensor->command_word0) == 0; | |
132 | } | |
133 | ||
134 | static void set_transforms(struct jr3_sensor __iomem *sensor, | |
135 | const struct jr3_pci_transform *transf, short num) | |
136 | { | |
137 | int i; | |
138 | ||
139 | num &= 0x000f; /* Make sure that 0 <= num <= 15 */ | |
140 | for (i = 0; i < 8; i++) { | |
141 | set_u16(&sensor->transforms[num].link[i].link_type, | |
142 | transf->link[i].link_type); | |
143 | udelay(1); | |
144 | set_s16(&sensor->transforms[num].link[i].link_amount, | |
145 | transf->link[i].link_amount); | |
146 | udelay(1); | |
147 | if (transf->link[i].link_type == end_x_form) | |
148 | break; | |
149 | } | |
150 | } | |
151 | ||
152 | static void use_transform(struct jr3_sensor __iomem *sensor, | |
153 | short transf_num) | |
154 | { | |
155 | set_s16(&sensor->command_word0, 0x0500 + (transf_num & 0x000f)); | |
156 | } | |
157 | ||
158 | static void use_offset(struct jr3_sensor __iomem *sensor, short offset_num) | |
159 | { | |
160 | set_s16(&sensor->command_word0, 0x0600 + (offset_num & 0x000f)); | |
161 | } | |
162 | ||
163 | static void set_offset(struct jr3_sensor __iomem *sensor) | |
164 | { | |
165 | set_s16(&sensor->command_word0, 0x0700); | |
166 | } | |
167 | ||
168 | struct six_axis_t { | |
169 | s16 fx; | |
170 | s16 fy; | |
171 | s16 fz; | |
172 | s16 mx; | |
173 | s16 my; | |
174 | s16 mz; | |
175 | }; | |
176 | ||
177 | static void set_full_scales(struct jr3_sensor __iomem *sensor, | |
178 | struct six_axis_t full_scale) | |
179 | { | |
180 | set_s16(&sensor->full_scale.fx, full_scale.fx); | |
181 | set_s16(&sensor->full_scale.fy, full_scale.fy); | |
182 | set_s16(&sensor->full_scale.fz, full_scale.fz); | |
183 | set_s16(&sensor->full_scale.mx, full_scale.mx); | |
184 | set_s16(&sensor->full_scale.my, full_scale.my); | |
185 | set_s16(&sensor->full_scale.mz, full_scale.mz); | |
186 | set_s16(&sensor->command_word0, 0x0a00); | |
187 | } | |
188 | ||
189 | static struct six_axis_t get_min_full_scales(struct jr3_sensor __iomem *sensor) | |
190 | { | |
191 | struct six_axis_t result; | |
192 | ||
193 | result.fx = get_s16(&sensor->min_full_scale.fx); | |
194 | result.fy = get_s16(&sensor->min_full_scale.fy); | |
195 | result.fz = get_s16(&sensor->min_full_scale.fz); | |
196 | result.mx = get_s16(&sensor->min_full_scale.mx); | |
197 | result.my = get_s16(&sensor->min_full_scale.my); | |
198 | result.mz = get_s16(&sensor->min_full_scale.mz); | |
199 | return result; | |
200 | } | |
201 | ||
202 | static struct six_axis_t get_max_full_scales(struct jr3_sensor __iomem *sensor) | |
203 | { | |
204 | struct six_axis_t result; | |
205 | ||
206 | result.fx = get_s16(&sensor->max_full_scale.fx); | |
207 | result.fy = get_s16(&sensor->max_full_scale.fy); | |
208 | result.fz = get_s16(&sensor->max_full_scale.fz); | |
209 | result.mx = get_s16(&sensor->max_full_scale.mx); | |
210 | result.my = get_s16(&sensor->max_full_scale.my); | |
211 | result.mz = get_s16(&sensor->max_full_scale.mz); | |
212 | return result; | |
213 | } | |
214 | ||
215 | static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, | |
216 | struct comedi_subdevice *s, | |
217 | unsigned int chan) | |
218 | { | |
219 | struct jr3_pci_subdev_private *spriv = s->private; | |
220 | unsigned int val = 0; | |
221 | ||
222 | if (spriv->state != state_jr3_done) | |
223 | return 0; | |
224 | ||
225 | if (chan < 56) { | |
226 | unsigned int axis = chan % 8; | |
227 | unsigned int filter = chan / 8; | |
228 | ||
229 | switch (axis) { | |
230 | case 0: | |
231 | val = get_s16(&spriv->sensor->filter[filter].fx); | |
232 | break; | |
233 | case 1: | |
234 | val = get_s16(&spriv->sensor->filter[filter].fy); | |
235 | break; | |
236 | case 2: | |
237 | val = get_s16(&spriv->sensor->filter[filter].fz); | |
238 | break; | |
239 | case 3: | |
240 | val = get_s16(&spriv->sensor->filter[filter].mx); | |
241 | break; | |
242 | case 4: | |
243 | val = get_s16(&spriv->sensor->filter[filter].my); | |
244 | break; | |
245 | case 5: | |
246 | val = get_s16(&spriv->sensor->filter[filter].mz); | |
247 | break; | |
248 | case 6: | |
249 | val = get_s16(&spriv->sensor->filter[filter].v1); | |
250 | break; | |
251 | case 7: | |
252 | val = get_s16(&spriv->sensor->filter[filter].v2); | |
253 | break; | |
254 | } | |
255 | val += 0x4000; | |
256 | } else if (chan == 56) { | |
257 | val = get_u16(&spriv->sensor->model_no); | |
258 | } else if (chan == 57) { | |
259 | val = get_u16(&spriv->sensor->serial_no); | |
260 | } | |
261 | ||
262 | return val; | |
263 | } | |
264 | ||
265 | static int jr3_pci_ai_insn_read(struct comedi_device *dev, | |
266 | struct comedi_subdevice *s, | |
267 | struct comedi_insn *insn, | |
268 | unsigned int *data) | |
269 | { | |
270 | struct jr3_pci_subdev_private *spriv = s->private; | |
271 | unsigned int chan = CR_CHAN(insn->chanspec); | |
272 | u16 errors; | |
273 | int i; | |
274 | ||
275 | errors = get_u16(&spriv->sensor->errors); | |
276 | if (spriv->state != state_jr3_done || | |
277 | (errors & (watch_dog | watch_dog2 | sensor_change))) { | |
278 | /* No sensor or sensor changed */ | |
279 | if (spriv->state == state_jr3_done) { | |
280 | /* Restart polling */ | |
281 | spriv->state = state_jr3_poll; | |
282 | } | |
283 | return -EAGAIN; | |
284 | } | |
285 | ||
286 | for (i = 0; i < insn->n; i++) | |
287 | data[i] = jr3_pci_ai_read_chan(dev, s, chan); | |
288 | ||
289 | return insn->n; | |
290 | } | |
291 | ||
292 | static int jr3_pci_open(struct comedi_device *dev) | |
293 | { | |
294 | struct jr3_pci_subdev_private *spriv; | |
295 | struct comedi_subdevice *s; | |
296 | int i; | |
297 | ||
298 | for (i = 0; i < dev->n_subdevices; i++) { | |
299 | s = &dev->subdevices[i]; | |
300 | spriv = s->private; | |
301 | dev_dbg(dev->class_dev, "serial[%d]: %d\n", s->index, | |
302 | spriv->serial_no); | |
303 | } | |
304 | return 0; | |
305 | } | |
306 | ||
307 | static int read_idm_word(const u8 *data, size_t size, int *pos, | |
308 | unsigned int *val) | |
309 | { | |
310 | int result = 0; | |
311 | int value; | |
312 | ||
313 | if (pos && val) { | |
314 | /* Skip over non hex */ | |
315 | for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) | |
316 | ; | |
317 | /* Collect value */ | |
318 | *val = 0; | |
319 | for (; *pos < size; (*pos)++) { | |
320 | value = hex_to_bin(data[*pos]); | |
321 | if (value >= 0) { | |
322 | result = 1; | |
323 | *val = (*val << 4) + value; | |
324 | } else { | |
325 | break; | |
326 | } | |
327 | } | |
328 | } | |
329 | return result; | |
330 | } | |
331 | ||
332 | static int jr3_check_firmware(struct comedi_device *dev, | |
333 | const u8 *data, size_t size) | |
334 | { | |
335 | int more = 1; | |
336 | int pos = 0; | |
337 | ||
338 | /* | |
339 | * IDM file format is: | |
340 | * { count, address, data <count> } * | |
341 | * ffff | |
342 | */ | |
343 | while (more) { | |
344 | unsigned int count = 0; | |
345 | unsigned int addr = 0; | |
346 | ||
347 | more = more && read_idm_word(data, size, &pos, &count); | |
348 | if (more && count == 0xffff) | |
349 | return 0; | |
350 | ||
351 | more = more && read_idm_word(data, size, &pos, &addr); | |
352 | while (more && count > 0) { | |
353 | unsigned int dummy = 0; | |
354 | ||
355 | more = more && read_idm_word(data, size, &pos, &dummy); | |
356 | count--; | |
357 | } | |
358 | } | |
359 | ||
360 | return -ENODATA; | |
361 | } | |
362 | ||
363 | static void jr3_write_firmware(struct comedi_device *dev, | |
364 | int subdev, const u8 *data, size_t size) | |
365 | { | |
366 | struct jr3_block __iomem *block = dev->mmio; | |
367 | u32 __iomem *lo; | |
368 | u32 __iomem *hi; | |
369 | int more = 1; | |
370 | int pos = 0; | |
371 | ||
372 | while (more) { | |
373 | unsigned int count = 0; | |
374 | unsigned int addr = 0; | |
375 | ||
376 | more = more && read_idm_word(data, size, &pos, &count); | |
377 | if (more && count == 0xffff) | |
378 | return; | |
379 | ||
380 | more = more && read_idm_word(data, size, &pos, &addr); | |
381 | ||
382 | dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", | |
383 | subdev, count, addr); | |
384 | ||
385 | while (more && count > 0) { | |
386 | if (addr & 0x4000) { | |
387 | /* 16 bit data, never seen in real life!! */ | |
388 | unsigned int data1 = 0; | |
389 | ||
390 | more = more && | |
391 | read_idm_word(data, size, &pos, &data1); | |
392 | count--; | |
393 | /* jr3[addr + 0x20000 * pnum] = data1; */ | |
394 | } else { | |
395 | /* Download 24 bit program */ | |
396 | unsigned int data1 = 0; | |
397 | unsigned int data2 = 0; | |
398 | ||
399 | lo = &block[subdev].program_lo[addr]; | |
400 | hi = &block[subdev].program_hi[addr]; | |
401 | ||
402 | more = more && | |
403 | read_idm_word(data, size, &pos, &data1); | |
404 | more = more && | |
405 | read_idm_word(data, size, &pos, &data2); | |
406 | count -= 2; | |
407 | if (more) { | |
408 | set_u16(lo, data1); | |
409 | udelay(1); | |
410 | set_u16(hi, data2); | |
411 | udelay(1); | |
412 | } | |
413 | } | |
414 | addr++; | |
415 | } | |
416 | } | |
417 | } | |
418 | ||
419 | static int jr3_download_firmware(struct comedi_device *dev, | |
420 | const u8 *data, size_t size, | |
421 | unsigned long context) | |
422 | { | |
423 | int subdev; | |
424 | int ret; | |
425 | ||
426 | /* verify IDM file format */ | |
427 | ret = jr3_check_firmware(dev, data, size); | |
428 | if (ret) | |
429 | return ret; | |
430 | ||
431 | /* write firmware to each subdevice */ | |
432 | for (subdev = 0; subdev < dev->n_subdevices; subdev++) | |
433 | jr3_write_firmware(dev, subdev, data, size); | |
434 | ||
435 | return 0; | |
436 | } | |
437 | ||
438 | static struct jr3_pci_poll_delay | |
439 | jr3_pci_poll_subdevice(struct comedi_subdevice *s) | |
440 | { | |
441 | struct jr3_pci_subdev_private *spriv = s->private; | |
442 | struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); | |
443 | struct jr3_sensor __iomem *sensor; | |
444 | u16 model_no; | |
445 | u16 serial_no; | |
446 | int errors; | |
447 | int i; | |
448 | ||
449 | sensor = spriv->sensor; | |
450 | errors = get_u16(&sensor->errors); | |
451 | ||
452 | if (errors != spriv->errors) | |
453 | spriv->errors = errors; | |
454 | ||
455 | /* Sensor communication lost? force poll mode */ | |
456 | if (errors & (watch_dog | watch_dog2 | sensor_change)) | |
457 | spriv->state = state_jr3_poll; | |
458 | ||
459 | switch (spriv->state) { | |
460 | case state_jr3_poll: | |
461 | model_no = get_u16(&sensor->model_no); | |
462 | serial_no = get_u16(&sensor->serial_no); | |
463 | ||
464 | if ((errors & (watch_dog | watch_dog2)) || | |
465 | model_no == 0 || serial_no == 0) { | |
466 | /* | |
467 | * Still no sensor, keep on polling. | |
468 | * Since it takes up to 10 seconds for offsets to | |
469 | * stabilize, polling each second should suffice. | |
470 | */ | |
471 | } else { | |
472 | spriv->retries = 0; | |
473 | spriv->state = state_jr3_init_wait_for_offset; | |
474 | } | |
475 | break; | |
476 | case state_jr3_init_wait_for_offset: | |
477 | spriv->retries++; | |
478 | if (spriv->retries < 10) { | |
479 | /* | |
480 | * Wait for offeset to stabilize | |
481 | * (< 10 s according to manual) | |
482 | */ | |
483 | } else { | |
484 | struct jr3_pci_transform transf; | |
485 | ||
486 | spriv->model_no = get_u16(&sensor->model_no); | |
487 | spriv->serial_no = get_u16(&sensor->serial_no); | |
488 | ||
489 | /* Transformation all zeros */ | |
490 | for (i = 0; i < ARRAY_SIZE(transf.link); i++) { | |
491 | transf.link[i].link_type = (enum link_types)0; | |
492 | transf.link[i].link_amount = 0; | |
493 | } | |
494 | ||
495 | set_transforms(sensor, &transf, 0); | |
496 | use_transform(sensor, 0); | |
497 | spriv->state = state_jr3_init_transform_complete; | |
498 | /* Allow 20 ms for completion */ | |
499 | result = poll_delay_min_max(20, 100); | |
500 | } | |
501 | break; | |
502 | case state_jr3_init_transform_complete: | |
503 | if (!is_complete(sensor)) { | |
504 | result = poll_delay_min_max(20, 100); | |
505 | } else { | |
506 | /* Set full scale */ | |
507 | struct six_axis_t min_full_scale; | |
508 | struct six_axis_t max_full_scale; | |
509 | ||
510 | min_full_scale = get_min_full_scales(sensor); | |
511 | max_full_scale = get_max_full_scales(sensor); | |
512 | set_full_scales(sensor, max_full_scale); | |
513 | ||
514 | spriv->state = state_jr3_init_set_full_scale_complete; | |
515 | /* Allow 20 ms for completion */ | |
516 | result = poll_delay_min_max(20, 100); | |
517 | } | |
518 | break; | |
519 | case state_jr3_init_set_full_scale_complete: | |
520 | if (!is_complete(sensor)) { | |
521 | result = poll_delay_min_max(20, 100); | |
522 | } else { | |
523 | struct force_array __iomem *fs = &sensor->full_scale; | |
524 | union jr3_pci_single_range *r = spriv->range; | |
525 | ||
526 | /* Use ranges in kN or we will overflow around 2000N! */ | |
527 | r[0].l.range[0].min = -get_s16(&fs->fx) * 1000; | |
528 | r[0].l.range[0].max = get_s16(&fs->fx) * 1000; | |
529 | r[1].l.range[0].min = -get_s16(&fs->fy) * 1000; | |
530 | r[1].l.range[0].max = get_s16(&fs->fy) * 1000; | |
531 | r[2].l.range[0].min = -get_s16(&fs->fz) * 1000; | |
532 | r[2].l.range[0].max = get_s16(&fs->fz) * 1000; | |
533 | r[3].l.range[0].min = -get_s16(&fs->mx) * 100; | |
534 | r[3].l.range[0].max = get_s16(&fs->mx) * 100; | |
535 | r[4].l.range[0].min = -get_s16(&fs->my) * 100; | |
536 | r[4].l.range[0].max = get_s16(&fs->my) * 100; | |
537 | r[5].l.range[0].min = -get_s16(&fs->mz) * 100; | |
538 | /* the next five are questionable */ | |
539 | r[5].l.range[0].max = get_s16(&fs->mz) * 100; | |
540 | r[6].l.range[0].min = -get_s16(&fs->v1) * 100; | |
541 | r[6].l.range[0].max = get_s16(&fs->v1) * 100; | |
542 | r[7].l.range[0].min = -get_s16(&fs->v2) * 100; | |
543 | r[7].l.range[0].max = get_s16(&fs->v2) * 100; | |
544 | r[8].l.range[0].min = 0; | |
545 | r[8].l.range[0].max = 65535; | |
546 | ||
547 | use_offset(sensor, 0); | |
548 | spriv->state = state_jr3_init_use_offset_complete; | |
549 | /* Allow 40 ms for completion */ | |
550 | result = poll_delay_min_max(40, 100); | |
551 | } | |
552 | break; | |
553 | case state_jr3_init_use_offset_complete: | |
554 | if (!is_complete(sensor)) { | |
555 | result = poll_delay_min_max(20, 100); | |
556 | } else { | |
557 | set_s16(&sensor->offsets.fx, 0); | |
558 | set_s16(&sensor->offsets.fy, 0); | |
559 | set_s16(&sensor->offsets.fz, 0); | |
560 | set_s16(&sensor->offsets.mx, 0); | |
561 | set_s16(&sensor->offsets.my, 0); | |
562 | set_s16(&sensor->offsets.mz, 0); | |
563 | ||
564 | set_offset(sensor); | |
565 | ||
566 | spriv->state = state_jr3_done; | |
567 | } | |
568 | break; | |
569 | case state_jr3_done: | |
570 | result = poll_delay_min_max(10000, 20000); | |
571 | break; | |
572 | default: | |
573 | break; | |
574 | } | |
575 | ||
576 | return result; | |
577 | } | |
578 | ||
579 | static void jr3_pci_poll_dev(struct timer_list *t) | |
580 | { | |
581 | struct jr3_pci_dev_private *devpriv = from_timer(devpriv, t, timer); | |
582 | struct comedi_device *dev = devpriv->dev; | |
583 | struct jr3_pci_subdev_private *spriv; | |
584 | struct comedi_subdevice *s; | |
585 | unsigned long flags; | |
586 | unsigned long now; | |
587 | int delay; | |
588 | int i; | |
589 | ||
590 | spin_lock_irqsave(&dev->spinlock, flags); | |
591 | delay = 1000; | |
592 | now = jiffies; | |
593 | ||
594 | /* Poll all sensors that are ready to be polled */ | |
595 | for (i = 0; i < dev->n_subdevices; i++) { | |
596 | s = &dev->subdevices[i]; | |
597 | spriv = s->private; | |
598 | ||
599 | if (time_after_eq(now, spriv->next_time_min)) { | |
600 | struct jr3_pci_poll_delay sub_delay; | |
601 | ||
602 | sub_delay = jr3_pci_poll_subdevice(s); | |
603 | ||
604 | spriv->next_time_min = jiffies + | |
605 | msecs_to_jiffies(sub_delay.min); | |
606 | ||
607 | if (sub_delay.max && sub_delay.max < delay) | |
608 | /* | |
609 | * Wake up as late as possible -> | |
610 | * poll as many sensors as possible at once. | |
611 | */ | |
612 | delay = sub_delay.max; | |
613 | } | |
614 | } | |
615 | spin_unlock_irqrestore(&dev->spinlock, flags); | |
616 | ||
617 | devpriv->timer.expires = jiffies + msecs_to_jiffies(delay); | |
618 | add_timer(&devpriv->timer); | |
619 | } | |
620 | ||
621 | static struct jr3_pci_subdev_private * | |
622 | jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) | |
623 | { | |
624 | struct jr3_block __iomem *block = dev->mmio; | |
625 | struct jr3_pci_subdev_private *spriv; | |
626 | int j; | |
627 | int k; | |
628 | ||
629 | spriv = comedi_alloc_spriv(s, sizeof(*spriv)); | |
630 | if (!spriv) | |
631 | return NULL; | |
632 | ||
633 | spriv->sensor = &block[s->index].sensor; | |
634 | ||
635 | for (j = 0; j < 8; j++) { | |
636 | spriv->range[j].l.length = 1; | |
637 | spriv->range[j].l.range[0].min = -1000000; | |
638 | spriv->range[j].l.range[0].max = 1000000; | |
639 | ||
640 | for (k = 0; k < 7; k++) { | |
641 | spriv->range_table_list[j + k * 8] = &spriv->range[j].l; | |
642 | spriv->maxdata_list[j + k * 8] = 0x7fff; | |
643 | } | |
644 | } | |
645 | spriv->range[8].l.length = 1; | |
646 | spriv->range[8].l.range[0].min = 0; | |
647 | spriv->range[8].l.range[0].max = 65535; | |
648 | ||
649 | spriv->range_table_list[56] = &spriv->range[8].l; | |
650 | spriv->range_table_list[57] = &spriv->range[8].l; | |
651 | spriv->maxdata_list[56] = 0xffff; | |
652 | spriv->maxdata_list[57] = 0xffff; | |
653 | ||
654 | return spriv; | |
655 | } | |
656 | ||
657 | static void jr3_pci_show_copyright(struct comedi_device *dev) | |
658 | { | |
659 | struct jr3_block __iomem *block = dev->mmio; | |
660 | struct jr3_sensor __iomem *sensor0 = &block[0].sensor; | |
661 | char copy[ARRAY_SIZE(sensor0->copyright) + 1]; | |
662 | int i; | |
663 | ||
664 | for (i = 0; i < ARRAY_SIZE(sensor0->copyright); i++) | |
665 | copy[i] = (char)(get_u16(&sensor0->copyright[i]) >> 8); | |
666 | copy[i] = '\0'; | |
667 | dev_dbg(dev->class_dev, "Firmware copyright: %s\n", copy); | |
668 | } | |
669 | ||
670 | static int jr3_pci_auto_attach(struct comedi_device *dev, | |
671 | unsigned long context) | |
672 | { | |
673 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); | |
674 | static const struct jr3_pci_board *board; | |
675 | struct jr3_pci_dev_private *devpriv; | |
676 | struct jr3_pci_subdev_private *spriv; | |
677 | struct jr3_block __iomem *block; | |
678 | struct comedi_subdevice *s; | |
679 | int ret; | |
680 | int i; | |
681 | ||
682 | BUILD_BUG_ON(sizeof(struct jr3_block) != 0x80000); | |
683 | ||
684 | if (context < ARRAY_SIZE(jr3_pci_boards)) | |
685 | board = &jr3_pci_boards[context]; | |
686 | if (!board) | |
687 | return -ENODEV; | |
688 | dev->board_ptr = board; | |
689 | dev->board_name = board->name; | |
690 | ||
691 | devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); | |
692 | if (!devpriv) | |
693 | return -ENOMEM; | |
694 | ||
695 | ret = comedi_pci_enable(dev); | |
696 | if (ret) | |
697 | return ret; | |
698 | ||
699 | if (pci_resource_len(pcidev, 0) < board->n_subdevs * sizeof(*block)) | |
700 | return -ENXIO; | |
701 | ||
702 | dev->mmio = pci_ioremap_bar(pcidev, 0); | |
703 | if (!dev->mmio) | |
704 | return -ENOMEM; | |
705 | ||
706 | block = dev->mmio; | |
707 | ||
708 | ret = comedi_alloc_subdevices(dev, board->n_subdevs); | |
709 | if (ret) | |
710 | return ret; | |
711 | ||
712 | dev->open = jr3_pci_open; | |
713 | for (i = 0; i < dev->n_subdevices; i++) { | |
714 | s = &dev->subdevices[i]; | |
715 | s->type = COMEDI_SUBD_AI; | |
716 | s->subdev_flags = SDF_READABLE | SDF_GROUND; | |
717 | s->n_chan = 8 * 7 + 2; | |
718 | s->insn_read = jr3_pci_ai_insn_read; | |
719 | ||
720 | spriv = jr3_pci_alloc_spriv(dev, s); | |
721 | if (!spriv) | |
722 | return -ENOMEM; | |
723 | ||
724 | /* Channel specific range and maxdata */ | |
725 | s->range_table_list = spriv->range_table_list; | |
726 | s->maxdata_list = spriv->maxdata_list; | |
727 | } | |
728 | ||
729 | /* Reset DSP card */ | |
730 | for (i = 0; i < dev->n_subdevices; i++) | |
731 | writel(0, &block[i].reset); | |
732 | ||
733 | ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, | |
734 | "comedi/jr3pci.idm", | |
735 | jr3_download_firmware, 0); | |
736 | dev_dbg(dev->class_dev, "Firmware load %d\n", ret); | |
737 | if (ret < 0) | |
738 | return ret; | |
739 | /* | |
740 | * TODO: use firmware to load preferred offset tables. Suggested | |
741 | * format: | |
742 | * model serial Fx Fy Fz Mx My Mz\n | |
743 | * | |
744 | * comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, | |
745 | * "comedi/jr3_offsets_table", | |
746 | * jr3_download_firmware, 1); | |
747 | */ | |
748 | ||
749 | /* | |
750 | * It takes a few milliseconds for software to settle as much as we | |
751 | * can read firmware version | |
752 | */ | |
753 | msleep_interruptible(25); | |
754 | jr3_pci_show_copyright(dev); | |
755 | ||
756 | /* Start card timer */ | |
757 | for (i = 0; i < dev->n_subdevices; i++) { | |
758 | s = &dev->subdevices[i]; | |
759 | spriv = s->private; | |
760 | ||
761 | spriv->next_time_min = jiffies + msecs_to_jiffies(500); | |
762 | } | |
763 | ||
764 | devpriv->dev = dev; | |
765 | timer_setup(&devpriv->timer, jr3_pci_poll_dev, 0); | |
766 | devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); | |
767 | add_timer(&devpriv->timer); | |
768 | ||
769 | return 0; | |
770 | } | |
771 | ||
772 | static void jr3_pci_detach(struct comedi_device *dev) | |
773 | { | |
774 | struct jr3_pci_dev_private *devpriv = dev->private; | |
775 | ||
776 | if (devpriv) | |
777 | del_timer_sync(&devpriv->timer); | |
778 | ||
779 | comedi_pci_detach(dev); | |
780 | } | |
781 | ||
782 | static struct comedi_driver jr3_pci_driver = { | |
783 | .driver_name = "jr3_pci", | |
784 | .module = THIS_MODULE, | |
785 | .auto_attach = jr3_pci_auto_attach, | |
786 | .detach = jr3_pci_detach, | |
787 | }; | |
788 | ||
789 | static int jr3_pci_pci_probe(struct pci_dev *dev, | |
790 | const struct pci_device_id *id) | |
791 | { | |
792 | return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data); | |
793 | } | |
794 | ||
795 | static const struct pci_device_id jr3_pci_pci_table[] = { | |
796 | { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, | |
797 | { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, | |
798 | { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, | |
799 | { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, | |
800 | { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, | |
801 | { 0 } | |
802 | }; | |
803 | MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); | |
804 | ||
805 | static struct pci_driver jr3_pci_pci_driver = { | |
806 | .name = "jr3_pci", | |
807 | .id_table = jr3_pci_pci_table, | |
808 | .probe = jr3_pci_pci_probe, | |
809 | .remove = comedi_pci_auto_unconfig, | |
810 | }; | |
811 | module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); | |
812 | ||
813 | MODULE_AUTHOR("Comedi https://www.comedi.org"); | |
814 | MODULE_DESCRIPTION("Comedi driver for JR3/PCI force sensor board"); | |
815 | MODULE_LICENSE("GPL"); | |
816 | MODULE_FIRMWARE("comedi/jr3pci.idm"); |