Skip to content

Commit e0c7e31

Browse files
author
Paolo Abeni
committed
Merge branch 'dpll-zl3073x-add-misc-features'
Ivan Vecera says: ==================== dpll: zl3073x: Add misc features Add several new features missing in initial submission: * Embedded sync for both pin types * Phase offset reporting for connected input pin * Selectable phase offset monitoring (aka all inputs phase monitor) * Phase adjustments for both pin types * Fractional frequency offset reporting for input pins Everything was tested on Microchip EVB-LAN9668 EDS2 development board. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 44eb62e + 904c99e commit e0c7e31

File tree

5 files changed

+1062
-2
lines changed

5 files changed

+1062
-2
lines changed

drivers/dpll/zl3073x/core.c

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,12 +669,137 @@ 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+
* @channel: DPLL channel number or -1
676+
*
677+
* The function asks device to update phase offsets latch registers with
678+
* the latest measured values. There are 2 sets of latch registers:
679+
*
680+
* 1) Up to 5 DPLL-to-connected-ref registers that contain phase offset
681+
* values between particular DPLL channel and its *connected* input
682+
* reference.
683+
*
684+
* 2) 10 selected-DPLL-to-all-ref registers that contain phase offset values
685+
* between selected DPLL channel and all input references.
686+
*
687+
* If the caller is interested in 2) then it has to pass DPLL channel number
688+
* in @channel parameter. If it is interested only in 1) then it should pass
689+
* @channel parameter with value of -1.
690+
*
691+
* Return: 0 on success, <0 on error
692+
*/
693+
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel)
694+
{
695+
int rc;
696+
697+
/* Per datasheet we have to wait for 'dpll_ref_phase_err_rqst_rd'
698+
* to be zero to ensure that the measured data are coherent.
699+
*/
700+
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
701+
ZL_REF_PHASE_ERR_READ_RQST_RD);
702+
if (rc)
703+
return rc;
704+
705+
/* Select DPLL channel if it is specified */
706+
if (channel != -1) {
707+
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_IDX, channel);
708+
if (rc)
709+
return rc;
710+
}
711+
712+
/* Request to update phase offsets measurement values */
713+
rc = zl3073x_write_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
714+
ZL_REF_PHASE_ERR_READ_RQST_RD);
715+
if (rc)
716+
return rc;
717+
718+
/* Wait for finish */
719+
return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_PHASE_ERR_READ_RQST,
720+
ZL_REF_PHASE_ERR_READ_RQST_RD);
721+
}
722+
723+
/**
724+
* zl3073x_ref_ffo_update - update reference fractional frequency offsets
725+
* @zldev: pointer to zl3073x_dev structure
726+
*
727+
* The function asks device to update fractional frequency offsets latch
728+
* registers the latest measured values, reads and stores them into
729+
*
730+
* Return: 0 on success, <0 on error
731+
*/
732+
static int
733+
zl3073x_ref_ffo_update(struct zl3073x_dev *zldev)
734+
{
735+
int i, rc;
736+
737+
/* Per datasheet we have to wait for 'ref_freq_meas_ctrl' to be zero
738+
* to ensure that the measured data are coherent.
739+
*/
740+
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
741+
ZL_REF_FREQ_MEAS_CTRL);
742+
if (rc)
743+
return rc;
744+
745+
/* Select all references for measurement */
746+
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_MASK_3_0,
747+
GENMASK(7, 0)); /* REF0P..REF3N */
748+
if (rc)
749+
return rc;
750+
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_MASK_4,
751+
GENMASK(1, 0)); /* REF4P..REF4N */
752+
if (rc)
753+
return rc;
754+
755+
/* Request frequency offset measurement */
756+
rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
757+
ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF);
758+
if (rc)
759+
return rc;
760+
761+
/* Wait for finish */
762+
rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL,
763+
ZL_REF_FREQ_MEAS_CTRL);
764+
if (rc)
765+
return rc;
766+
767+
/* Read DPLL-to-REFx frequency offset measurements */
768+
for (i = 0; i < ZL3073X_NUM_REFS; i++) {
769+
s32 value;
770+
771+
/* Read value stored in units of 2^-32 signed */
772+
rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value);
773+
if (rc)
774+
return rc;
775+
776+
/* Convert to ppm -> ffo = (10^6 * value) / 2^32 */
777+
zldev->ref[i].ffo = mul_s64_u64_shr(value, 1000000, 32);
778+
}
779+
780+
return 0;
781+
}
782+
672783
static void
673784
zl3073x_dev_periodic_work(struct kthread_work *work)
674785
{
675786
struct zl3073x_dev *zldev = container_of(work, struct zl3073x_dev,
676787
work.work);
677788
struct zl3073x_dpll *zldpll;
789+
int rc;
790+
791+
/* Update DPLL-to-connected-ref phase offsets registers */
792+
rc = zl3073x_ref_phase_offsets_update(zldev, -1);
793+
if (rc)
794+
dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
795+
ERR_PTR(rc));
796+
797+
/* Update references' fractional frequency offsets */
798+
rc = zl3073x_ref_ffo_update(zldev);
799+
if (rc)
800+
dev_warn(zldev->dev,
801+
"Failed to update fractional frequency offsets: %pe\n",
802+
ERR_PTR(rc));
678803

