.. | .. |
---|
15 | 15 | #include <media/v4l2-device.h> |
---|
16 | 16 | #include <linux/rk_vcm_head.h> |
---|
17 | 17 | #include <linux/compat.h> |
---|
| 18 | +#include <linux/regulator/consumer.h> |
---|
18 | 19 | |
---|
19 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) |
---|
| 20 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x1) |
---|
20 | 21 | #define DW9763_NAME "dw9763" |
---|
21 | 22 | |
---|
22 | 23 | #define DW9763_MAX_CURRENT 120U |
---|
23 | 24 | #define DW9763_MAX_REG 1023U |
---|
| 25 | +#define DW9763_GRADUAL_MOVELENS_STEPS 32 |
---|
24 | 26 | |
---|
25 | 27 | #define DW9763_DEFAULT_START_CURRENT 20 |
---|
26 | 28 | #define DW9763_DEFAULT_RATED_CURRENT 90 |
---|
.. | .. |
---|
40 | 42 | SAC4_MODE = 5, |
---|
41 | 43 | DIRECT_MODE, |
---|
42 | 44 | }; |
---|
| 45 | + |
---|
| 46 | +static int debug; |
---|
| 47 | +module_param(debug, int, 0644); |
---|
| 48 | +MODULE_PARM_DESC(debug, "debug level (0-2)"); |
---|
43 | 49 | |
---|
44 | 50 | /* dw9763 device structure */ |
---|
45 | 51 | struct dw9763_device { |
---|
.. | .. |
---|
69 | 75 | struct rk_cam_vcm_cfg vcm_cfg; |
---|
70 | 76 | int max_ma; |
---|
71 | 77 | struct mutex lock; |
---|
| 78 | + struct regulator *supply; |
---|
| 79 | + bool power_on; |
---|
72 | 80 | }; |
---|
73 | 81 | |
---|
74 | 82 | static inline struct dw9763_device *to_dw9763_vcm(struct v4l2_ctrl *ctrl) |
---|
.. | .. |
---|
88 | 96 | u8 buf[5]; |
---|
89 | 97 | u8 *val_p; |
---|
90 | 98 | __be32 val_be; |
---|
| 99 | + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); |
---|
91 | 100 | |
---|
92 | 101 | if (len > 4) |
---|
93 | 102 | return -EINVAL; |
---|
.. | .. |
---|
106 | 115 | dev_err(&client->dev, "Failed to write 0x%04x,0x%x\n", reg, val); |
---|
107 | 116 | return -EIO; |
---|
108 | 117 | } |
---|
109 | | - dev_dbg(&client->dev, "succeed to write 0x%04x,0x%x\n", reg, val); |
---|
| 118 | + v4l2_dbg(1, debug, &dev_vcm->sd, "succeed to write 0x%04x,0x%x\n", reg, val); |
---|
110 | 119 | |
---|
111 | 120 | return 0; |
---|
112 | 121 | } |
---|
.. | .. |
---|
120 | 129 | u8 *data_be_p; |
---|
121 | 130 | __be32 data_be = 0; |
---|
122 | 131 | int ret; |
---|
| 132 | + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); |
---|
123 | 133 | |
---|
124 | 134 | if (len > 4 || !len) |
---|
125 | 135 | return -EINVAL; |
---|
.. | .. |
---|
142 | 152 | return -EIO; |
---|
143 | 153 | |
---|
144 | 154 | *val = be32_to_cpu(data_be); |
---|
| 155 | + |
---|
| 156 | + v4l2_dbg(1, debug, &dev_vcm->sd, "succeed to read 0x%04x,0x%x\n", reg, *val); |
---|
145 | 157 | |
---|
146 | 158 | return 0; |
---|
147 | 159 | } |
---|
.. | .. |
---|
204 | 216 | break; |
---|
205 | 217 | } |
---|
206 | 218 | |
---|
207 | | - dev_dbg(&client->dev, |
---|
| 219 | + v4l2_dbg(1, debug, &dev_vcm->sd, |
---|
208 | 220 | "%s: vcm_movefull_t is: %d us\n", |
---|
209 | 221 | __func__, move_time_us); |
---|
210 | 222 | |
---|
211 | | - return move_time_us; |
---|
| 223 | + return ((move_time_us + 500) / 1000); |
---|
212 | 224 | } |
---|
213 | 225 | |
---|
214 | 226 | static int dw9763_set_dac(struct dw9763_device *dev_vcm, |
---|
.. | .. |
---|
228 | 240 | ret = dw9763_write_reg(client, 0x03, 2, dest_dac); |
---|
229 | 241 | if (ret != 0) |
---|
230 | 242 | goto err; |
---|
231 | | - dev_dbg(&client->dev, |
---|
| 243 | + v4l2_dbg(1, debug, &dev_vcm->sd, |
---|
232 | 244 | "%s: set reg val %d\n", __func__, dest_dac); |
---|
233 | 245 | |
---|
234 | 246 | return ret; |
---|
.. | .. |
---|
249 | 261 | goto err; |
---|
250 | 262 | |
---|
251 | 263 | *cur_dac = abs_step; |
---|
252 | | - dev_dbg(&client->dev, "%s: get dac %d\n", __func__, *cur_dac); |
---|
| 264 | + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: get dac %d\n", __func__, *cur_dac); |
---|
253 | 265 | |
---|
254 | 266 | return 0; |
---|
255 | 267 | |
---|
.. | .. |
---|
279 | 291 | abs_step = 0; |
---|
280 | 292 | |
---|
281 | 293 | *cur_pos = abs_step; |
---|
282 | | - dev_dbg(&client->dev, "%s: get position %d\n", __func__, *cur_pos); |
---|
| 294 | + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: get position %d\n", __func__, *cur_pos); |
---|
283 | 295 | return 0; |
---|
284 | 296 | |
---|
285 | 297 | err: |
---|
.. | .. |
---|
293 | 305 | { |
---|
294 | 306 | int ret; |
---|
295 | 307 | unsigned int position = 0; |
---|
296 | | - struct i2c_client *client = dev_vcm->client; |
---|
297 | 308 | |
---|
298 | 309 | if (dest_pos >= VCMDRV_MAX_LOG) |
---|
299 | 310 | position = dev_vcm->start_current; |
---|
.. | .. |
---|
308 | 319 | dev_vcm->current_related_pos = dest_pos; |
---|
309 | 320 | |
---|
310 | 321 | ret = dw9763_set_dac(dev_vcm, position); |
---|
311 | | - dev_dbg(&client->dev, "%s: set position %d, dac %d\n", __func__, dest_pos, position); |
---|
| 322 | + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: set position %d, dac %d\n", |
---|
| 323 | + __func__, dest_pos, position); |
---|
312 | 324 | |
---|
313 | 325 | return ret; |
---|
314 | 326 | } |
---|
.. | .. |
---|
331 | 343 | long mv_us; |
---|
332 | 344 | int ret = 0; |
---|
333 | 345 | |
---|
334 | | - dev_dbg(&client->dev, "ctrl->id: 0x%x, ctrl->val: 0x%x\n", |
---|
| 346 | + v4l2_dbg(1, debug, &dev_vcm->sd, "ctrl->id: 0x%x, ctrl->val: 0x%x\n", |
---|
335 | 347 | ctrl->id, ctrl->val); |
---|
336 | 348 | |
---|
337 | 349 | if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { |
---|
.. | .. |
---|
345 | 357 | |
---|
346 | 358 | ret = dw9763_set_pos(dev_vcm, dest_pos); |
---|
347 | 359 | |
---|
348 | | - dev_vcm->move_us = dev_vcm->vcm_movefull_t; |
---|
| 360 | + dev_vcm->move_us = dev_vcm->vcm_movefull_t * 1000; |
---|
349 | 361 | |
---|
350 | | - dev_dbg(&client->dev, |
---|
| 362 | + v4l2_dbg(1, debug, &dev_vcm->sd, |
---|
351 | 363 | "dest_pos %d, move_us %ld\n", |
---|
352 | 364 | dest_pos, dev_vcm->move_us); |
---|
353 | 365 | |
---|
.. | .. |
---|
373 | 385 | .s_ctrl = dw9763_set_ctrl, |
---|
374 | 386 | }; |
---|
375 | 387 | |
---|
| 388 | +static int dw9763_init(struct i2c_client *client); |
---|
376 | 389 | static int dw9763_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
---|
377 | 390 | { |
---|
378 | 391 | int rval; |
---|
| 392 | + struct dw9763_device *dev_vcm = sd_to_dw9763_vcm(sd); |
---|
| 393 | + unsigned int move_time; |
---|
| 394 | + int dac = dev_vcm->start_current; |
---|
| 395 | + struct i2c_client *client = dev_vcm->client; |
---|
| 396 | + |
---|
| 397 | +#ifdef CONFIG_PM |
---|
| 398 | + v4l2_info(sd, "%s: enter, power.usage_count(%d)!\n", __func__, |
---|
| 399 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 400 | +#endif |
---|
379 | 401 | |
---|
380 | 402 | rval = pm_runtime_get_sync(sd->dev); |
---|
381 | 403 | if (rval < 0) { |
---|
.. | .. |
---|
383 | 405 | return rval; |
---|
384 | 406 | } |
---|
385 | 407 | |
---|
| 408 | + dw9763_init(client); |
---|
| 409 | + |
---|
| 410 | + v4l2_dbg(1, debug, sd, "%s: current_lens_pos %d, current_related_pos %d\n", |
---|
| 411 | + __func__, dev_vcm->current_lens_pos, dev_vcm->current_related_pos); |
---|
| 412 | + |
---|
| 413 | + move_time = 1000 * dw9763_move_time(dev_vcm, DW9763_GRADUAL_MOVELENS_STEPS); |
---|
| 414 | + while (dac <= dev_vcm->current_lens_pos) { |
---|
| 415 | + dw9763_set_dac(dev_vcm, dac); |
---|
| 416 | + usleep_range(move_time, move_time + 100); |
---|
| 417 | + dac += DW9763_GRADUAL_MOVELENS_STEPS; |
---|
| 418 | + if (dac > dev_vcm->current_lens_pos) |
---|
| 419 | + break; |
---|
| 420 | + } |
---|
| 421 | + |
---|
| 422 | + if (dac > dev_vcm->current_lens_pos) { |
---|
| 423 | + dac = dev_vcm->current_lens_pos; |
---|
| 424 | + dw9763_set_dac(dev_vcm, dac); |
---|
| 425 | + } |
---|
| 426 | + |
---|
| 427 | +#ifdef CONFIG_PM |
---|
| 428 | + v4l2_info(sd, "%s: exit, power.usage_count(%d)!\n", __func__, |
---|
| 429 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 430 | +#endif |
---|
386 | 431 | return 0; |
---|
387 | 432 | } |
---|
388 | 433 | |
---|
389 | 434 | static int dw9763_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
---|
390 | 435 | { |
---|
| 436 | + struct dw9763_device *dev_vcm = sd_to_dw9763_vcm(sd); |
---|
| 437 | + int dac = dev_vcm->current_lens_pos; |
---|
| 438 | + unsigned int move_time; |
---|
| 439 | + int ret; |
---|
| 440 | + struct i2c_client *client = dev_vcm->client; |
---|
| 441 | + |
---|
| 442 | +#ifdef CONFIG_PM |
---|
| 443 | + v4l2_info(sd, "%s: enter, power.usage_count(%d)!\n", __func__, |
---|
| 444 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 445 | +#endif |
---|
| 446 | + |
---|
| 447 | + v4l2_dbg(1, debug, sd, "%s: current_lens_pos %d, current_related_pos %d\n", |
---|
| 448 | + __func__, dev_vcm->current_lens_pos, dev_vcm->current_related_pos); |
---|
| 449 | + |
---|
| 450 | + dac -= DW9763_GRADUAL_MOVELENS_STEPS; |
---|
| 451 | + move_time = 1000 * dw9763_move_time(dev_vcm, DW9763_GRADUAL_MOVELENS_STEPS); |
---|
| 452 | + while (dac >= DW9763_GRADUAL_MOVELENS_STEPS) { |
---|
| 453 | + dw9763_set_dac(dev_vcm, dac); |
---|
| 454 | + usleep_range(move_time, move_time + 1000); |
---|
| 455 | + dac -= DW9763_GRADUAL_MOVELENS_STEPS; |
---|
| 456 | + if (dac <= 0) |
---|
| 457 | + break; |
---|
| 458 | + } |
---|
| 459 | + |
---|
| 460 | + if (dac < DW9763_GRADUAL_MOVELENS_STEPS) { |
---|
| 461 | + dac = DW9763_GRADUAL_MOVELENS_STEPS / 2; |
---|
| 462 | + dw9763_set_dac(dev_vcm, dac); |
---|
| 463 | + } |
---|
| 464 | + /* set to power down mode */ |
---|
| 465 | + ret = dw9763_write_reg(client, 0x02, 1, 0x01); |
---|
| 466 | + if (ret) |
---|
| 467 | + dev_err(&client->dev, "failed to set power down mode!\n"); |
---|
| 468 | + |
---|
391 | 469 | pm_runtime_put(sd->dev); |
---|
| 470 | +#ifdef CONFIG_PM |
---|
| 471 | + v4l2_info(sd, "%s: exit, power.usage_count(%d)!\n", __func__, |
---|
| 472 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 473 | +#endif |
---|
392 | 474 | |
---|
393 | 475 | return 0; |
---|
394 | 476 | } |
---|
.. | .. |
---|
442 | 524 | vcm_tim->vcm_end_t.tv_sec = dev_vcm->end_move_tv.tv_sec; |
---|
443 | 525 | vcm_tim->vcm_end_t.tv_usec = dev_vcm->end_move_tv.tv_usec; |
---|
444 | 526 | |
---|
445 | | - dev_dbg(&client->dev, "dw9763_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", |
---|
| 527 | + v4l2_dbg(1, debug, &dev_vcm->sd, "dw9763_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", |
---|
446 | 528 | vcm_tim->vcm_start_t.tv_sec, |
---|
447 | 529 | vcm_tim->vcm_start_t.tv_usec, |
---|
448 | 530 | vcm_tim->vcm_end_t.tv_sec, |
---|
.. | .. |
---|
634 | 716 | } |
---|
635 | 717 | #endif |
---|
636 | 718 | |
---|
637 | | -static int __dw9763_set_power(struct dw9763_device *dw9763_dev, bool on) |
---|
| 719 | +static int __dw9763_set_power(struct dw9763_device *dw9763, bool on) |
---|
638 | 720 | { |
---|
639 | | - if (dw9763_dev->power_gpio) |
---|
640 | | - gpiod_direction_output(dw9763_dev->power_gpio, on); |
---|
641 | | - usleep_range(10000, 11000); |
---|
| 721 | + struct i2c_client *client = dw9763->client; |
---|
| 722 | + int ret = 0; |
---|
642 | 723 | |
---|
643 | | - return 0; |
---|
| 724 | + dev_info(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on); |
---|
| 725 | + |
---|
| 726 | + if (dw9763->power_on == !!on) |
---|
| 727 | + goto unlock_and_return; |
---|
| 728 | + |
---|
| 729 | + if (on) { |
---|
| 730 | + ret = regulator_enable(dw9763->supply); |
---|
| 731 | + if (ret < 0) { |
---|
| 732 | + dev_err(&client->dev, "Failed to enable regulator\n"); |
---|
| 733 | + goto unlock_and_return; |
---|
| 734 | + } |
---|
| 735 | + dw9763->power_on = true; |
---|
| 736 | + } else { |
---|
| 737 | + ret = regulator_disable(dw9763->supply); |
---|
| 738 | + if (ret < 0) { |
---|
| 739 | + dev_err(&client->dev, "Failed to disable regulator\n"); |
---|
| 740 | + goto unlock_and_return; |
---|
| 741 | + } |
---|
| 742 | + dw9763->power_on = false; |
---|
| 743 | + } |
---|
| 744 | + |
---|
| 745 | +unlock_and_return: |
---|
| 746 | + return ret; |
---|
| 747 | +} |
---|
| 748 | + |
---|
| 749 | +static int dw9763_configure_regulator(struct dw9763_device *dw9763) |
---|
| 750 | +{ |
---|
| 751 | + struct i2c_client *client = dw9763->client; |
---|
| 752 | + int ret = 0; |
---|
| 753 | + |
---|
| 754 | + dw9763->supply = devm_regulator_get(&client->dev, "avdd"); |
---|
| 755 | + if (IS_ERR(dw9763->supply)) { |
---|
| 756 | + ret = PTR_ERR(dw9763->supply); |
---|
| 757 | + if (ret != -EPROBE_DEFER) |
---|
| 758 | + dev_err(&client->dev, "could not get regulator avdd\n"); |
---|
| 759 | + return ret; |
---|
| 760 | + } |
---|
| 761 | + dw9763->power_on = false; |
---|
| 762 | + return ret; |
---|
644 | 763 | } |
---|
645 | 764 | |
---|
646 | 765 | static int __maybe_unused dw9763_check_id(struct dw9763_device *dw9763_dev) |
---|
.. | .. |
---|
661 | 780 | dev_info(&dw9763_dev->client->dev, |
---|
662 | 781 | "Detected dw9763 vcm id:0x%x\n", DW9763_CHIP_ID); |
---|
663 | 782 | return 0; |
---|
664 | | -} |
---|
665 | | -static int dw9763_probe_init(struct i2c_client *client) |
---|
666 | | -{ |
---|
667 | | - int ret = 0; |
---|
668 | | - |
---|
669 | | - /* Default goto power down mode when finished probe */ |
---|
670 | | - ret = dw9763_write_reg(client, 0x02, 1, 0x01); |
---|
671 | | - if (ret) |
---|
672 | | - goto err; |
---|
673 | | - |
---|
674 | | - return 0; |
---|
675 | | -err: |
---|
676 | | - dev_err(&client->dev, "probe init failed with error %d\n", ret); |
---|
677 | | - return -1; |
---|
678 | 783 | } |
---|
679 | 784 | |
---|
680 | 785 | static int dw9763_probe(struct i2c_client *client, |
---|
.. | .. |
---|
765 | 870 | dev_warn(&client->dev, |
---|
766 | 871 | "Failed to get power-gpios, maybe no use\n"); |
---|
767 | 872 | } |
---|
768 | | - |
---|
769 | | - /* enter power down mode */ |
---|
770 | | - dw9763_probe_init(client); |
---|
| 873 | + ret = dw9763_configure_regulator(dw9763_dev); |
---|
| 874 | + if (ret) { |
---|
| 875 | + dev_err(&client->dev, "Failed to get power regulator!\n"); |
---|
| 876 | + return ret; |
---|
| 877 | + } |
---|
771 | 878 | |
---|
772 | 879 | v4l2_i2c_subdev_init(&dw9763_dev->sd, client, &dw9763_ops); |
---|
773 | 880 | dw9763_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
---|
.. | .. |
---|
780 | 887 | ret = media_entity_pads_init(&dw9763_dev->sd.entity, 0, NULL); |
---|
781 | 888 | if (ret < 0) |
---|
782 | 889 | goto err_cleanup; |
---|
| 890 | + |
---|
| 891 | + ret = dw9763_check_id(dw9763_dev); |
---|
| 892 | + if (ret) |
---|
| 893 | + goto err_power_off; |
---|
783 | 894 | |
---|
784 | 895 | sd = &dw9763_dev->sd; |
---|
785 | 896 | sd->entity.function = MEDIA_ENT_F_LENS; |
---|
.. | .. |
---|
823 | 934 | dev_info(&client->dev, "probing successful\n"); |
---|
824 | 935 | |
---|
825 | 936 | return 0; |
---|
| 937 | +err_power_off: |
---|
| 938 | + __dw9763_set_power(dw9763_dev, false); |
---|
| 939 | + |
---|
826 | 940 | err_cleanup: |
---|
827 | 941 | dw9763_subdev_cleanup(dw9763_dev); |
---|
828 | 942 | |
---|
.. | .. |
---|
847 | 961 | { |
---|
848 | 962 | struct dw9763_device *dev_vcm = i2c_get_clientdata(client); |
---|
849 | 963 | int ret = 0; |
---|
850 | | - u32 ring = 0; |
---|
851 | 964 | u32 mode_val = 0; |
---|
852 | 965 | u32 algo_time = 0; |
---|
853 | 966 | |
---|
| 967 | + if (dev_vcm->step_mode == DIRECT_MODE) |
---|
| 968 | + return 0; |
---|
854 | 969 | |
---|
855 | | - /* Delay 200us~300us */ |
---|
856 | | - usleep_range(200, 300); |
---|
857 | 970 | ret = dw9763_write_reg(client, 0x02, 1, 0x00); |
---|
858 | 971 | if (ret) |
---|
859 | 972 | goto err; |
---|
860 | | - usleep_range(100, 200); |
---|
861 | 973 | |
---|
862 | | - if (dev_vcm->step_mode != DIRECT_MODE) |
---|
863 | | - ring = 0x02; |
---|
864 | | - ret = dw9763_write_reg(client, 0x02, 1, ring); |
---|
| 974 | + usleep_range(200, 300); |
---|
| 975 | + ret = dw9763_write_reg(client, 0x02, 1, 0x02); |
---|
865 | 976 | if (ret) |
---|
866 | 977 | goto err; |
---|
867 | 978 | switch (dev_vcm->step_mode) { |
---|
.. | .. |
---|
895 | 1006 | static int __maybe_unused dw9763_vcm_suspend(struct device *dev) |
---|
896 | 1007 | { |
---|
897 | 1008 | struct i2c_client *client = to_i2c_client(dev); |
---|
898 | | - int ret = 0; |
---|
| 1009 | + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); |
---|
| 1010 | + struct v4l2_subdev *sd = &(dev_vcm->sd); |
---|
899 | 1011 | |
---|
900 | | - /* set to power down mode */ |
---|
901 | | - ret = dw9763_write_reg(client, 0x02, 1, 0x01); |
---|
902 | | - if (ret) |
---|
903 | | - dev_err(&client->dev, "failed to set power down mode!\n"); |
---|
| 1012 | +#ifdef CONFIG_PM |
---|
| 1013 | + v4l2_dbg(1, debug, sd, "%s: enter, power.usage_count(%d)!\n", __func__, |
---|
| 1014 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 1015 | +#endif |
---|
904 | 1016 | |
---|
| 1017 | + __dw9763_set_power(dev_vcm, false); |
---|
905 | 1018 | return 0; |
---|
906 | 1019 | } |
---|
907 | 1020 | |
---|
.. | .. |
---|
909 | 1022 | { |
---|
910 | 1023 | struct i2c_client *client = to_i2c_client(dev); |
---|
911 | 1024 | struct dw9763_device *dev_vcm = i2c_get_clientdata(client); |
---|
| 1025 | + struct v4l2_subdev *sd = &(dev_vcm->sd); |
---|
912 | 1026 | |
---|
913 | | - dw9763_init(client); |
---|
914 | | - dw9763_set_pos(dev_vcm, dev_vcm->current_related_pos); |
---|
| 1027 | +#ifdef CONFIG_PM |
---|
| 1028 | + v4l2_dbg(1, debug, sd, "%s: enter, power.usage_count(%d)!\n", __func__, |
---|
| 1029 | + atomic_read(&sd->dev->power.usage_count)); |
---|
| 1030 | +#endif |
---|
| 1031 | + __dw9763_set_power(dev_vcm, true); |
---|
| 1032 | + |
---|
915 | 1033 | return 0; |
---|
916 | 1034 | } |
---|
917 | 1035 | |
---|