Skip to content

Commit 86ed4cd

Browse files
iveceraPaolo Abeni
authored andcommitted
dpll: zl3073x: Add support to get phase offset on connected input pin
Add support to get phase offset for the connected input pin. Implement the appropriate callback and function that performs DPLL to connected reference phase error measurement and notifies DPLL core about changes. The measurement is performed internally by device on background 40 times per second but the measured value is read each second and compared with previous value. Reviewed-by: Jiri Pirko <[email protected]> Tested-by: Prathosh Satish <[email protected]> Co-developed-by: Prathosh Satish <[email protected]> Signed-off-by: Prathosh Satish <[email protected]> Signed-off-by: Ivan Vecera <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 634ca2c commit 86ed4cd

File tree

4 files changed

+208
-1
lines changed

4 files changed

+208
-1
lines changed

drivers/dpll/zl3073x/core.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,12 +669,52 @@ zl3073x_dev_state_fetch(struct zl3073x_dev *zldev)
669669
return rc;
670670
}
671671

672+
/**
673+
* zl3073x_ref_phase_offsets_update - update reference phase offsets
674+
* @zldev: pointer to zl3073x_dev structure
675+
*
676+
* Ask device to update phase offsets latch registers with the latest
677+
* measured values.
678+
*
679+
* Return: 0 on success, <0 on error
680+
*/
681+
static int
682+
zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev)
683+
{
684+
int rc;
685+
686+
/* Per datasheet we have to wait for 'dpll_ref_phase_err_rqst_rd'
687+
* to be zero to ensure that the measured data are coherent.
688+
*/
689+
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
690+
ZL_REF_PHASE_ERR_READ_RQST_RD);
691+
if (rc)
692+
return rc;
693+
694+
/* Request to update phase offsets measurement values */
695+
rc = zl3073x_write_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
696+
ZL_REF_PHASE_ERR_READ_RQST_RD);
697+
if (rc)
698+
return rc;
699+
700+
/* Wait for finish */
701+
return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
702+
ZL_REF_PHASE_ERR_READ_RQST_RD);
703+
}
704+
672705
static void
673706
zl3073x_dev_periodic_work(struct kthread_work *work)
674707
{
675708
struct zl3073x_dev *zldev = container_of(work, struct zl3073x_dev,
676709
work.work);
677710
struct zl3073x_dpll *zldpll;
711+
int rc;
712+
713+
/* Update DPLL-to-connected-ref phase offsets registers */
714+
rc = zl3073x_ref_phase_offsets_update(zldev);
715+
if (rc)
716+
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
717+
ERR_PTR(rc));
678718

679719
list_for_each_entry(zldpll, &zldev->dplls, list)
680720
zl3073x_dpll_changes_check(zldpll);
@@ -767,6 +807,46 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
767807
return rc;
768808
}
769809

810+
/**
811+
* zl3073x_dev_phase_meas_setup - setup phase offset measurement
812+
* @zldev: pointer to zl3073x_dev structure
813+
* @num_channels: number of DPLL channels
814+
*
815+
* Enable phase offset measurement block, set measurement averaging factor
816+
* and enable DPLL-to-its-ref phase measurement for all DPLLs.
817+
*
818+
* Returns: 0 on success, <0 on error
819+
*/
820+
static int
821+
zl3073x_dev_phase_meas_setup(struct zl3073x_dev *zldev, int num_channels)
822+
{
823+
u8 dpll_meas_ctrl, mask;
824+
int i, rc;
825+
826+
/* Read DPLL phase measurement control register */
827+
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, &dpll_meas_ctrl);
828+
if (rc)
829+
return rc;
830+
831+
/* Setup phase measurement averaging factor */
832+
dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR;
833+
dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, 3);
834+
835+
/* Enable DPLL measurement block */
836+
dpll_meas_ctrl |= ZL_DPLL_MEAS_CTRL_EN;
837+
838+
/* Update phase measurement control register */
839+
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl);
840+
if (rc)
841+
return rc;
842+
843+
/* Enable DPLL-to-connected-ref measurement for each channel */
844+
for (i = 0, mask = 0; i < num_channels; i++)
845+
mask |= BIT(i);
846+
847+
return zl3073x_write_u8(zldev, ZL_REG_DPLL_PHASE_ERR_READ_MASK, mask);
848+
}
849+
770850
/**
771851
* zl3073x_dev_probe - initialize zl3073x device
772852
* @zldev: pointer to zl3073x device
@@ -839,6 +919,12 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
839919
if (rc)
840920
return rc;
841921

922+
/* Setup phase offset measurement block */
923+
rc = zl3073x_dev_phase_meas_setup(zldev, chip_info->num_channels);
924+
if (rc)
925+
return dev_err_probe(zldev->dev, rc,
926+
"Failed to setup phase measurement\n");
927+
842928
/* Register DPLL channels */
843929
rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels);
844930
if (rc)

