[PATCH net-next 5/5] dpll: zl3073x: add ref-sync pair support

Ivan Vecera posted 5 patches 2 weeks, 3 days ago
There is a newer version of this series
[PATCH net-next 5/5] dpll: zl3073x: add ref-sync pair support
Posted by Ivan Vecera 2 weeks, 3 days ago
Add support for ref-sync pair registration using the 'ref-sync-sources'
phandle property from device tree. A ref-sync pair consists of a clock
reference and a low-frequency sync signal where the DPLL locks to the
clock reference but phase-aligns to the sync reference.

The implementation:
- Stores fwnode handle in zl3073x_dpll_pin during pin registration
- Adds ref_sync_get/set callbacks to read and write the sync control
  mode and pair registers
- Validates ref-sync frequency constraints: sync signal must be 8 kHz
  or less, clock reference must be 1 kHz or more and higher than sync
- Excludes sync source from automatic reference selection by setting
  its priority to NONE on connect; on disconnect the priority is left
  as NONE and the user must explicitly make the pin selectable again
- Iterates ref-sync-sources phandles to register declared pairings
  via dpll_pin_ref_sync_pair_add()

Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
 drivers/dpll/zl3073x/dpll.c | 207 +++++++++++++++++++++++++++++++++++-
 1 file changed, 206 insertions(+), 1 deletion(-)

diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 276f0a92db0b1..8010e2635f641 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/netlink.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/sprintf.h>
 
@@ -30,6 +31,7 @@
  * @dpll: DPLL the pin is registered to
  * @dpll_pin: pointer to registered dpll_pin
  * @tracker: tracking object for the acquired reference
+ * @fwnode: firmware node handle
  * @label: package label
  * @dir: pin direction
  * @id: pin id
@@ -45,6 +47,7 @@ struct zl3073x_dpll_pin {
 	struct zl3073x_dpll	*dpll;
 	struct dpll_pin		*dpll_pin;
 	dpll_tracker		tracker;
+	struct fwnode_handle	*fwnode;
 	char			label[8];
 	enum dpll_pin_direction	dir;
 	u8			id;
@@ -184,6 +187,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
 	return zl3073x_ref_state_set(zldev, ref_id, &ref);
 }
 
