|
17 | 17 |
|
18 | 18 | #include "core.h" |
19 | 19 | #include "devlink.h" |
| 20 | +#include "dpll.h" |
20 | 21 | #include "regs.h" |
21 | 22 |
|
22 | 23 | /* Chip IDs for zl30731 */ |
@@ -668,6 +669,104 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev) |
668 | 669 | return rc; |
669 | 670 | } |
670 | 671 |
|
| 672 | +static void |
| 673 | +zl3073x_dev_periodic_work(struct kthread_work *work) |
| 674 | +{ |
| 675 | + struct zl3073x_dev *zldev = container_of(work, struct zl3073x_dev, |
| 676 | + work.work); |
| 677 | + struct zl3073x_dpll *zldpll; |
| 678 | + |
| 679 | + list_for_each_entry(zldpll, &zldev->dplls, list) |
| 680 | + zl3073x_dpll_changes_check(zldpll); |
| 681 | + |
| 682 | + /* Run twice a second */ |
| 683 | + kthread_queue_delayed_work(zldev->kworker, &zldev->work, |
| 684 | + msecs_to_jiffies(500)); |
| 685 | +} |
| 686 | + |
| 687 | +static void zl3073x_dev_dpll_fini(void *ptr) |
| 688 | +{ |
| 689 | + struct zl3073x_dpll *zldpll, *next; |
| 690 | + struct zl3073x_dev *zldev = ptr; |
| 691 | + |
| 692 | + /* Stop monitoring thread */ |
| 693 | + if (zldev->kworker) { |
| 694 | + kthread_cancel_delayed_work_sync(&zldev->work); |
| 695 | + kthread_destroy_worker(zldev->kworker); |
| 696 | + zldev->kworker = NULL; |
| 697 | + } |
| 698 | + |
| 699 | + /* Release DPLLs */ |
| 700 | + list_for_each_entry_safe(zldpll, next, &zldev->dplls, list) { |
| 701 | + zl3073x_dpll_unregister(zldpll); |
| 702 | + list_del(&zldpll->list); |
| 703 | + zl3073x_dpll_free(zldpll); |
| 704 | + } |
| 705 | +} |
| 706 | + |
| 707 | +static int |
| 708 | +zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls) |
| 709 | +{ |
| 710 | + struct kthread_worker *kworker; |
| 711 | + struct zl3073x_dpll *zldpll; |
| 712 | + unsigned int i; |
| 713 | + int rc; |
| 714 | + |
| 715 | + INIT_LIST_HEAD(&zldev->dplls); |
| 716 | + |
| 717 | + /* Initialize all DPLLs */ |
| 718 | + for (i = 0; i < num_dplls; i++) { |
| 719 | + zldpll = zl3073x_dpll_alloc(zldev, i); |
| 720 | + if (IS_ERR(zldpll)) { |
| 721 | + dev_err_probe(zldev->dev, PTR_ERR(zldpll), |
| 722 | + "Failed to alloc DPLL%u\n", i); |
| 723 | + rc = PTR_ERR(zldpll); |
| 724 | + goto error; |
| 725 | + } |
| 726 | + |
| 727 | + rc = zl3073x_dpll_register(zldpll); |
| 728 | + if (rc) { |
| 729 | + dev_err_probe(zldev->dev, rc, |
| 730 | + "Failed to register DPLL%u\n", i); |
| 731 | + zl3073x_dpll_free(zldpll); |
| 732 | + goto error; |
| 733 | + } |
| 734 | + |
| 735 | + list_add_tail(&zldpll->list, &zldev->dplls); |
| 736 | + } |
| 737 | + |
| 738 | + /* Perform initial firmware fine phase correction */ |
| 739 | + rc = zl3073x_dpll_init_fine_phase_adjust(zldev); |
| 740 | + if (rc) { |
| 741 | + dev_err_probe(zldev->dev, rc, |
| 742 | + "Failed to init fine phase correction\n"); |
| 743 | + goto error; |
| 744 | + } |
| 745 | + |
| 746 | + /* Initialize monitoring thread */ |
| 747 | + kthread_init_delayed_work(&zldev->work, zl3073x_dev_periodic_work); |
| 748 | + kworker = kthread_run_worker(0, "zl3073x-%s", dev_name(zldev->dev)); |
| 749 | + if (IS_ERR(kworker)) { |
| 750 | + rc = PTR_ERR(kworker); |
| 751 | + goto error; |
| 752 | + } |
| 753 | + |
| 754 | + zldev->kworker = kworker; |
| 755 | + kthread_queue_delayed_work(zldev->kworker, &zldev->work, 0); |
| 756 | + |
| 757 | + /* Add devres action to release DPLL related resources */ |
| 758 | + rc = devm_add_action_or_reset(zldev->dev, zl3073x_dev_dpll_fini, zldev); |
| 759 | + if (rc) |
| 760 | + goto error; |
| 761 | + |
| 762 | + return 0; |
| 763 | + |
| 764 | +error: |
| 765 | + zl3073x_dev_dpll_fini(zldev); |
| 766 | + |
| 767 | + return rc; |
| 768 | +} |
| 769 | + |
671 | 770 | /** |
672 | 771 | * zl3073x_dev_probe - initialize zl3073x device |
673 | 772 | * @zldev: pointer to zl3073x device |
@@ -740,6 +839,11 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev, |
740 | 839 | if (rc) |
741 | 840 | return rc; |
742 | 841 |
|
| 842 | + /* Register DPLL channels */ |
| 843 | + rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels); |
| 844 | + if (rc) |
| 845 | + return rc; |
| 846 | + |
743 | 847 | /* Register the devlink instance and parameters */ |
744 | 848 | rc = zl3073x_devlink_register(zldev); |
745 | 849 | if (rc) |
|
0 commit comments