diff --git a/drivers/dpll/dpll_zl3073x.c b/drivers/dpll/dpll_zl3073x.c
index b1f38f000899b..e1d7f6d4c3d57 100644
--- a/drivers/dpll/dpll_zl3073x.c
+++ b/drivers/dpll/dpll_zl3073x.c
@@ -81,6 +81,14 @@ ZL3073X_REG16_DEF(ref_ratio_m,			0x509);
 ZL3073X_REG16_DEF(ref_ratio_n,			0x50b);
 ZL3073X_REG48_DEF(ref_phase_compensation,	0x528);
 
+ZL3073X_REG8_DEF(ref_sync_ctrl,			0x52e);
+#define REF_SYNC_CTRL_MODE			GENMASK(2, 0)
+#define REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF	0
+#define REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75	2
+
+ZL3073X_REG32_DEF(ref_esync_div,		0x530);
+#define REF_ESYNC_DIV_1HZ			0
+
 /*
  * Register Map Page 12, DPLL Mailbox
  */
@@ -94,10 +102,17 @@ ZL3073X_REG8_IDX_DEF(dpll_ref_prio,		0x652,
 /*
  * Register Map Page 14, Output Mailbox
  */
+ZL3073X_REG8_DEF(output_mode,			0x705);
+#define OUTPUT_MODE_CLOCK_TYPE			GENMASK(2, 0)
+#define OUTPUT_MODE_CLOCK_TYPE_NORMAL		0
+#define OUTPUT_MODE_CLOCK_TYPE_ESYNC		1
+
 ZL3073X_REG32_DEF(output_div,			0x70c);
 ZL3073X_REG32_DEF(output_width,			0x710);
-ZL3073X_REG32_DEF(output_ndiv_period,		0x714);
-ZL3073X_REG32_DEF(output_ndiv_width,		0x718);
+ZL3073X_REG32_DEF(output_esync_period,		0x714);
+ZL3073X_REG32_DEF(output_ndiv_period,		0x714); /* alias for previous */
+ZL3073X_REG32_DEF(output_esync_width,		0x718);
+ZL3073X_REG32_DEF(output_ndiv_width,		0x718); /* alias for previous */
 
 ZL3073X_REG32_DEF(output_phase_compensation,	0x720);
 
@@ -122,6 +137,7 @@ struct zl3073x_dpll_pin_info {
  * @index: index in zl3073x_dpll.pins array
  * @prio: pin priority <0, 14>
  * @selectable: pin is selectable in automatic mode
+ * @esync_control: embedded sync is controllable
  * @pin_state: last saved pin state
  * @phase_offset: last saved pin phase offset
  */
@@ -130,6 +146,7 @@ struct zl3073x_dpll_pin {
 	u8				index;
 	u8				prio;
 	bool				selectable;
+	bool				esync_control;
 	enum dpll_pin_state		pin_state;
 	s64				phase_offset;
 };
@@ -213,6 +230,13 @@ zl3073x_dpll_is_n_pin(struct zl3073x_dpll_pin *pin)
 	return zl3073x_is_n_pin(zl3073x_dpll_pin_index_get(pin));
 }
 
+/*
+ * Supported esync ranges for input and for output per output pair type
+ */
+static const struct dpll_pin_frequency esync_freq_ranges[] = {
+	DPLL_PIN_FREQUENCY_RANGE(0, 1),
+};
+
 /**
  * zl3073x_dpll_is_p_pin - check if the pin is P-pin
  * @pin: pin to check
@@ -352,6 +376,128 @@ zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dev *zldev, u8 ref_id,
 	return rc;
 }
 
+static int
+zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
+				 void *pin_priv,
+				 const struct dpll_device *dpll,
+				 void *dpll_priv,
+				 struct dpll_pin_esync *esync,
+				 struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll *zldpll = dpll_priv;
+	struct zl3073x_dev *zldev = zldpll->mfd;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	u8 sync_mode, ref_id, ref_sync_ctrl;
+	u32 esync_div;
+	u64 ref_freq;
+	int rc;
+
+	/* Take device lock */
+	guard(zl3073x)(zldev);
+
+	/* Get index of the pin */
+	ref_id = zl3073x_dpll_pin_index_get(pin);
+
+	/* Get reference frequency */
+	rc = zl3073x_dpll_input_ref_frequency_get(zldev, ref_id, &ref_freq);
+	if (rc)
+		return rc;
+
+	/* Get ref sync mode */
+	rc = zl3073x_read_ref_sync_ctrl(zldev, &ref_sync_ctrl);
+	if (rc)
+		return rc;
+
+	sync_mode = FIELD_GET(REF_SYNC_CTRL_MODE, ref_sync_ctrl);
+
+	/* Get esync divisor */
+	rc = zl3073x_read_ref_esync_div(zldev, &esync_div);
+	if (rc)
+		return rc;
+
+	switch (sync_mode) {
+	case REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75:
+		esync->freq = (esync_div == REF_ESYNC_DIV_1HZ) ? 1 : 0;
+		esync->pulse = 25;
+		break;
+	default:
+		esync->freq = 0;
+		esync->pulse = 50;
+		break;
+	}
+
+	/* If the pin supports esync control expose its range but only
+	 * if the current reference frequency is > 1 Hz.
+	 */
+	if (pin->esync_control && ref_freq > 1) {
+		esync->range = esync_freq_ranges;
+		esync->range_num = ARRAY_SIZE(esync_freq_ranges);
+	} else {
+		esync->range = NULL;
+		esync->range_num = 0;
+	}
+
+	return rc;
+}
+
+static int
+zl3073x_dpll_input_pin_esync_set(const struct dpll_pin *dpll_pin,
+				 void *pin_priv,
+				 const struct dpll_device *dpll,
+				 void *dpll_priv, u64 freq,
+				 struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll *zldpll = dpll_priv;
+	struct zl3073x_dev *zldev = zldpll->mfd;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	u8 ref_id, ref_sync_ctrl, sync_mode;
+	int rc;
+
+	/* Take device lock */
+	guard(zl3073x)(zldev);
+
+	/* Get index of the pin */
+	ref_id = zl3073x_dpll_pin_index_get(pin);
+
+	/* Read reference configuration into mailbox */
+	rc = zl3073x_mb_ref_read(zldev, ref_id);
+	if (rc)
+		return rc;
+
+	/* Read ref sync control */
+	rc = zl3073x_read_ref_sync_ctrl(zldev, &ref_sync_ctrl);
+	if (rc)
+		return rc;
+
+	/* Use freq == 0 to disable esync */
+	if (!freq)
+		sync_mode = REF_SYNC_CTRL_MODE_REFSYNC_PAIR_OFF;
+	else
+		sync_mode = REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75;
+
+	ref_sync_ctrl &= REF_SYNC_CTRL_MODE;
+	ref_sync_ctrl |= FIELD_PREP(REF_SYNC_CTRL_MODE, sync_mode);
+
+	/* Update ref sync control register */
+	rc = zl3073x_write_ref_sync_ctrl(zldev, ref_sync_ctrl);
+	if (rc)
+		return rc;
+
+	if (freq) {
+		/* 1 Hz is only supported frequnecy currently */
+		rc = zl3073x_write_ref_esync_div(zldev, REF_ESYNC_DIV_1HZ);
+		if (rc)
+			return rc;
+	}
+
+	/* Update reference configuration from mailbox */
+	rc = zl3073x_mb_ref_write(zldev, ref_id);
+	if (rc)
+		return rc;
+
+	return rc;
+}
+
 static int
 zl3073x_dpll_input_pin_frequency_get(const struct dpll_pin *dpll_pin,
 				     void *pin_priv,
@@ -1017,6 +1163,218 @@ zl3073x_dpll_pin_synth_get(struct zl3073x_dpll_pin *pin)
 	return zl3073x_output_synth_get(pin_to_dev(pin), output);
 }
 