drivers/dpll/zl3073x/dpll.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* @selectable: pin is selectable in automatic mode
3737
* @esync_control: embedded sync is controllable
3838
* @pin_state: last saved pin state
39+
* @phase_offset: last saved pin phase offset
3940
*/
4041
struct zl3073x_dpll_pin {
4142
struct list_head list;
@@ -48,6 +49,7 @@ struct zl3073x_dpll_pin {
4849
bool selectable;
4950
bool esync_control;
5051
enum dpll_pin_state pin_state;
52+
s64 phase_offset;
5153
};
5254

5355
/*
@@ -496,6 +498,50 @@ zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
496498
return 0;
497499
}
498500

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+
499545
/**
500546
* zl3073x_dpll_ref_prio_get - get priority for given input pin
501547
* @pin: pointer to pin
@@ -1303,6 +1349,7 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
13031349
.esync_set = zl3073x_dpll_input_pin_esync_set,
13041350
.frequency_get = zl3073x_dpll_input_pin_frequency_get,
13051351
.frequency_set = zl3073x_dpll_input_pin_frequency_set,
1352+
.phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get,
13061353
.prio_get = zl3073x_dpll_input_pin_prio_get,
13071354
.prio_set = zl3073x_dpll_input_pin_prio_set,
13081355
.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
@@ -1673,6 +1720,51 @@ zl3073x_dpll_device_unregister(struct zl3073x_dpll *zldpll)
16731720
zldpll->dpll_dev = NULL;
16741721
}
16751722

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+
16761768
/**
16771769
* zl3073x_dpll_changes_check - check for changes and send notifications
16781770
* @zldpll: pointer to zl3073x_dpll structure
@@ -1691,6 +1783,8 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
16911783
struct zl3073x_dpll_pin *pin;
16921784
int rc;
16931785

1786+
zldpll->check_count++;
1787+
16941788
/* Get current lock status for the DPLL */
16951789
rc = zl3073x_dpll_lock_status_get(zldpll->dpll_dev, zldpll,
16961790
&lock_status, NULL, NULL);
@@ -1715,6 +1809,7 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
17151809

17161810
list_for_each_entry(pin, &zldpll->pins, list) {
17171811
enum dpll_pin_state state;
1812+
bool pin_changed = false;
17181813

17191814
/* Output pins change checks are not necessary because output
17201815
* states are constant.
@@ -1734,8 +1829,16 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
17341829
dev_dbg(dev, "%s state changed: %u->%u\n", pin->label,
17351830
pin->pin_state, state);
17361831
pin->pin_state = state;
1737-
dpll_pin_change_ntf(pin->dpll_pin);
1832+
pin_changed = true;
17381833
}
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);
17391842
}
17401843
}
17411844

drivers/dpll/zl3073x/dpll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
* @id: DPLL index
1616
* @refsel_mode: reference selection mode
1717
* @forced_ref: selected reference in forced reference lock mode
18+
* @check_count: periodic check counter
1819
* @dpll_dev: pointer to registered DPLL device
1920
* @lock_status: last saved DPLL lock status
2021
* @pins: list of pins
@@ -25,6 +26,7 @@ struct zl3073x_dpll {
2526
u8 id;
2627
u8 refsel_mode;
2728
u8 forced_ref;
29+
u8 check_count;
2830
struct dpll_device *dpll_dev;
2931
enum dpll_lock_status lock_status;
3032
struct list_head pins;

drivers/dpll/zl3073x/regs.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@
9494
#define ZL_DPLL_REFSEL_STATUS_STATE GENMASK(6, 4)
9595
#define ZL_DPLL_REFSEL_STATUS_STATE_LOCK 4
9696

97+
/**********************
98+
* Register Page 4, Ref
99+
**********************/
100+
101+
#define ZL_REG_REF_PHASE_ERR_READ_RQST ZL_REG(4, 0x0f, 1)
102+
#define ZL_REF_PHASE_ERR_READ_RQST_RD BIT(0)
103+
97104
/***********************
98105
* Register Page 5, DPLL
99106
***********************/
@@ -108,6 +115,15 @@
108115
#define ZL_DPLL_MODE_REFSEL_MODE_NCO 4
109116
#define ZL_DPLL_MODE_REFSEL_REF GENMASK(7, 4)
110117

118+
#define ZL_REG_DPLL_MEAS_CTRL ZL_REG(5, 0x50, 1)
119+
#define ZL_DPLL_MEAS_CTRL_EN BIT(0)
120+
#define ZL_DPLL_MEAS_CTRL_AVG_FACTOR GENMASK(7, 4)
121+
122+
#define ZL_REG_DPLL_PHASE_ERR_READ_MASK ZL_REG(5, 0x54, 1)
123+
124+
#define ZL_REG_DPLL_PHASE_ERR_DATA(_idx) \
125+
ZL_REG_IDX(_idx, 5, 0x55, 6, ZL3073X_MAX_CHANNELS, 6)
126+
111127
/***********************************
112128
* Register Page 9, Synth and Output
113129
***********************************/

0 commit comments

Comments
 (0)