| 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(usec: 1); |
| 143 | set_s16(p: &sensor->transforms[num].link[i].link_amount, |
| 144 | val: transf->link[i].link_amount); |
| 145 | udelay(usec: 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(usec: 1); |
| 396 | set_u16(p: hi, val: data2); |
| 397 | udelay(usec: 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 = timer_container_of(devpriv, t, |
| 566 | timer); |
| 567 | struct comedi_device *dev = devpriv->dev; |
| 568 | struct jr3_pci_subdev_private *spriv; |
| 569 | struct comedi_subdevice *s; |
| 570 | unsigned long flags; |
| 571 | unsigned long now; |
| 572 | int delay; |
| 573 | int i; |
| 574 | |
| 575 | spin_lock_irqsave(&dev->spinlock, flags); |
| 576 | delay = 1000; |
| 577 | now = jiffies; |
| 578 | |
| 579 | /* Poll all sensors that are ready to be polled */ |
| 580 | for (i = 0; i < dev->n_subdevices; i++) { |
| 581 | s = &dev->subdevices[i]; |
| 582 | spriv = s->private; |
| 583 | |
| 584 | if (time_after_eq(now, spriv->next_time_min)) { |
| 585 | struct jr3_pci_poll_delay sub_delay; |
| 586 | |
| 587 | sub_delay = jr3_pci_poll_subdevice(s); |
| 588 | |
| 589 | spriv->next_time_min = jiffies + |
| 590 | msecs_to_jiffies(m: sub_delay.min); |
| 591 | |
| 592 | if (sub_delay.max && sub_delay.max < delay) |
| 593 | /* |
| 594 | * Wake up as late as possible -> |
| 595 | * poll as many sensors as possible at once. |
| 596 | */ |
| 597 | delay = sub_delay.max; |
| 598 | } |
| 599 | } |
| 600 | spin_unlock_irqrestore(lock: &dev->spinlock, flags); |
| 601 | |
| 602 | devpriv->timer.expires = jiffies + msecs_to_jiffies(m: delay); |
| 603 | add_timer(timer: &devpriv->timer); |
| 604 | } |
| 605 | |
| 606 | static struct jr3_pci_subdev_private * |
| 607 | jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) |
| 608 | { |
| 609 | struct jr3_block __iomem *block = dev->mmio; |
| 610 | struct jr3_pci_subdev_private *spriv; |
| 611 | int j; |
| 612 | int k; |
| 613 | |
| 614 | spriv = comedi_alloc_spriv(s, size: sizeof(*spriv)); |
| 615 | if (!spriv) |
| 616 | return NULL; |
| 617 | |
| 618 | spriv->sensor = &block[s->index].sensor; |
| 619 | |
| 620 | for (j = 0; j < 8; j++) { |
| 621 | spriv->range[j].l.length = 1; |
| 622 | spriv->range[j].l.range[0].min = -1000000; |
| 623 | spriv->range[j].l.range[0].max = 1000000; |
| 624 | |
| 625 | for (k = 0; k < 7; k++) { |
| 626 | spriv->range_table_list[j + k * 8] = &spriv->range[j].l; |
| 627 | spriv->maxdata_list[j + k * 8] = 0x7fff; |
| 628 | } |
| 629 | } |
| 630 | spriv->range[8].l.length = 1; |
| 631 | spriv->range[8].l.range[0].min = 0; |
| 632 | spriv->range[8].l.range[0].max = 65535; |
| 633 | |
| 634 | spriv->range_table_list[56] = &spriv->range[8].l; |
| 635 | spriv->range_table_list[57] = &spriv->range[8].l; |
| 636 | spriv->maxdata_list[56] = 0xffff; |
| 637 | spriv->maxdata_list[57] = 0xffff; |
| 638 | |
| 639 | return spriv; |
| 640 | } |
| 641 | |
| 642 | static void jr3_pci_show_copyright(struct comedi_device *dev) |
| 643 | { |
| 644 | struct jr3_block __iomem *block = dev->mmio; |
| 645 | struct jr3_sensor __iomem *sensor0 = &block[0].sensor; |
| 646 | char copy[ARRAY_SIZE(sensor0->copyright) + 1]; |
| 647 | int i; |
| 648 | |
| 649 | for (i = 0; i < ARRAY_SIZE(sensor0->copyright); i++) |
| 650 | copy[i] = (char)(get_u16(p: &sensor0->copyright[i]) >> 8); |
| 651 | copy[i] = '\0'; |
| 652 | dev_dbg(dev->class_dev, "Firmware copyright: %s\n" , copy); |
| 653 | } |
| 654 | |
| 655 | static int jr3_pci_auto_attach(struct comedi_device *dev, |
| 656 | unsigned long context) |
| 657 | { |
| 658 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
| 659 | static const struct jr3_pci_board *board; |
| 660 | struct jr3_pci_dev_private *devpriv; |
| 661 | struct jr3_pci_subdev_private *spriv; |
| 662 | struct jr3_block __iomem *block; |
| 663 | struct comedi_subdevice *s; |
| 664 | int ret; |
| 665 | int i; |
| 666 | |
| 667 | BUILD_BUG_ON(sizeof(struct jr3_block) != 0x80000); |
| 668 | |
| 669 | if (context < ARRAY_SIZE(jr3_pci_boards)) |
| 670 | board = &jr3_pci_boards[context]; |
| 671 | if (!board) |
| 672 | return -ENODEV; |
| 673 | dev->board_ptr = board; |
| 674 | dev->board_name = board->name; |
| 675 | |
| 676 | devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv)); |
| 677 | if (!devpriv) |
| 678 | return -ENOMEM; |
| 679 | |
| 680 | ret = comedi_pci_enable(dev); |
| 681 | if (ret) |
| 682 | return ret; |
| 683 | |
| 684 | if (pci_resource_len(pcidev, 0) < board->n_subdevs * sizeof(*block)) |
| 685 | return -ENXIO; |
| 686 | |
| 687 | dev->mmio = pci_ioremap_bar(pdev: pcidev, bar: 0); |
| 688 | if (!dev->mmio) |
| 689 | return -ENOMEM; |
| 690 | |
| 691 | block = dev->mmio; |
| 692 | |
| 693 | ret = comedi_alloc_subdevices(dev, num_subdevices: board->n_subdevs); |
| 694 | if (ret) |
| 695 | return ret; |
| 696 | |
| 697 | dev->open = jr3_pci_open; |
| 698 | for (i = 0; i < dev->n_subdevices; i++) { |
| 699 | s = &dev->subdevices[i]; |
| 700 | s->type = COMEDI_SUBD_AI; |
| 701 | s->subdev_flags = SDF_READABLE | SDF_GROUND; |
| 702 | s->n_chan = 8 * 7 + 2; |
| 703 | s->insn_read = jr3_pci_ai_insn_read; |
| 704 | |
| 705 | spriv = jr3_pci_alloc_spriv(dev, s); |
| 706 | if (!spriv) |
| 707 | return -ENOMEM; |
| 708 | |
| 709 | /* Channel specific range and maxdata */ |
| 710 | s->range_table_list = spriv->range_table_list; |
| 711 | s->maxdata_list = spriv->maxdata_list; |
| 712 | } |
| 713 | |
| 714 | /* Reset DSP card */ |
| 715 | for (i = 0; i < dev->n_subdevices; i++) |
| 716 | writel(val: 0, addr: &block[i].reset); |
| 717 | |
| 718 | ret = comedi_load_firmware(dev, hw_dev: &comedi_to_pci_dev(dev)->dev, |
| 719 | name: "comedi/jr3pci.idm" , |
| 720 | cb: jr3_download_firmware, context: 0); |
| 721 | dev_dbg(dev->class_dev, "Firmware load %d\n" , ret); |
| 722 | if (ret < 0) |
| 723 | return ret; |
| 724 | /* |
| 725 | * TODO: use firmware to load preferred offset tables. Suggested |
| 726 | * format: |
| 727 | * model serial Fx Fy Fz Mx My Mz\n |
| 728 | * |
| 729 | * comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, |
| 730 | * "comedi/jr3_offsets_table", |
| 731 | * jr3_download_firmware, 1); |
| 732 | */ |
| 733 | |
| 734 | /* |
| 735 | * It takes a few milliseconds for software to settle as much as we |
| 736 | * can read firmware version |
| 737 | */ |
| 738 | msleep_interruptible(msecs: 25); |
| 739 | jr3_pci_show_copyright(dev); |
| 740 | |
| 741 | /* Start card timer */ |
| 742 | for (i = 0; i < dev->n_subdevices; i++) { |
| 743 | s = &dev->subdevices[i]; |
| 744 | spriv = s->private; |
| 745 | |
| 746 | spriv->next_time_min = jiffies + msecs_to_jiffies(m: 500); |
| 747 | } |
| 748 | |
| 749 | devpriv->dev = dev; |
| 750 | timer_setup(&devpriv->timer, jr3_pci_poll_dev, 0); |
| 751 | devpriv->timer.expires = jiffies + msecs_to_jiffies(m: 1000); |
| 752 | add_timer(timer: &devpriv->timer); |
| 753 | |
| 754 | return 0; |
| 755 | } |
| 756 | |
| 757 | static void jr3_pci_detach(struct comedi_device *dev) |
| 758 | { |
| 759 | struct jr3_pci_dev_private *devpriv = dev->private; |
| 760 | |
| 761 | if (devpriv) |
| 762 | timer_shutdown_sync(timer: &devpriv->timer); |
| 763 | |
| 764 | comedi_pci_detach(dev); |
| 765 | } |
| 766 | |
| 767 | static struct comedi_driver jr3_pci_driver = { |
| 768 | .driver_name = "jr3_pci" , |
| 769 | .module = THIS_MODULE, |
| 770 | .auto_attach = jr3_pci_auto_attach, |
| 771 | .detach = jr3_pci_detach, |
| 772 | }; |
| 773 | |
| 774 | static int jr3_pci_pci_probe(struct pci_dev *dev, |
| 775 | const struct pci_device_id *id) |
| 776 | { |
| 777 | return comedi_pci_auto_config(pcidev: dev, driver: &jr3_pci_driver, context: id->driver_data); |
| 778 | } |
| 779 | |
| 780 | static const struct pci_device_id jr3_pci_pci_table[] = { |
| 781 | { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, |
| 782 | { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, |
| 783 | { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, |
| 784 | { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, |
| 785 | { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, |
| 786 | { 0 } |
| 787 | }; |
| 788 | MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); |
| 789 | |
| 790 | static struct pci_driver jr3_pci_pci_driver = { |
| 791 | .name = "jr3_pci" , |
| 792 | .id_table = jr3_pci_pci_table, |
| 793 | .probe = jr3_pci_pci_probe, |
| 794 | .remove = comedi_pci_auto_unconfig, |
| 795 | }; |
| 796 | module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); |
| 797 | |
| 798 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
| 799 | MODULE_DESCRIPTION("Comedi driver for JR3/PCI force sensor board" ); |
| 800 | MODULE_LICENSE("GPL" ); |
| 801 | MODULE_FIRMWARE("comedi/jr3pci.idm" ); |
| 802 | |