+static int
+zl3073x_dpll_output_pin_esync_get(const struct dpll_pin *dpll_pin,
+				  void *pin_priv,
+				  const struct dpll_device *dpll,
+				  void *dpll_priv,
+				  struct dpll_pin_esync *esync,
+				  struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll *zldpll = dpll_priv;
+	struct zl3073x_dev *zldev = zldpll->mfd;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	u32 esync_period, esync_width, output_div;
+	u8 clock_type, output, output_mode, synth;
+	u64 synth_freq;
+	int rc;
+
+	output = zl3073x_dpll_output_pin_output_get(pin);
+
+	/* If N-division is enabled, esync is not supported. The register used
+	 * for N-division is also used for the esync divider so both cannot
+	 * be used.
+	 */
+	switch (zl3073x_output_signal_format_get(zldev, output)) {
+	case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV:
+	case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV:
+		return -EOPNOTSUPP;
+	default:
+		break;
+	}
+
+	/* Take device lock */
+	guard(zl3073x)(zldev);
+
+	/* Read output configuration into mailbox */
+	rc = zl3073x_mb_output_read(zldev, output);
+	if (rc)
+		return rc;
+
+	/* Read output mode */
+	rc = zl3073x_read_output_mode(zldev, &output_mode);
+	if (rc)
+		return rc;
+
+	/* Read output divisor */
+	rc = zl3073x_read_output_div(zldev, &output_div);
+	if (rc)
+		return rc;
+
+	/* Check output divisor for zero */
+	if (!output_div) {
+		dev_err(zldev->dev,
+			"Zero divisor for OUTPUT%u got from device\n",
+			output);
+		return -EINVAL;
+	}
+
+	/* Get synth attached to output pin */
+	synth = zl3073x_dpll_pin_synth_get(pin);
+
+	/* Get synth frequency */
+	synth_freq = zl3073x_synth_freq_get(zldev, synth);
+
+	clock_type = FIELD_GET(OUTPUT_MODE_CLOCK_TYPE, output_mode);
+	if (clock_type != OUTPUT_MODE_CLOCK_TYPE_ESYNC) {
+		/* No need to read esync data if it is not enabled */
+		esync->freq = 0;
+		esync->pulse = 50;
+
+		goto finish;
+	}
+
+	/* Read esync period */
+	rc = zl3073x_read_output_esync_period(zldev, &esync_period);
+	if (rc)
+		return rc;
+
+	/* Check esync divisor for zero */
+	if (!esync_period) {
+		dev_err(zldev->dev,
+			"Zero esync divisor for OUTPUT%u got from device\n",
+			output);
+		return -EINVAL;
+	}
+
+	/* Get esync pulse width in units of half synth cycles */
+	rc = zl3073x_read_output_esync_width(zldev, &esync_width);
+	if (rc)
+		return rc;
+
+	/* Compute esync frequency:
+	 * esync_freq = synth_freq / output_div / esync_period;
+	 *     ...    = synth_freq / (output_div * esync_period);
+	 */
+	esync->freq = div64_u64(synth_freq,
+				mul_u32_u32(output_div, esync_period));
+
+	/* By comparing the esync_pulse_width to the half of the pulse width
+	 * the esync pulse percentage can be determined.
+	 * Note that half pulse width is in units of half synth cycles, which
+	 * is why it reduces down to be output_div.
+	 */
+	esync->pulse = (50 * esync_width) / output_div;
+
+finish:
+	/* Set supported esync ranges if the pin supports esync control and
+	 * if the output frequency is > 1 Hz.
+	 */
+	if (pin->esync_control && div_u64(synth_freq, output_div) > 1) {
+		esync->range = esync_freq_ranges;
+		esync->range_num = ARRAY_SIZE(esync_freq_ranges);
+	} else {
+		esync->range = NULL;
+		esync->range_num = 0;
+	}
+
+	return 0;
+}
+
+static int
+zl3073x_dpll_output_pin_esync_set(const struct dpll_pin *dpll_pin,
+				  void *pin_priv,
+				  const struct dpll_device *dpll,
+				  void *dpll_priv, u64 freq,
+				  struct netlink_ext_ack *extack)
+{
+	struct zl3073x_dpll *zldpll = dpll_priv;
+	struct zl3073x_dev *zldev = zldpll->mfd;
+	struct zl3073x_dpll_pin *pin = pin_priv;
+	u32 esync_period, esync_width, output_div;
+	u8 clock_type, output, output_mode, synth;
+	u64 synth_freq;
+	int rc;
+
+	output = zl3073x_dpll_output_pin_output_get(pin);
+
+	/* If N-division is enabled, esync is not supported. The register used
+	 * for N-division is also used for the esync divider so both cannot
+	 * be used.
+	 */
+	switch (zl3073x_output_signal_format_get(zldev, output)) {
+	case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV:
+	case OUTPUT_MODE_SIGNAL_FORMAT_TWO_N_DIV_INV:
+		return -EOPNOTSUPP;
+	default:
+		break;
+	}
+
+	/* Take device lock */
+	guard(zl3073x)(zldev);
+
+	/* Read output configuration into mailbox */
+	rc = zl3073x_mb_output_read(zldev, output);
+	if (rc)
+		return rc;
+
+	/* Read output mode */
+	rc = zl3073x_read_output_mode(zldev, &output_mode);
+	if (rc)
+		return rc;
+
+	/* Select clock type */
+	if (freq)
+		clock_type = OUTPUT_MODE_CLOCK_TYPE_ESYNC;
+	else
+		clock_type = OUTPUT_MODE_CLOCK_TYPE_NORMAL;
+
+	/* Update clock type in ref sync control */
+	output_mode &= ~OUTPUT_MODE_CLOCK_TYPE;
+	output_mode |= FIELD_PREP(OUTPUT_MODE_CLOCK_TYPE, clock_type);
+	rc = zl3073x_write_output_mode(zldev, output_mode);
+	if (rc)
+		return rc;
+
+	/* If esync is being disabled just write mailbox and finish */
+	if (!freq)
+		goto write_mailbox;
+
+	/* Read output divisor */
+	rc = zl3073x_read_output_div(zldev, &output_div);
+	if (rc)
+		return rc;
+
+	/* Get synth attached to output pin */
+	synth = zl3073x_dpll_pin_synth_get(pin);
+
+	/* Get synth frequency */
+	synth_freq = zl3073x_synth_freq_get(zldev, synth);
+
+	/* Compute and update esync period */
+	esync_period = (u32)div64_u64(synth_freq, freq * output_div);
+	rc = zl3073x_write_output_esync_period(zldev, esync_period);
+	if (rc)
+		return rc;
+
+	/* Half of the period in units of 1/2 synth cycle can be represented by
+	 * the output_div. To get the supported esync pulse width of 25% of the
+	 * period the output_div can just be divided by 2. Note that this
+	 * assumes that output_div is even, otherwise some resolution will be
+	 * lost.
+	 */
+	esync_width = output_div / 2;
+	rc = zl3073x_write_output_esync_width(zldev, esync_width);
+	if (rc)
+		return rc;
+
+write_mailbox:
+	/* Update output configuration from mailbox */
+	rc = zl3073x_mb_output_write(zldev, output);
+
+	return rc;
+}
+
 static int
 zl3073x_dpll_output_pin_frequency_get(const struct dpll_pin *dpll_pin,
 				      void *pin_priv,
@@ -1418,6 +1776,8 @@ zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv,
 
 static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
 	.direction_get = zl3073x_dpll_pin_direction_get,
+	.esync_get = zl3073x_dpll_input_pin_esync_get,
+	.esync_set = zl3073x_dpll_input_pin_esync_set,
 	.frequency_get = zl3073x_dpll_input_pin_frequency_get,
 	.frequency_set = zl3073x_dpll_input_pin_frequency_set,
 	.phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get,
@@ -1431,6 +1791,8 @@ static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = {
 
 static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = {
 	.direction_get = zl3073x_dpll_pin_direction_get,
+	.esync_get = zl3073x_dpll_output_pin_esync_get,
+	.esync_set = zl3073x_dpll_output_pin_esync_set,
 	.frequency_get = zl3073x_dpll_output_pin_frequency_get,
 	.frequency_set = zl3073x_dpll_output_pin_frequency_set,
 	.phase_adjust_get = zl3073x_dpll_output_pin_phase_adjust_get,
@@ -1678,6 +2040,10 @@ zl3073x_dpll_pin_info_get(struct zl3073x_dpll_pin *pin)
 				 pin_type);
 	}
 
+	/* Check if the pin supports embedded sync control */
+	pin->esync_control = fwnode_property_read_bool(pin_info->fwnode,
+						       "esync-control");
+
 	/* Read supported frequencies property if it is specified */
 	num_freqs = fwnode_property_count_u64(pin_info->fwnode,
 					      "supported-frequencies");