679804
list_for_each_entry(zldpll, &zldev->dplls, list)
680805
zl3073x_dpll_changes_check(zldpll);
@@ -767,6 +892,46 @@ zl3073x_devm_dpll_init(struct zl3073x_dev *zldev, u8 num_dplls)
767892
return rc;
768893
}
769894

895+
/**
896+
* zl3073x_dev_phase_meas_setup - setup phase offset measurement
897+
* @zldev: pointer to zl3073x_dev structure
898+
* @num_channels: number of DPLL channels
899+
*
900+
* Enable phase offset measurement block, set measurement averaging factor
901+
* and enable DPLL-to-its-ref phase measurement for all DPLLs.
902+
*
903+
* Returns: 0 on success, <0 on error
904+
*/
905+
static int
906+
zl3073x_dev_phase_meas_setup(struct zl3073x_dev *zldev, int num_channels)
907+
{
908+
u8 dpll_meas_ctrl, mask;
909+
int i, rc;
910+
911+
/* Read DPLL phase measurement control register */
912+
rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, &dpll_meas_ctrl);
913+
if (rc)
914+
return rc;
915+
916+
/* Setup phase measurement averaging factor */
917+
dpll_meas_ctrl &= ~ZL_DPLL_MEAS_CTRL_AVG_FACTOR;
918+
dpll_meas_ctrl |= FIELD_PREP(ZL_DPLL_MEAS_CTRL_AVG_FACTOR, 3);
919+
920+
/* Enable DPLL measurement block */
921+
dpll_meas_ctrl |= ZL_DPLL_MEAS_CTRL_EN;
922+
923+
/* Update phase measurement control register */
924+
rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MEAS_CTRL, dpll_meas_ctrl);
925+
if (rc)
926+
return rc;
927+
928+
/* Enable DPLL-to-connected-ref measurement for each channel */
929+
for (i = 0, mask = 0; i < num_channels; i++)
930+
mask |= BIT(i);
931+
932+
return zl3073x_write_u8(zldev, ZL_REG_DPLL_PHASE_ERR_READ_MASK, mask);
933+
}
934+
770935
/**
771936
* zl3073x_dev_probe - initialize zl3073x device
772937
* @zldev: pointer to zl3073x device
@@ -839,6 +1004,12 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
8391004
if (rc)
8401005
return rc;
8411006

1007+
/* Setup phase offset measurement block */
1008+
rc = zl3073x_dev_phase_meas_setup(zldev, chip_info->num_channels);
1009+
if (rc)
1010+
return dev_err_probe(zldev->dev, rc,
1011+
"Failed to setup phase measurement\n");
1012+
8421013
/* Register DPLL channels */
8431014
rc = zl3073x_devm_dpll_init(zldev, chip_info->num_channels);
8441015
if (rc)

drivers/dpll/zl3073x/core.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ struct zl3073x_dpll;
3030
* struct zl3073x_ref - input reference invariant info
3131
* @enabled: input reference is enabled or disabled
3232
* @diff: true if input reference is differential
33+
* @ffo: current fractional frequency offset
3334
*/
3435
struct zl3073x_ref {
3536
bool enabled;
3637
bool diff;
38+
s64 ffo;
3739
};
3840

3941
/**
@@ -130,6 +132,7 @@ int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
130132
*****************/
131133

132134
int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult);
135+
int zl3073x_ref_phase_offsets_update(struct zl3073x_dev *zldev, int channel);
133136

134137
static inline bool
135138
zl3073x_is_n_pin(u8 id)
@@ -169,6 +172,19 @@ zl3073x_output_pin_out_get(u8 id)
169172
return id / 2;
170173
}
171174

175+
/**
176+
* zl3073x_ref_ffo_get - get current fractional frequency offset
177+
* @zldev: pointer to zl3073x device
178+
* @index: input reference index
179+
*
180+
* Return: the latest measured fractional frequency offset
181+
*/
182+
static inline s64
183+
zl3073x_ref_ffo_get(struct zl3073x_dev *zldev, u8 index)
184+
{
185+
return zldev->ref[index].ffo;
186+
}
187+
172188
/**
173189
* zl3073x_ref_is_diff - check if the given input reference is differential
174190
* @zldev: pointer to zl3073x device

0 commit comments

Comments
 (0)