Commit c1224569 authored by Ivan Vecera's avatar Ivan Vecera Committed by Paolo Abeni
Browse files

dpll: zl3073x: make frequency monitor a per-device attribute



The frequency monitoring feature uses shared hardware registers
that measure input reference frequencies independently of
individual DPLL channels. However, the freq_monitor flag was
incorrectly placed in the per-DPLL structure, causing each
channel to track its own enable/disable state independently.

Since the DPLL core calls measured_freq_get() only for the first
pin registration, the measured_freq_check() in the periodic worker
was gated by the per-DPLL freq_monitor flag of whichever channel
happens to be checked. If the first DPLL channel had frequency
monitoring disabled while another had it enabled, measurements
were never reported.

Move freq_monitor from struct zl3073x_dpll to struct zl3073x_dev
so all DPLL channels share a single flag, matching the hardware
behavior. Update freq_monitor_set() to notify other DPLL devices
about the change (like phase_offset_avg_factor_set() already does)
and remove the mode-dependent guard in zl3073x_dpll_changes_check()
since all input pin monitoring (pin state, phase offset, FFO, and
measured frequency) works correctly in all DPLL modes.

Fixes: bfc923b6 ("dpll: zl3073x: implement frequency monitoring")
Signed-off-by: default avatarIvan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20260526074525.1451008-4-ivecera@redhat.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent d733f519
Loading
Loading
Loading
Loading
+8 −11
Original line number Diff line number Diff line
@@ -762,18 +762,15 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
		dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n",
			 ERR_PTR(rc));

	/* Update measured input reference frequencies if any DPLL has
	 * frequency monitoring enabled.
	/* Update measured input reference frequencies if frequency
	 * monitoring is enabled.
	 */
	list_for_each_entry(zldpll, &zldev->dplls, list) {
		if (zldpll->freq_monitor) {
	if (zldev->freq_monitor) {
		rc = zl3073x_ref_freq_meas_update(zldev);
		if (rc)
			dev_warn(zldev->dev,
				 "Failed to update measured frequencies: %pe\n",
				 ERR_PTR(rc));
			break;
		}
	}

	/* Update references' fractional frequency offsets */
+3 −1
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ struct zl3073x_chip_info {
 * @work: periodic work
 * @clock_id: clock id of the device
 * @phase_avg_factor: phase offset measurement averaging factor
 * @freq_monitor: is frequency monitor enabled
 */
struct zl3073x_dev {
	struct device			*dev;
@@ -77,9 +78,10 @@ struct zl3073x_dev {
	struct kthread_worker		*kworker;
	struct kthread_delayed_work	work;

	/* Devlink parameters */
	/* Per-chip parameters */
	u64			clock_id;
	u8			phase_avg_factor;
	bool			freq_monitor;
};

extern const struct regmap_config zl3073x_regmap_config;
+14 −15
Original line number Diff line number Diff line
@@ -1212,7 +1212,7 @@ zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll,
{
	struct zl3073x_dpll *zldpll = dpll_priv;

	if (zldpll->freq_monitor)
	if (zldpll->dev->freq_monitor)
		*state = DPLL_FEATURE_STATE_ENABLE;
	else
		*state = DPLL_FEATURE_STATE_DISABLE;
@@ -1226,9 +1226,19 @@ zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll,
			      enum dpll_feature_state state,
			      struct netlink_ext_ack *extack)
{
	struct zl3073x_dpll *zldpll = dpll_priv;
	struct zl3073x_dpll *item, *zldpll = dpll_priv;

	zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);
	zldpll->dev->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE);

	/* The frequency monitoring is common for all DPLL channels so after
	 * change we have to send a notification for other DPLL devices.
	 */
	list_for_each_entry(item, &zldpll->dev->dplls, list) {
		struct dpll_device *dpll_dev = READ_ONCE(item->dpll_dev);

		if (item != zldpll && dpll_dev)
			__dpll_device_change_ntf(dpll_dev);
	}

	return 0;
}
@@ -1745,7 +1755,7 @@ zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin)
	u8 ref_id;
	u32 freq;

	if (!zldpll->freq_monitor)
	if (!zldpll->dev->freq_monitor)
		return false;

	ref_id = zl3073x_input_pin_ref_get(pin->id);
@@ -1778,10 +1788,8 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
	struct zl3073x_dev *zldev = zldpll->dev;
	enum dpll_lock_status lock_status;
	struct device *dev = zldev->dev;
	const struct zl3073x_chan *chan;
	struct zl3073x_dpll_pin *pin;
	int rc;
	u8 mode;

	zldpll->check_count++;

@@ -1800,15 +1808,6 @@ zl3073x_dpll_changes_check(struct zl3073x_dpll *zldpll)
		dpll_device_change_ntf(zldpll->dpll_dev);
	}

	/* Input pin monitoring does make sense only in automatic
	 * or forced reference modes.
	 */
	chan = zl3073x_chan_state_get(zldev, zldpll->id);
	mode = zl3073x_chan_mode_get(chan);
	if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO &&
	    mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK)
		return;

	/* Update phase offset latch registers for this DPLL if the phase
	 * offset monitor feature is enabled.
	 */
+0 −2
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 * @id: DPLL index
 * @check_count: periodic check counter
 * @phase_monitor: is phase offset monitor enabled
 * @freq_monitor: is frequency monitor enabled
 * @ops: DPLL device operations for this instance
 * @dpll_dev: pointer to registered DPLL device
 * @tracker: tracking object for the acquired reference
@@ -28,7 +27,6 @@ struct zl3073x_dpll {
	u8				id;
	u8				check_count;
	bool				phase_monitor;
	bool				freq_monitor;
	struct dpll_device_ops		ops;
	struct dpll_device		*dpll_dev;
	dpll_tracker			tracker;