36
36
* @selectable: pin is selectable in automatic mode
37
37
* @esync_control: embedded sync is controllable
38
38
* @pin_state: last saved pin state
39
+ * @phase_offset: last saved pin phase offset
39
40
*/
40
41
struct zl3073x_dpll_pin {
41
42
struct list_head list ;
@@ -48,6 +49,7 @@ struct zl3073x_dpll_pin {
48
49
bool selectable ;
49
50
bool esync_control ;
50
51
enum dpll_pin_state pin_state ;
52
+ s64 phase_offset ;
51
53
};
52
54
53
55
/*
@@ -496,6 +498,50 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
496
498
return 0 ;
497
499
}
498
500
501
+ static int
502
+ zl3073x_dpll_input_pin_phase_offset_get (const struct dpll_pin * dpll_pin ,
503
+ void * pin_priv ,
504
+ const struct dpll_device * dpll ,
505
+ void * dpll_priv , s64 * phase_offset ,
506
+ struct netlink_ext_ack * extack )
507
+ {
508
+ struct zl3073x_dpll * zldpll = dpll_priv ;
509
+ struct zl3073x_dev * zldev = zldpll -> dev ;
510
+ struct zl3073x_dpll_pin * pin = pin_priv ;
511
+ u8 conn_ref , ref , ref_status ;
512
+ int rc ;
513
+
514
+ /* Get currently connected reference */
515
+ rc = zl3073x_dpll_connected_ref_get (zldpll , & conn_ref );
516
+ if (rc )
517
+ return rc ;
518
+
519
+ /* Report phase offset only for currently connected pin */
520
+ ref = zl3073x_input_pin_ref_get (pin -> id );
521
+ if (ref != conn_ref ) {
522
+ * phase_offset = 0 ;
523
+
524
+ return 0 ;
525
+ }
526
+
527
+ /* Get this pin monitor status */
528
+ rc = zl3073x_read_u8 (zldev , ZL_REG_REF_MON_STATUS (ref ), & ref_status );
529
+ if (rc )
530
+ return rc ;
531
+
532
+ /* Report phase offset only if the input pin signal is present */
533
+ if (ref_status != ZL_REF_MON_STATUS_OK ) {
534
+ * phase_offset = 0 ;
535
+
536
+ return 0 ;
537
+ }
538
+
539
+ /* Report the latest measured phase offset for the connected ref */
540
+ * phase_offset = pin -> phase_offset * DPLL_PHASE_OFFSET_DIVIDER ;
541
+
542
+ return rc ;
543
+ }
544
+
499
545
/**
500
546
* zl3073x_dpll_ref_prio_get - get priority for given input pin
501
547
* @pin: pointer to pin
@@ -1303,6 +1349,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
1303
1349
.esync_set = zl3073x_dpll_input_pin_esync_set ,
1304
1350
.frequency_get = zl3073x_dpll_input_pin_frequency_get ,
1305
1351
.frequency_set = zl3073x_dpll_input_pin_frequency_set ,
1352
+ .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get ,
1306
1353
.prio_get = zl3073x_dpll_input_pin_prio_get ,
1307
1354
.prio_set = zl3073x_dpll_input_pin_prio_set ,
1308
1355
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get ,
@@ -1673,6 +1720,51 @@ zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll)
1673
1720
zldpll -> dpll_dev = NULL ;
1674
1721
}
1675
1722
1723
+ /**
1724
+ * zl3073x_dpll_pin_phase_offset_check - check for pin phase offset change
1725
+ * @pin: pin to check
1726
+ *
1727
+ * Check for the change of DPLL to connected pin phase offset change.
1728
+ *
1729
+ * Return: true on phase offset change, false otherwise
1730
+ */
1731
+ static bool
1732
+ zl3073x_dpll_pin_phase_offset_check (struct zl3073x_dpll_pin * pin )
1733
+ {
1734
+ struct zl3073x_dpll * zldpll = pin -> dpll ;
1735
+ struct zl3073x_dev * zldev = zldpll -> dev ;
1736
+ s64 phase_offset ;
1737
+ int rc ;
1738
+
1739
+ /* Do not check phase offset if the pin is not connected one */
1740
+ if (pin -> pin_state != DPLL_PIN_STATE_CONNECTED )
1741
+ return false;
1742
+
1743
+ /* Read DPLL-to-connected-ref phase offset measurement value */
1744
+ rc = zl3073x_read_u48 (zldev , ZL_REG_DPLL_PHASE_ERR_DATA (zldpll -> id ),
1745
+ & phase_offset );
1746
+ if (rc ) {
1747
+ dev_err (zldev -> dev , "Failed to read ref phase offset: %pe\n" ,
1748
+ ERR_PTR (rc ));
1749
+
1750
+ return false;
1751
+ }
1752
+
1753
+ /* Convert to ps */
1754
+ phase_offset = div_s64 (sign_extend64 (phase_offset , 47 ), 100 );
1755
+
1756
+ /* Compare with previous value */
1757
+ if (phase_offset != pin -> phase_offset ) {
1758
+ dev_dbg (zldev -> dev , "%s phase offset changed: %lld -> %lld\n" ,
1759
+ pin -> label , pin -> phase_offset , phase_offset );
1760
+ pin -> phase_offset = phase_offset ;
1761
+
1762
+ return true;
1763
+ }
1764
+
1765
+ return false;
1766
+ }
1767
+
1676
1768
/**
1677
1769
* zl3073x_dpll_changes_check - check for changes and send notifications
1678
1770
* @zldpll: pointer to zl3073x_dpll structure
@@ -1691,6 +1783,8 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
1691
1783
struct zl3073x_dpll_pin * pin ;
1692
1784
int rc ;
1693
1785
1786
+ zldpll -> check_count ++ ;
1787
+
1694
1788
/* Get current lock status for the DPLL */
1695
1789
rc = zl3073x_dpll_lock_status_get (zldpll -> dpll_dev , zldpll ,
1696
1790
& lock_status , NULL , NULL );
@@ -1715,6 +1809,7 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
1715
1809
1716
1810
list_for_each_entry (pin , & zldpll -> pins , list ) {
1717
1811
enum dpll_pin_state state ;
1812
+ bool pin_changed = false;
1718
1813
1719
1814
/* Output pins change checks are not necessary because output
1720
1815
* states are constant.
@@ -1734,8 +1829,16 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
1734
1829
dev_dbg (dev , "%s state changed: %u->%u\n" , pin -> label ,
1735
1830
pin -> pin_state , state );
1736
1831
pin -> pin_state = state ;
1737
- dpll_pin_change_ntf ( pin -> dpll_pin ) ;
1832
+ pin_changed = true ;
1738
1833
}
1834
+
1835
+ /* Check for phase offset change once per second */
1836
+ if (zldpll -> check_count % 2 == 0 )
1837
+ if (zl3073x_dpll_pin_phase_offset_check (pin ))
1838
+ pin_changed = true;
1839
+
1840
+ if (pin_changed )
1841
+ dpll_pin_change_ntf (pin -> dpll_pin );
1739
1842
}
1740
1843
}
1741
1844
0 commit comments