+static int
+zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin,
+				    void *pin_priv,
+				    const struct dpll_pin *ref_sync_pin,
+				    void *ref_sync_pin_priv,
+				    enum dpll_pin_state *state,
+				    struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	struct zl3073x_dpll *zldpll = pin->dpll;
+	struct zl3073x_dev *zldev = zldpll->dev;
+	const struct zl3073x_ref *ref;
+	u8 ref_id, mode, pair;
+
+	ref_id = zl3073x_input_pin_ref_get(pin->id);
+	ref = zl3073x_ref_state_get(zldev, ref_id);
+	mode = zl3073x_ref_sync_mode_get(ref);
+	pair = zl3073x_ref_sync_pair_get(ref);
+
+	if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR &&
+	    pair == zl3073x_input_pin_ref_get(sync_pin->id))
+		*state = DPLL_PIN_STATE_CONNECTED;
+	else
+		*state = DPLL_PIN_STATE_DISCONNECTED;
+
+	return 0;
+}
+
+static int
+zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
+				    void *pin_priv,
+				    const struct dpll_pin *ref_sync_pin,
+				    void *ref_sync_pin_priv,
+				    const enum dpll_pin_state state,
+				    struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	struct zl3073x_dpll *zldpll = pin->dpll;
+	struct zl3073x_dev *zldev = zldpll->dev;
+	u8 mode, ref_id, sync_ref_id;
+	struct zl3073x_chan chan;
+	struct zl3073x_ref ref;
+	int rc;
+
+	ref_id = zl3073x_input_pin_ref_get(pin->id);
+	sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id);
+	ref = *zl3073x_ref_state_get(zldev, ref_id);
+
+	if (state == DPLL_PIN_STATE_CONNECTED) {
+		const struct zl3073x_ref *sync_ref;
+		u32 ref_freq, sync_freq;
+
+		sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id);
+		ref_freq = zl3073x_ref_freq_get(&ref);
+		sync_freq = zl3073x_ref_freq_get(sync_ref);
+
+		/* Sync signal must be 8 kHz or less and clock reference
+		 * must be 1 kHz or more and higher than the sync signal.
+		 */
+		if (sync_freq > 8000) {
+			NL_SET_ERR_MSG(extack,
+				       "sync frequency must be 8 kHz or less");
+			return -EINVAL;
+		}
+		if (ref_freq < 1000) {
+			NL_SET_ERR_MSG(extack,
+				       "clock frequency must be 1 kHz or more");
+			return -EINVAL;
+		}
+		if (ref_freq <= sync_freq) {
+			NL_SET_ERR_MSG(extack,
+				       "clock frequency must be higher than sync frequency");
+			return -EINVAL;
+		}
+
+		zl3073x_ref_sync_pair_set(&ref, sync_ref_id);
+		mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR;
+	} else {
+		mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
+	}
+
+	zl3073x_ref_sync_mode_set(&ref, mode);
+
+	rc = zl3073x_ref_state_set(zldev, ref_id, &ref);
+	if (rc)
+		return rc;
+
+	/* Exclude sync source from automatic reference selection by setting
+	 * its priority to NONE. On disconnect the priority is left as NONE
+	 * and the user must explicitly make the pin selectable again.
+	 */
+	if (state == DPLL_PIN_STATE_CONNECTED) {
+		chan = *zl3073x_chan_state_get(zldev, zldpll->id);
+		zl3073x_chan_ref_prio_set(&chan, sync_ref_id,
+					  ZL_DPLL_REF_PRIO_NONE);
+		return zl3073x_chan_state_set(zldev, zldpll->id, &chan);
+	}
+
+	return 0;
+}
+
 static int
 zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
 			       const struct dpll_device *dpll, void *dpll_priv,
@@ -1100,6 +1206,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
 	.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
 	.prio_get = zl3073x_dpll_input_pin_prio_get,
 	.prio_set = zl3073x_dpll_input_pin_prio_set,
+	.ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get,
+	.ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set,
 	.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
 	.state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set,
 };
@@ -1190,8 +1298,11 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
 	if (IS_ERR(props))
 		return PTR_ERR(props);
 
-	/* Save package label, esync capability and phase adjust granularity */
+	/* Save package label, fwnode, esync capability and phase adjust
+	 * granularity.
+	 */
 	strscpy(pin->label, props->package_label);
+	pin->fwnode = fwnode_handle_get(props->fwnode);
 	pin->esync_control = props->esync_control;
 	pin->phase_gran = props->dpll_props.phase_gran;
 
@@ -1236,6 +1347,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
 	dpll_pin_put(pin->dpll_pin, &pin->tracker);
 	pin->dpll_pin = NULL;
 err_pin_get:
+	fwnode_handle_put(pin->fwnode);
+	pin->fwnode = NULL;
 	zl3073x_pin_props_put(props);
 
 	return rc;
@@ -1265,6 +1378,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin)
 
 	dpll_pin_put(pin->dpll_pin, &pin->tracker);
 	pin->dpll_pin = NULL;
