.. | .. |
---|
44 | 44 | /* dw9800w device structure */ |
---|
45 | 45 | struct dw9800w_device { |
---|
46 | 46 | struct v4l2_ctrl_handler ctrls_vcm; |
---|
| 47 | + struct v4l2_ctrl *focus; |
---|
47 | 48 | struct i2c_client *client; |
---|
48 | 49 | struct v4l2_subdev sd; |
---|
49 | 50 | struct v4l2_device vdev; |
---|
.. | .. |
---|
52 | 53 | struct gpio_desc *power_gpio; |
---|
53 | 54 | unsigned short current_related_pos; |
---|
54 | 55 | unsigned short current_lens_pos; |
---|
| 56 | + unsigned int max_current; |
---|
55 | 57 | unsigned int start_current; |
---|
56 | 58 | unsigned int rated_current; |
---|
57 | | - unsigned int step; |
---|
58 | 59 | unsigned int step_mode; |
---|
59 | 60 | unsigned int vcm_movefull_t; |
---|
60 | 61 | unsigned int t_src; |
---|
61 | 62 | unsigned int t_div; |
---|
| 63 | + unsigned int max_logicalpos; |
---|
62 | 64 | |
---|
63 | 65 | struct __kernel_old_timeval start_move_tv; |
---|
64 | 66 | struct __kernel_old_timeval end_move_tv; |
---|
.. | .. |
---|
67 | 69 | u32 module_index; |
---|
68 | 70 | const char *module_facing; |
---|
69 | 71 | struct rk_cam_vcm_cfg vcm_cfg; |
---|
70 | | - int max_ma; |
---|
71 | 72 | struct mutex lock; |
---|
72 | 73 | }; |
---|
73 | 74 | |
---|
.. | .. |
---|
217 | 218 | unsigned int *cur_pos) |
---|
218 | 219 | { |
---|
219 | 220 | struct i2c_client *client = dev_vcm->client; |
---|
| 221 | + unsigned int dac, position, range; |
---|
220 | 222 | int ret; |
---|
221 | | - unsigned int abs_step; |
---|
222 | 223 | |
---|
223 | | - ret = dw9800w_read_reg(client, 0x03, 2, &abs_step); |
---|
| 224 | + range = dev_vcm->rated_current - dev_vcm->start_current; |
---|
| 225 | + ret = dw9800w_read_reg(client, 0x03, 2, &dac); |
---|
224 | 226 | if (ret != 0) |
---|
225 | 227 | goto err; |
---|
226 | 228 | |
---|
227 | | - if (abs_step <= dev_vcm->start_current) |
---|
228 | | - abs_step = VCMDRV_MAX_LOG; |
---|
229 | | - else if ((abs_step > dev_vcm->start_current) && |
---|
230 | | - (abs_step <= dev_vcm->rated_current)) |
---|
231 | | - abs_step = (dev_vcm->rated_current - abs_step) / dev_vcm->step; |
---|
232 | | - else |
---|
233 | | - abs_step = 0; |
---|
| 229 | + if (dac <= dev_vcm->start_current) { |
---|
| 230 | + position = dev_vcm->max_logicalpos; |
---|
| 231 | + } else if ((dac > dev_vcm->start_current) && |
---|
| 232 | + (dac <= dev_vcm->rated_current)) { |
---|
| 233 | + position = (dac - dev_vcm->start_current) * dev_vcm->max_logicalpos / range; |
---|
| 234 | + position = dev_vcm->max_logicalpos - position; |
---|
| 235 | + } else { |
---|
| 236 | + position = 0; |
---|
| 237 | + } |
---|
234 | 238 | |
---|
235 | | - *cur_pos = abs_step; |
---|
| 239 | + *cur_pos = position; |
---|
236 | 240 | dev_dbg(&client->dev, "%s: get position %d\n", __func__, *cur_pos); |
---|
237 | 241 | return 0; |
---|
238 | 242 | |
---|
.. | .. |
---|
245 | 249 | static int dw9800w_set_pos(struct dw9800w_device *dev_vcm, |
---|
246 | 250 | unsigned int dest_pos) |
---|
247 | 251 | { |
---|
248 | | - int ret; |
---|
249 | | - unsigned int position = 0; |
---|
250 | | - struct i2c_client *client = dev_vcm->client; |
---|
| 252 | + struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); |
---|
| 253 | + unsigned int position; |
---|
| 254 | + unsigned int range; |
---|
251 | 255 | u32 is_busy, i; |
---|
| 256 | + int ret; |
---|
252 | 257 | |
---|
253 | | - if (dest_pos >= VCMDRV_MAX_LOG) |
---|
| 258 | + range = dev_vcm->rated_current - dev_vcm->start_current; |
---|
| 259 | + if (dest_pos >= dev_vcm->max_logicalpos) |
---|
254 | 260 | position = dev_vcm->start_current; |
---|
255 | 261 | else |
---|
256 | 262 | position = dev_vcm->start_current + |
---|
257 | | - (dev_vcm->step * (VCMDRV_MAX_LOG - dest_pos)); |
---|
| 263 | + (range * (dev_vcm->max_logicalpos - dest_pos) / dev_vcm->max_logicalpos); |
---|
258 | 264 | |
---|
259 | 265 | if (position > DW9800W_MAX_REG) |
---|
260 | 266 | position = DW9800W_MAX_REG; |
---|
.. | .. |
---|
304 | 310 | |
---|
305 | 311 | if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { |
---|
306 | 312 | |
---|
307 | | - if (dest_pos > VCMDRV_MAX_LOG) { |
---|
| 313 | + if (dest_pos > dev_vcm->max_logicalpos) { |
---|
308 | 314 | dev_info(&client->dev, |
---|
309 | 315 | "%s dest_pos is error. %d > %d\n", |
---|
310 | | - __func__, dest_pos, VCMDRV_MAX_LOG); |
---|
| 316 | + __func__, dest_pos, dev_vcm->max_logicalpos); |
---|
311 | 317 | return -EINVAL; |
---|
312 | 318 | } |
---|
313 | 319 | /* calculate move time */ |
---|
.. | .. |
---|
318 | 324 | ret = dw9800w_set_pos(dev_vcm, dest_pos); |
---|
319 | 325 | if (dev_vcm->step_mode == LSC_MODE) |
---|
320 | 326 | dev_vcm->move_us = ((dev_vcm->vcm_movefull_t * (uint32_t)move_pos) / |
---|
321 | | - VCMDRV_MAX_LOG); |
---|
| 327 | + dev_vcm->max_logicalpos); |
---|
322 | 328 | else |
---|
323 | 329 | dev_vcm->move_us = dev_vcm->vcm_movefull_t; |
---|
324 | 330 | |
---|
.. | .. |
---|
376 | 382 | static void dw9800w_update_vcm_cfg(struct dw9800w_device *dev_vcm) |
---|
377 | 383 | { |
---|
378 | 384 | struct i2c_client *client = dev_vcm->client; |
---|
379 | | - int cur_dist; |
---|
380 | 385 | |
---|
381 | | - if (dev_vcm->max_ma == 0) { |
---|
| 386 | + if (dev_vcm->max_current == 0) { |
---|
382 | 387 | dev_err(&client->dev, "max current is zero"); |
---|
383 | 388 | return; |
---|
384 | 389 | } |
---|
385 | 390 | |
---|
386 | | - cur_dist = dev_vcm->vcm_cfg.rated_ma - dev_vcm->vcm_cfg.start_ma; |
---|
387 | | - cur_dist = cur_dist * DW9800W_MAX_REG / dev_vcm->max_ma; |
---|
388 | | - dev_vcm->step = (cur_dist + (VCMDRV_MAX_LOG - 1)) / VCMDRV_MAX_LOG; |
---|
| 391 | + if (dev_vcm->vcm_cfg.rated_ma > dev_vcm->max_current) |
---|
| 392 | + dev_vcm->max_current = DW9800W_MAX_REG; |
---|
| 393 | + |
---|
389 | 394 | dev_vcm->start_current = dev_vcm->vcm_cfg.start_ma * |
---|
390 | | - DW9800W_MAX_REG / dev_vcm->max_ma; |
---|
| 395 | + DW9800W_MAX_REG / dev_vcm->max_current; |
---|
391 | 396 | dev_vcm->rated_current = dev_vcm->vcm_cfg.rated_ma * |
---|
392 | | - DW9800W_MAX_REG / dev_vcm->max_ma; |
---|
| 397 | + DW9800W_MAX_REG / dev_vcm->max_current; |
---|
393 | 398 | dev_vcm->step_mode = dev_vcm->vcm_cfg.step_mode; |
---|
394 | 399 | |
---|
395 | 400 | dev_info(&client->dev, |
---|
396 | | - "vcm_cfg: %d, %d, %d, max_ma %d\n", |
---|
| 401 | + "vcm_cfg: %d, %d, %d, max_current %d\n", |
---|
397 | 402 | dev_vcm->vcm_cfg.start_ma, |
---|
398 | 403 | dev_vcm->vcm_cfg.rated_ma, |
---|
399 | 404 | dev_vcm->vcm_cfg.step_mode, |
---|
400 | | - dev_vcm->max_ma); |
---|
| 405 | + dev_vcm->max_current); |
---|
401 | 406 | } |
---|
402 | 407 | |
---|
403 | 408 | static long dw9800w_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
---|
.. | .. |
---|
406 | 411 | struct i2c_client *client = dev_vcm->client; |
---|
407 | 412 | struct rk_cam_vcm_tim *vcm_tim; |
---|
408 | 413 | struct rk_cam_vcm_cfg *vcm_cfg; |
---|
| 414 | + unsigned int max_logicalpos; |
---|
409 | 415 | int ret = 0; |
---|
410 | 416 | |
---|
411 | 417 | if (cmd == RK_VIDIOC_VCM_TIMEINFO) { |
---|
.. | .. |
---|
441 | 447 | dev_vcm->vcm_cfg.rated_ma = vcm_cfg->rated_ma; |
---|
442 | 448 | dev_vcm->vcm_cfg.step_mode = vcm_cfg->step_mode; |
---|
443 | 449 | dw9800w_update_vcm_cfg(dev_vcm); |
---|
| 450 | + } else if (cmd == RK_VIDIOC_SET_VCM_MAX_LOGICALPOS) { |
---|
| 451 | + max_logicalpos = *(unsigned int *)arg; |
---|
| 452 | + |
---|
| 453 | + if (max_logicalpos > 0) { |
---|
| 454 | + dev_vcm->max_logicalpos = max_logicalpos; |
---|
| 455 | + __v4l2_ctrl_modify_range(dev_vcm->focus, |
---|
| 456 | + 0, dev_vcm->max_logicalpos, 1, dev_vcm->max_logicalpos); |
---|
| 457 | + } |
---|
| 458 | + dev_dbg(&client->dev, |
---|
| 459 | + "max_logicalpos %d\n", max_logicalpos); |
---|
444 | 460 | } else { |
---|
445 | 461 | dev_err(&client->dev, |
---|
446 | 462 | "cmd 0x%x not supported\n", cmd); |
---|
.. | .. |
---|
460 | 476 | struct rk_cam_compat_vcm_tim compat_vcm_tim; |
---|
461 | 477 | struct rk_cam_vcm_tim vcm_tim; |
---|
462 | 478 | struct rk_cam_vcm_cfg vcm_cfg; |
---|
| 479 | + unsigned int max_logicalpos; |
---|
463 | 480 | long ret; |
---|
464 | 481 | |
---|
465 | 482 | if (cmd == RK_VIDIOC_COMPAT_VCM_TIMEINFO) { |
---|
.. | .. |
---|
490 | 507 | ret = copy_from_user(&vcm_cfg, up, sizeof(vcm_cfg)); |
---|
491 | 508 | if (!ret) |
---|
492 | 509 | ret = dw9800w_ioctl(sd, cmd, &vcm_cfg); |
---|
| 510 | + else |
---|
| 511 | + ret = -EFAULT; |
---|
| 512 | + } else if (cmd == RK_VIDIOC_SET_VCM_MAX_LOGICALPOS) { |
---|
| 513 | + ret = copy_from_user(&max_logicalpos, up, sizeof(max_logicalpos)); |
---|
| 514 | + if (!ret) |
---|
| 515 | + ret = dw9800w_ioctl(sd, cmd, &max_logicalpos); |
---|
493 | 516 | else |
---|
494 | 517 | ret = -EFAULT; |
---|
495 | 518 | } else { |
---|
.. | .. |
---|
528 | 551 | |
---|
529 | 552 | v4l2_ctrl_handler_init(hdl, 1); |
---|
530 | 553 | |
---|
531 | | - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, |
---|
532 | | - 0, VCMDRV_MAX_LOG, 1, 32); |
---|
| 554 | + dev_vcm->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, |
---|
| 555 | + 0, dev_vcm->max_logicalpos, 1, |
---|
| 556 | + dev_vcm->max_logicalpos / 2); |
---|
533 | 557 | |
---|
534 | 558 | if (hdl->error) |
---|
535 | 559 | dev_err(dev_vcm->sd.dev, "%s fail error: 0x%x\n", |
---|
.. | .. |
---|
585 | 609 | { |
---|
586 | 610 | struct device_node *np = of_node_get(client->dev.of_node); |
---|
587 | 611 | struct dw9800w_device *dw9800w_dev; |
---|
588 | | - unsigned int max_ma, start_ma, rated_ma, step_mode; |
---|
| 612 | + unsigned int max_current, start_ma, rated_ma, step_mode; |
---|
589 | 613 | unsigned int t_src, t_div; |
---|
590 | 614 | struct v4l2_subdev *sd; |
---|
591 | 615 | char facing[2]; |
---|
.. | .. |
---|
594 | 618 | dev_info(&client->dev, "probing...\n"); |
---|
595 | 619 | if (of_property_read_u32(np, |
---|
596 | 620 | OF_CAMERA_VCMDRV_MAX_CURRENT, |
---|
597 | | - (unsigned int *)&max_ma)) { |
---|
598 | | - max_ma = DW9800W_MAX_CURRENT; |
---|
| 621 | + (unsigned int *)&max_current)) { |
---|
| 622 | + max_current = DW9800W_MAX_CURRENT; |
---|
599 | 623 | dev_info(&client->dev, |
---|
600 | 624 | "could not get module %s from dts!\n", |
---|
601 | 625 | OF_CAMERA_VCMDRV_MAX_CURRENT); |
---|
602 | 626 | } |
---|
603 | | - if (max_ma == 0) |
---|
604 | | - max_ma = DW9800W_MAX_CURRENT; |
---|
| 627 | + if (max_current == 0) |
---|
| 628 | + max_current = DW9800W_MAX_CURRENT; |
---|
605 | 629 | |
---|
606 | 630 | if (of_property_read_u32(np, |
---|
607 | 631 | OF_CAMERA_VCMDRV_START_CURRENT, |
---|
.. | .. |
---|
680 | 704 | dw9800w_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
---|
681 | 705 | dw9800w_dev->sd.internal_ops = &dw9800w_int_ops; |
---|
682 | 706 | |
---|
| 707 | + dw9800w_dev->max_logicalpos = VCMDRV_MAX_LOG; |
---|
683 | 708 | ret = dw9800w_init_controls(dw9800w_dev); |
---|
684 | 709 | if (ret) |
---|
685 | 710 | goto err_cleanup; |
---|
.. | .. |
---|
704 | 729 | if (ret) |
---|
705 | 730 | dev_err(&client->dev, "v4l2 async register subdev failed\n"); |
---|
706 | 731 | |
---|
707 | | - dw9800w_dev->max_ma = max_ma; |
---|
| 732 | + dw9800w_dev->max_current = max_current; |
---|
708 | 733 | dw9800w_dev->vcm_cfg.start_ma = start_ma; |
---|
709 | 734 | dw9800w_dev->vcm_cfg.rated_ma = rated_ma; |
---|
710 | 735 | dw9800w_dev->vcm_cfg.step_mode = step_mode; |
---|
711 | 736 | dw9800w_update_vcm_cfg(dw9800w_dev); |
---|
712 | 737 | dw9800w_dev->move_us = 0; |
---|
713 | | - dw9800w_dev->current_related_pos = VCMDRV_MAX_LOG; |
---|
| 738 | + dw9800w_dev->current_related_pos = dw9800w_dev->max_logicalpos; |
---|
714 | 739 | dw9800w_dev->start_move_tv = ns_to_kernel_old_timeval(ktime_get_ns()); |
---|
715 | 740 | dw9800w_dev->end_move_tv = ns_to_kernel_old_timeval(ktime_get_ns()); |
---|
716 | 741 | |
---|