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