+
+	fwnode_handle_put(pin->fwnode);
+	pin->fwnode = NULL;
 }
 
 /**
@@ -1735,6 +1851,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll)
 	kfree(zldpll);
 }
 
+/**
+ * zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a pin
+ * @pin: pointer to zl3073x_dpll_pin structure
+ *
+ * Iterates 'ref-sync-sources' phandles in the pin's firmware node and
+ * registers each declared pairing.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin)
+{
+	struct zl3073x_dev *zldev = pin->dpll->dev;
+	struct fwnode_handle *fwnode;
+	struct dpll_pin *sync_pin;
+	dpll_tracker tracker;
+	int n, rc;
+
+	for (n = 0; ; n++) {
+		/* Get n'th ref-sync source */
+		fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources",
+					       n);
+		if (IS_ERR(fwnode)) {
+			rc = PTR_ERR(fwnode);
+			break;
+		}
+
+		/* Find associated dpll pin */
+		sync_pin = fwnode_dpll_pin_find(fwnode, &tracker);
+		fwnode_handle_put(fwnode);
+		if (!sync_pin) {
+			dev_warn(zldev->dev, "%s: ref-sync source %d not found",
+				 pin->label, n);
+			continue;
+		}
+
+		/* Register new ref-sync pair */
+		rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin);
+		dpll_pin_put(sync_pin, &tracker);
+
+		/* -EBUSY means pairing already exists from another DPLL's
+		 * registration.
+		 */
+		if (rc && rc != -EBUSY) {
+			dev_err(zldev->dev,
+				"%s: failed to add ref-sync source %d: %pe",
+				pin->label, n, ERR_PTR(rc));
+			break;
+		}
+	}
+
+	return rc != -ENOENT ? rc : 0;
+}
+
+/**
+ * zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a DPLL
+ * @zldpll: pointer to zl3073x_dpll structure
+ *
+ * Iterates all registered input pins of the given DPLL and establishes
+ * ref_sync pairings declared by 'ref-sync-sources' phandles in the
+ * device tree.
+ *
+ * Return: 0 on success, <0 on error
+ */
+static int
+zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll)
+{
+	struct zl3073x_dpll_pin *pin;
+	int rc;
+
+	list_for_each_entry(pin, &zldpll->pins, list) {
+		if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode)
+			continue;
+
+		rc = zl3073x_dpll_ref_sync_pair_register(pin);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
 /**
  * zl3073x_dpll_register - register DPLL device and all its pins
  * @zldpll: pointer to zl3073x_dpll structure
@@ -1758,6 +1956,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll)
 		return rc;
 	}
 
+	rc = zl3073x_dpll_ref_sync_pairs_register(zldpll);
+	if (rc) {
+		zl3073x_dpll_pins_unregister(zldpll);
+		zl3073x_dpll_device_unregister(zldpll);
+		return rc;
+	}
+
 	return 0;
 }
 
-- 
2.52.0
Re: [PATCH net-next 5/5] dpll: zl3073x: add ref-sync pair support
Posted by Petr Oros 1 week, 2 days ago
> Add support for ref-sync pair registration using the 'ref-sync-sources'
> phandle property from device tree. A ref-sync pair consists of a clock
> reference and a low-frequency sync signal where the DPLL locks to the
> clock reference but phase-aligns to the sync reference.
>
> The implementation:
> - Stores fwnode handle in zl3073x_dpll_pin during pin registration
> - Adds ref_sync_get/set callbacks to read and write the sync control
>    mode and pair registers
> - Validates ref-sync frequency constraints: sync signal must be 8 kHz
>    or less, clock reference must be 1 kHz or more and higher than sync
> - Excludes sync source from automatic reference selection by setting
>    its priority to NONE on connect; on disconnect the priority is left
>    as NONE and the user must explicitly make the pin selectable again
> - Iterates ref-sync-sources phandles to register declared pairings
>    via dpll_pin_ref_sync_pair_add()
>
> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
> ---
>   drivers/dpll/zl3073x/dpll.c | 207 +++++++++++++++++++++++++++++++++++-
>   1 file changed, 206 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
> index 276f0a92db0b1..8010e2635f641 100644
> --- a/drivers/dpll/zl3073x/dpll.c
> +++ b/drivers/dpll/zl3073x/dpll.c
> @@ -13,6 +13,7 @@
>   #include <linux/module.h>
>   #include <linux/netlink.h>
>   #include <linux/platform_device.h>
> +#include <linux/property.h>
>   #include <linux/slab.h>
>   #include <linux/sprintf.h>
>   
> @@ -30,6 +31,7 @@
>    * @dpll: DPLL the pin is registered to
>    * @dpll_pin: pointer to registered dpll_pin
>    * @tracker: tracking object for the acquired reference
> + * @fwnode: firmware node handle
>    * @label: package label
>    * @dir: pin direction
>    * @id: pin id
> @@ -45,6 +47,7 @@ struct zl3073x_dpll_pin {
>   	struct zl3073x_dpll	*dpll;
>   	struct dpll_pin		*dpll_pin;
>   	dpll_tracker		tracker;
> +	struct fwnode_handle	*fwnode;
>   	char			label[8];
>   	enum dpll_pin_direction	dir;
>   	u8			id;
> @@ -184,6 +187,109 @@ zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
>   	return zl3073x_ref_state_set(zldev, ref_id, &ref);
>   }
>   
> +static int
> +zl3073x_dpll_input_pin_ref_sync_get(const struct dpll_pin *dpll_pin,
> +				    void *pin_priv,
> +				    const struct dpll_pin *ref_sync_pin,
> +				    void *ref_sync_pin_priv,
> +				    enum dpll_pin_state *state,
> +				    struct netlink_ext_ack *extack)
> +{
> +	struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
> +	struct zl3073x_dpll_pin *pin = pin_priv;
> +	struct zl3073x_dpll *zldpll = pin->dpll;
> +	struct zl3073x_dev *zldev = zldpll->dev;
> +	const struct zl3073x_ref *ref;
> +	u8 ref_id, mode, pair;
> +
> +	ref_id = zl3073x_input_pin_ref_get(pin->id);
> +	ref = zl3073x_ref_state_get(zldev, ref_id);
> +	mode = zl3073x_ref_sync_mode_get(ref);
> +	pair = zl3073x_ref_sync_pair_get(ref);
> +
> +	if (mode == ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR &&
> +	    pair == zl3073x_input_pin_ref_get(sync_pin->id))
> +		*state = DPLL_PIN_STATE_CONNECTED;
> +	else
> +		*state = DPLL_PIN_STATE_DISCONNECTED;
> +
> +	return 0;
> +}
> +
> +static int
> +zl3073x_dpll_input_pin_ref_sync_set(const struct dpll_pin *dpll_pin,
> +				    void *pin_priv,
> +				    const struct dpll_pin *ref_sync_pin,
> +				    void *ref_sync_pin_priv,
> +				    const enum dpll_pin_state state,
> +				    struct netlink_ext_ack *extack)
> +{
> +	struct zl3073x_dpll_pin *sync_pin = ref_sync_pin_priv;
> +	struct zl3073x_dpll_pin *pin = pin_priv;
> +	struct zl3073x_dpll *zldpll = pin->dpll;
> +	struct zl3073x_dev *zldev = zldpll->dev;
> +	u8 mode, ref_id, sync_ref_id;
> +	struct zl3073x_chan chan;
> +	struct zl3073x_ref ref;
> +	int rc;
> +
> +	ref_id = zl3073x_input_pin_ref_get(pin->id);
> +	sync_ref_id = zl3073x_input_pin_ref_get(sync_pin->id);
> +	ref = *zl3073x_ref_state_get(zldev, ref_id);
> +
> +	if (state == DPLL_PIN_STATE_CONNECTED) {
> +		const struct zl3073x_ref *sync_ref;
> +		u32 ref_freq, sync_freq;
> +
> +		sync_ref = zl3073x_ref_state_get(zldev, sync_ref_id);
> +		ref_freq = zl3073x_ref_freq_get(&ref);
> +		sync_freq = zl3073x_ref_freq_get(sync_ref);
> +
> +		/* Sync signal must be 8 kHz or less and clock reference
> +		 * must be 1 kHz or more and higher than the sync signal.
> +		 */
> +		if (sync_freq > 8000) {
> +			NL_SET_ERR_MSG(extack,
> +				       "sync frequency must be 8 kHz or less");
> +			return -EINVAL;
> +		}
> +		if (ref_freq < 1000) {
> +			NL_SET_ERR_MSG(extack,
> +				       "clock frequency must be 1 kHz or more");
> +			return -EINVAL;
> +		}
> +		if (ref_freq <= sync_freq) {
> +			NL_SET_ERR_MSG(extack,
> +				       "clock frequency must be higher than sync frequency");
> +			return -EINVAL;
> +		}
> +
> +		zl3073x_ref_sync_pair_set(&ref, sync_ref_id);
> +		mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR;
> +	} else {
> +		mode = ZL_REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
> +	}
> +
> +	zl3073x_ref_sync_mode_set(&ref, mode);
> +
> +	rc = zl3073x_ref_state_set(zldev, ref_id, &ref);
> +	if (rc)
> +		return rc;
> +
> +	/* Exclude sync source from automatic reference selection by setting
> +	 * its priority to NONE. On disconnect the priority is left as NONE
> +	 * and the user must explicitly make the pin selectable again.
> +	 */
> +	if (state == DPLL_PIN_STATE_CONNECTED) {
> +		chan = *zl3073x_chan_state_get(zldev, zldpll->id);
> +		zl3073x_chan_ref_prio_set(&chan, sync_ref_id,
> +					  ZL_DPLL_REF_PRIO_NONE);
> +		return zl3073x_chan_state_set(zldev, zldpll->id, &chan);
> +	}
> +
> +	return 0;
> +}
> +
>   static int
>   zl3073x_dpll_input_pin_ffo_get(const struct dpll_pin *dpll_pin, void *pin_priv,
>   			       const struct dpll_device *dpll, void *dpll_priv,
> @@ -1100,6 +1206,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
>   	.phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set,
>   	.prio_get = zl3073x_dpll_input_pin_prio_get,
>   	.prio_set = zl3073x_dpll_input_pin_prio_set,
> +	.ref_sync_get = zl3073x_dpll_input_pin_ref_sync_get,
> +	.ref_sync_set = zl3073x_dpll_input_pin_ref_sync_set,
>   	.state_on_dpll_get = zl3073x_dpll_input_pin_state_on_dpll_get,
>   	.state_on_dpll_set = zl3073x_dpll_input_pin_state_on_dpll_set,
>   };
> @@ -1190,8 +1298,11 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
>   	if (IS_ERR(props))
>   		return PTR_ERR(props);
>   
> -	/* Save package label, esync capability and phase adjust granularity */
> +	/* Save package label, fwnode, esync capability and phase adjust
> +	 * granularity.
> +	 */
>   	strscpy(pin->label, props->package_label);
> +	pin->fwnode = fwnode_handle_get(props->fwnode);
>   	pin->esync_control = props->esync_control;
>   	pin->phase_gran = props->dpll_props.phase_gran;
>   
> @@ -1236,6 +1347,8 @@ zl3073x_dpll_pin_register(struct zl3073x_dpll_pin *pin, u32 index)
>   	dpll_pin_put(pin->dpll_pin, &pin->tracker);
>   	pin->dpll_pin = NULL;
>   err_pin_get:
> +	fwnode_handle_put(pin->fwnode);
> +	pin->fwnode = NULL;
>   	zl3073x_pin_props_put(props);
>   
>   	return rc;
> @@ -1265,6 +1378,9 @@ zl3073x_dpll_pin_unregister(struct zl3073x_dpll_pin *pin)
>   
>   	dpll_pin_put(pin->dpll_pin, &pin->tracker);
>   	pin->dpll_pin = NULL;
> +
> +	fwnode_handle_put(pin->fwnode);
> +	pin->fwnode = NULL;
>   }
>   
>   /**
> @@ -1735,6 +1851,88 @@ zl3073x_dpll_free(struct zl3073x_dpll *zldpll)
>   	kfree(zldpll);
>   }
>   
> +/**
> + * zl3073x_dpll_ref_sync_pair_register - register ref_sync pairs for a pin
> + * @pin: pointer to zl3073x_dpll_pin structure
> + *
> + * Iterates 'ref-sync-sources' phandles in the pin's firmware node and
> + * registers each declared pairing.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int
> +zl3073x_dpll_ref_sync_pair_register(struct zl3073x_dpll_pin *pin)
> +{
> +	struct zl3073x_dev *zldev = pin->dpll->dev;
> +	struct fwnode_handle *fwnode;
> +	struct dpll_pin *sync_pin;
> +	dpll_tracker tracker;
> +	int n, rc;
> +
> +	for (n = 0; ; n++) {
> +		/* Get n'th ref-sync source */
> +		fwnode = fwnode_find_reference(pin->fwnode, "ref-sync-sources",
> +					       n);
> +		if (IS_ERR(fwnode)) {
> +			rc = PTR_ERR(fwnode);
> +			break;
> +		}
> +
> +		/* Find associated dpll pin */
> +		sync_pin = fwnode_dpll_pin_find(fwnode, &tracker);
> +		fwnode_handle_put(fwnode);
> +		if (!sync_pin) {
> +			dev_warn(zldev->dev, "%s: ref-sync source %d not found",
> +				 pin->label, n);
> +			continue;
> +		}
> +
> +		/* Register new ref-sync pair */
> +		rc = dpll_pin_ref_sync_pair_add(pin->dpll_pin, sync_pin);
> +		dpll_pin_put(sync_pin, &tracker);
> +
> +		/* -EBUSY means pairing already exists from another DPLL's
> +		 * registration.
> +		 */
> +		if (rc && rc != -EBUSY) {
> +			dev_err(zldev->dev,
> +				"%s: failed to add ref-sync source %d: %pe",
> +				pin->label, n, ERR_PTR(rc));
> +			break;
> +		}
> +	}
> +
> +	return rc != -ENOENT ? rc : 0;
> +}
> +
> +/**
> + * zl3073x_dpll_ref_sync_pairs_register - register ref_sync pairs for a DPLL
> + * @zldpll: pointer to zl3073x_dpll structure
> + *
> + * Iterates all registered input pins of the given DPLL and establishes
> + * ref_sync pairings declared by 'ref-sync-sources' phandles in the
> + * device tree.
> + *
> + * Return: 0 on success, <0 on error
> + */
> +static int
> +zl3073x_dpll_ref_sync_pairs_register(struct zl3073x_dpll *zldpll)
> +{
> +	struct zl3073x_dpll_pin *pin;
> +	int rc;
> +
> +	list_for_each_entry(pin, &zldpll->pins, list) {
> +		if (!zl3073x_dpll_is_input_pin(pin) || !pin->fwnode)
> +			continue;
> +
> +		rc = zl3073x_dpll_ref_sync_pair_register(pin);
> +		if (rc)
> +			return rc;
> +	}
> +
> +	return 0;
> +}
> +
>   /**
>    * zl3073x_dpll_register - register DPLL device and all its pins
>    * @zldpll: pointer to zl3073x_dpll structure
> @@ -1758,6 +1956,13 @@ zl3073x_dpll_register(struct zl3073x_dpll *zldpll)
>   		return rc;
>   	}
>   
> +	rc = zl3073x_dpll_ref_sync_pairs_register(zldpll);
> +	if (rc) {
> +		zl3073x_dpll_pins_unregister(zldpll);
> +		zl3073x_dpll_device_unregister(zldpll);
> +		return rc;
> +	}
> +
>   	return 0;
>   }
>   

LGTM.


Reviewed-by: Petr Oros <poros@redhat.com>