.. | .. |
---|
22 | 22 | * 5. power control: local by pwdn gpio, remote by pocen gpio |
---|
23 | 23 | * 6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN |
---|
24 | 24 | * |
---|
| 25 | + * V2.02.00 |
---|
| 26 | + * 1. Force all MIPI clocks running Setting in csi out enable. |
---|
| 27 | + * 2. Pattern mode force_clock_out_en default enable. |
---|
| 28 | + * |
---|
| 29 | + * V2.03.00 |
---|
| 30 | + * 1. remote device add the maxim4c prefix to driver name. |
---|
| 31 | + * |
---|
| 32 | + * V2.04.04 |
---|
| 33 | + * 1. Add regulator supplier dependencies. |
---|
| 34 | + * 2. Add config ssc-ratio property |
---|
| 35 | + * 3. Add debugfs entry to change MIPI timing |
---|
| 36 | + * 4. Use PM runtime autosuspend feature |
---|
| 37 | + * 5. Fix unbalanced disabling for PoC regulator |
---|
| 38 | + * 6. MIPI VC count does not affected by data lane count |
---|
| 39 | + * |
---|
| 40 | + * V2.05.00 |
---|
| 41 | + * 1. local device power on add some delay for i2c normal access. |
---|
| 42 | + * 2. enable hot plug detect for partial links are locked. |
---|
| 43 | + * 3. remote device hot plug init disable lock irq. |
---|
| 44 | + * |
---|
25 | 45 | */ |
---|
26 | 46 | #include <linux/clk.h> |
---|
27 | 47 | #include <linux/i2c.h> |
---|
.. | .. |
---|
51 | 71 | |
---|
52 | 72 | #include "maxim4c_api.h" |
---|
53 | 73 | |
---|
54 | | -#define DRIVER_VERSION KERNEL_VERSION(2, 0x01, 0x00) |
---|
| 74 | +#define DRIVER_VERSION KERNEL_VERSION(2, 0x05, 0x00) |
---|
55 | 75 | |
---|
56 | 76 | #define MAXIM4C_XVCLK_FREQ 25000000 |
---|
| 77 | + |
---|
| 78 | +static const char *const maxim4c_supply_names[MAXIM4C_NUM_SUPPLIES] = { |
---|
| 79 | + "vcc1v2", |
---|
| 80 | + "vcc1v8", |
---|
| 81 | +}; |
---|
57 | 82 | |
---|
58 | 83 | static int maxim4c_check_local_chipid(maxim4c_t *maxim4c) |
---|
59 | 84 | { |
---|
.. | .. |
---|
83 | 108 | return 0; |
---|
84 | 109 | } |
---|
85 | 110 | } else { |
---|
| 111 | + // if chipid is unexpected, retry |
---|
86 | 112 | dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid); |
---|
87 | | - return -ENODEV; |
---|
88 | 113 | } |
---|
89 | 114 | } |
---|
90 | 115 | } |
---|
.. | .. |
---|
115 | 140 | |
---|
116 | 141 | queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, |
---|
117 | 142 | &maxim4c->hot_plug_work.state_d_work, |
---|
118 | | - msecs_to_jiffies(50)); |
---|
| 143 | + msecs_to_jiffies(100)); |
---|
119 | 144 | } |
---|
120 | 145 | mutex_unlock(&maxim4c->mutex); |
---|
121 | 146 | |
---|
.. | .. |
---|
189 | 214 | if (curr_lock_state & MAXIM4C_LINK_MASK_A) { |
---|
190 | 215 | dev_info(dev, "Link A plug in\n"); |
---|
191 | 216 | |
---|
| 217 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 218 | + disable_irq(maxim4c->hot_plug_irq); |
---|
| 219 | + |
---|
192 | 220 | maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A); |
---|
| 221 | + |
---|
| 222 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 223 | + enable_irq(maxim4c->hot_plug_irq); |
---|
193 | 224 | |
---|
194 | 225 | maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); |
---|
195 | 226 | } else { |
---|
.. | .. |
---|
205 | 236 | if (curr_lock_state & MAXIM4C_LINK_MASK_B) { |
---|
206 | 237 | dev_info(dev, "Link B plug in\n"); |
---|
207 | 238 | |
---|
| 239 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 240 | + disable_irq(maxim4c->hot_plug_irq); |
---|
| 241 | + |
---|
208 | 242 | maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B); |
---|
| 243 | + |
---|
| 244 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 245 | + enable_irq(maxim4c->hot_plug_irq); |
---|
209 | 246 | |
---|
210 | 247 | maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); |
---|
211 | 248 | } else { |
---|
.. | .. |
---|
221 | 258 | if (curr_lock_state & MAXIM4C_LINK_MASK_C) { |
---|
222 | 259 | dev_info(dev, "Link C plug in\n"); |
---|
223 | 260 | |
---|
| 261 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 262 | + disable_irq(maxim4c->hot_plug_irq); |
---|
| 263 | + |
---|
224 | 264 | maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C); |
---|
| 265 | + |
---|
| 266 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 267 | + enable_irq(maxim4c->hot_plug_irq); |
---|
225 | 268 | |
---|
226 | 269 | maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); |
---|
227 | 270 | } else { |
---|
.. | .. |
---|
237 | 280 | if (curr_lock_state & MAXIM4C_LINK_MASK_D) { |
---|
238 | 281 | dev_info(dev, "Link D plug in\n"); |
---|
239 | 282 | |
---|
| 283 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 284 | + disable_irq(maxim4c->hot_plug_irq); |
---|
| 285 | + |
---|
240 | 286 | maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D); |
---|
| 287 | + |
---|
| 288 | + if (maxim4c->hot_plug_irq > 0) |
---|
| 289 | + enable_irq(maxim4c->hot_plug_irq); |
---|
241 | 290 | |
---|
242 | 291 | maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); |
---|
243 | 292 | } else { |
---|
.. | .. |
---|
253 | 302 | } else { |
---|
254 | 303 | queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, |
---|
255 | 304 | &maxim4c->hot_plug_work.state_d_work, |
---|
256 | | - msecs_to_jiffies(100)); |
---|
| 305 | + msecs_to_jiffies(200)); |
---|
257 | 306 | } |
---|
258 | 307 | |
---|
259 | 308 | mutex_unlock(&maxim4c->mutex); |
---|
| 309 | +} |
---|
| 310 | + |
---|
| 311 | +int maxim4c_hot_plug_detect_work_start(maxim4c_t *maxim4c) |
---|
| 312 | +{ |
---|
| 313 | + struct device *dev = &maxim4c->client->dev; |
---|
| 314 | + u8 link_lock_state = 0, link_enable_mask = 0; |
---|
| 315 | + |
---|
| 316 | + link_lock_state = maxim4c->link_lock_state; |
---|
| 317 | + link_enable_mask = maxim4c->gmsl_link.link_enable_mask; |
---|
| 318 | + |
---|
| 319 | + if (link_lock_state != link_enable_mask) { |
---|
| 320 | + dev_info(dev, "%s: link_lock = 0x%02x, link_mask = 0x%02x\n", |
---|
| 321 | + __func__, link_lock_state, link_enable_mask); |
---|
| 322 | + |
---|
| 323 | + maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_OUT; |
---|
| 324 | + |
---|
| 325 | + queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, |
---|
| 326 | + &maxim4c->hot_plug_work.state_d_work, |
---|
| 327 | + msecs_to_jiffies(200)); |
---|
| 328 | + } |
---|
| 329 | + |
---|
| 330 | + return 0; |
---|
260 | 331 | } |
---|
261 | 332 | |
---|
262 | 333 | static int maxim4c_lock_state_work_init(maxim4c_t *maxim4c) |
---|
.. | .. |
---|
295 | 366 | static int maxim4c_local_device_power_on(maxim4c_t *maxim4c) |
---|
296 | 367 | { |
---|
297 | 368 | struct device *dev = &maxim4c->client->dev; |
---|
| 369 | + int ret; |
---|
| 370 | + |
---|
| 371 | + ret = regulator_bulk_enable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies); |
---|
| 372 | + if (ret < 0) { |
---|
| 373 | + dev_err(dev, "Failed to enable regulators\n"); |
---|
| 374 | + return -EINVAL; |
---|
| 375 | + } |
---|
298 | 376 | |
---|
299 | 377 | if (!IS_ERR(maxim4c->pwdn_gpio)) { |
---|
300 | 378 | dev_info(dev, "local device pwdn gpio on\n"); |
---|
301 | 379 | |
---|
302 | 380 | gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1); |
---|
303 | 381 | |
---|
304 | | - usleep_range(5000, 10000); |
---|
| 382 | + usleep_range(10000, 11000); |
---|
305 | 383 | } |
---|
306 | 384 | |
---|
307 | 385 | return 0; |
---|
.. | .. |
---|
310 | 388 | static void maxim4c_local_device_power_off(maxim4c_t *maxim4c) |
---|
311 | 389 | { |
---|
312 | 390 | struct device *dev = &maxim4c->client->dev; |
---|
| 391 | + int ret; |
---|
313 | 392 | |
---|
314 | 393 | if (!IS_ERR(maxim4c->pwdn_gpio)) { |
---|
315 | 394 | dev_info(dev, "local device pwdn gpio off\n"); |
---|
316 | 395 | |
---|
317 | 396 | gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0); |
---|
318 | 397 | } |
---|
| 398 | + |
---|
| 399 | + ret = regulator_bulk_disable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies); |
---|
| 400 | + if (ret < 0) { |
---|
| 401 | + dev_warn(dev, "Failed to disable regulators\n"); |
---|
| 402 | + } |
---|
319 | 403 | } |
---|
320 | 404 | |
---|
321 | 405 | static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c) |
---|
322 | 406 | { |
---|
323 | 407 | struct device *dev = &maxim4c->client->dev; |
---|
| 408 | + int ret; |
---|
324 | 409 | |
---|
325 | | - // remote PoC enable |
---|
326 | | - if (!IS_ERR(maxim4c->pocen_gpio)) { |
---|
327 | | - dev_info(dev, "remote device pocen gpio on\n"); |
---|
328 | | - |
---|
329 | | - gpiod_set_value_cansleep(maxim4c->pocen_gpio, 1); |
---|
330 | | - usleep_range(5000, 10000); |
---|
| 410 | + dev_dbg(dev, "Turn PoC on\n"); |
---|
| 411 | + ret = regulator_enable(maxim4c->poc_regulator); |
---|
| 412 | + if (ret < 0) { |
---|
| 413 | + dev_err(dev, "Unable to turn PoC on\n"); |
---|
| 414 | + return ret; |
---|
331 | 415 | } |
---|
332 | 416 | |
---|
333 | 417 | return 0; |
---|
.. | .. |
---|
336 | 420 | static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c) |
---|
337 | 421 | { |
---|
338 | 422 | struct device *dev = &maxim4c->client->dev; |
---|
| 423 | + int ret; |
---|
339 | 424 | |
---|
340 | | - // remote PoC enable |
---|
341 | | - if (!IS_ERR(maxim4c->pocen_gpio)) { |
---|
342 | | - dev_info(dev, "remote device pocen gpio off\n"); |
---|
343 | | - |
---|
344 | | - gpiod_set_value_cansleep(maxim4c->pocen_gpio, 0); |
---|
345 | | - } |
---|
| 425 | + dev_dbg(dev, "Turn PoC off\n"); |
---|
| 426 | + ret = regulator_disable(maxim4c->poc_regulator); |
---|
| 427 | + if (ret < 0) |
---|
| 428 | + dev_warn(dev, "Unable to turn PoC off\n"); |
---|
346 | 429 | |
---|
347 | 430 | return 0; |
---|
348 | 431 | } |
---|
.. | .. |
---|
574 | 657 | maxim4c_t *maxim4c = NULL; |
---|
575 | 658 | u32 chip_id; |
---|
576 | 659 | int ret = 0; |
---|
| 660 | + unsigned int i; |
---|
577 | 661 | |
---|
578 | 662 | dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, |
---|
579 | 663 | (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); |
---|
.. | .. |
---|
613 | 697 | maxim4c->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
---|
614 | 698 | if (IS_ERR(maxim4c->pwdn_gpio)) |
---|
615 | 699 | dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n"); |
---|
616 | | - |
---|
617 | | - maxim4c->pocen_gpio = devm_gpiod_get(dev, "pocen", GPIOD_OUT_LOW); |
---|
618 | | - if (IS_ERR(maxim4c->pocen_gpio)) |
---|
619 | | - dev_warn(dev, "Failed to get pocen-gpios\n"); |
---|
| 700 | + else |
---|
| 701 | + usleep_range(1000, 1100); |
---|
620 | 702 | |
---|
621 | 703 | maxim4c->lock_gpio = devm_gpiod_get(dev, "lock", GPIOD_IN); |
---|
622 | 704 | if (IS_ERR(maxim4c->lock_gpio)) |
---|
623 | 705 | dev_warn(dev, "Failed to get lock-gpios\n"); |
---|
| 706 | + |
---|
| 707 | + for (i = 0; i < MAXIM4C_NUM_SUPPLIES; i++) |
---|
| 708 | + maxim4c->supplies[i].supply = maxim4c_supply_names[i]; |
---|
| 709 | + |
---|
| 710 | + ret = devm_regulator_bulk_get(dev, MAXIM4C_NUM_SUPPLIES, |
---|
| 711 | + maxim4c->supplies); |
---|
| 712 | + if (ret < 0) { |
---|
| 713 | + if (ret != -EPROBE_DEFER) |
---|
| 714 | + dev_err(dev, "Unable to get supply regulators\n"); |
---|
| 715 | + else |
---|
| 716 | + dev_warn(dev, "Get PoC regulator deferred\n"); |
---|
| 717 | + return ret; |
---|
| 718 | + } |
---|
| 719 | + |
---|
| 720 | + maxim4c->poc_regulator = devm_regulator_get(dev, "poc"); |
---|
| 721 | + if (IS_ERR(maxim4c->poc_regulator)) { |
---|
| 722 | + if (PTR_ERR(maxim4c->poc_regulator) != -EPROBE_DEFER) |
---|
| 723 | + dev_err(dev, "Unable to get PoC regulator (%ld)\n", |
---|
| 724 | + PTR_ERR(maxim4c->poc_regulator)); |
---|
| 725 | + else |
---|
| 726 | + dev_err(dev, "Get PoC regulator deferred\n"); |
---|
| 727 | + |
---|
| 728 | + ret = PTR_ERR(maxim4c->poc_regulator); |
---|
| 729 | +#if !MAXIM4C_TEST_PATTERN |
---|
| 730 | + return ret; |
---|
| 731 | +#endif |
---|
| 732 | + } |
---|
624 | 733 | |
---|
625 | 734 | mutex_init(&maxim4c->mutex); |
---|
626 | 735 | |
---|
627 | 736 | ret = maxim4c_local_device_power_on(maxim4c); |
---|
628 | 737 | if (ret) |
---|
629 | 738 | goto err_destroy_mutex; |
---|
| 739 | + |
---|
| 740 | + ret = maxim4c_remote_device_power_on(maxim4c); |
---|
| 741 | + if (ret) |
---|
| 742 | + dev_warn(dev, "Power on PoC regulator failed\n"); |
---|
| 743 | + |
---|
| 744 | + pm_runtime_set_active(dev); |
---|
| 745 | + pm_runtime_get_noresume(dev); |
---|
| 746 | + pm_runtime_enable(dev); |
---|
630 | 747 | |
---|
631 | 748 | ret = maxim4c_check_local_chipid(maxim4c); |
---|
632 | 749 | if (ret) |
---|
.. | .. |
---|
651 | 768 | goto err_power_off; |
---|
652 | 769 | #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ |
---|
653 | 770 | |
---|
654 | | - pm_runtime_set_active(dev); |
---|
655 | | - pm_runtime_enable(dev); |
---|
656 | | - pm_runtime_idle(dev); |
---|
| 771 | + pm_runtime_set_autosuspend_delay(dev, 1000); |
---|
| 772 | + pm_runtime_use_autosuspend(dev); |
---|
| 773 | + pm_runtime_mark_last_busy(dev); |
---|
| 774 | + pm_runtime_put_autosuspend(dev); |
---|
657 | 775 | |
---|
658 | 776 | return 0; |
---|
659 | 777 | #endif /* MAXIM4C_TEST_PATTERN */ |
---|
.. | .. |
---|
661 | 779 | maxim4c_module_data_init(maxim4c); |
---|
662 | 780 | maxim4c_module_parse_dt(maxim4c); |
---|
663 | 781 | |
---|
| 782 | + ret = maxim4c_dbgfs_init(maxim4c); |
---|
| 783 | + if (ret) |
---|
| 784 | + goto err_subdev_deinit; |
---|
| 785 | + |
---|
664 | 786 | #if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0) |
---|
665 | 787 | ret = maxim4c_module_hw_init(maxim4c); |
---|
666 | 788 | if (ret) |
---|
667 | | - goto err_subdev_deinit; |
---|
| 789 | + goto err_dbgfs_deinit; |
---|
668 | 790 | #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ |
---|
669 | 791 | |
---|
670 | 792 | ret = maxim4c_remote_mfd_add_devices(maxim4c); |
---|
671 | 793 | if (ret) |
---|
672 | | - goto err_subdev_deinit; |
---|
| 794 | + goto err_dbgfs_deinit; |
---|
673 | 795 | |
---|
674 | 796 | maxim4c_lock_irq_init(maxim4c); |
---|
675 | 797 | maxim4c_lock_state_work_init(maxim4c); |
---|
676 | 798 | |
---|
677 | | - pm_runtime_set_active(dev); |
---|
678 | | - pm_runtime_enable(dev); |
---|
679 | | - pm_runtime_idle(dev); |
---|
| 799 | + pm_runtime_set_autosuspend_delay(dev, 1000); |
---|
| 800 | + pm_runtime_use_autosuspend(dev); |
---|
| 801 | + pm_runtime_mark_last_busy(dev); |
---|
| 802 | + pm_runtime_put_autosuspend(dev); |
---|
680 | 803 | |
---|
681 | 804 | return 0; |
---|
682 | 805 | |
---|
| 806 | +err_dbgfs_deinit: |
---|
| 807 | + maxim4c_dbgfs_deinit(maxim4c); |
---|
683 | 808 | err_subdev_deinit: |
---|
684 | 809 | maxim4c_v4l2_subdev_deinit(maxim4c); |
---|
685 | 810 | err_power_off: |
---|
| 811 | + pm_runtime_disable(dev); |
---|
| 812 | + pm_runtime_put_noidle(dev); |
---|
| 813 | + maxim4c_remote_device_power_off(maxim4c); |
---|
686 | 814 | maxim4c_local_device_power_off(maxim4c); |
---|
687 | 815 | err_destroy_mutex: |
---|
688 | 816 | mutex_destroy(&maxim4c->mutex); |
---|
.. | .. |
---|
696 | 824 | |
---|
697 | 825 | maxim4c_lock_state_work_deinit(maxim4c); |
---|
698 | 826 | |
---|
| 827 | + maxim4c_dbgfs_deinit(maxim4c); |
---|
| 828 | + |
---|
699 | 829 | maxim4c_v4l2_subdev_deinit(maxim4c); |
---|
700 | 830 | |
---|
701 | 831 | mutex_destroy(&maxim4c->mutex); |
---|