From: Ivan Vecera <ivecera@redhat.com>
To: netdev@vger.kernel.org
Cc: Donald Hunter <donald.hunter@gmail.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Vadim Fedorenko <vadim.fedorenko@linux.dev>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Jiri Pirko <jiri@resnulli.us>,
Prathosh Satish <Prathosh.Satish@microchip.com>,
Petr Oros <poros@redhat.com>,
linux-kernel@vger.kernel.org,
Michal Schmidt <mschmidt@redhat.com>
Subject: [PATCH net-next 3/3] dpll: zl3073x: Implement device mode setting support
Date: Mon, 12 Jan 2026 11:14:09 +0100 [thread overview]
Message-ID: <20260112101409.804206-4-ivecera@redhat.com> (raw)
In-Reply-To: <20260112101409.804206-1-ivecera@redhat.com>
Add support for .supported_modes_get() and .mode_set() callbacks
to enable switching between manual and automatic modes via netlink.
Implement .supported_modes_get() to report available modes based
on the current hardware configuration:
* manual mode is always supported
* automatic mode is supported unless the dpll channel is configured
in NCO (Numerically Controlled Oscillator) mode
Implement .mode_set() to handle the specific logic required when
transitioning between modes:
1) Transition to manual:
* If a valid reference is currently active, switch the hardware
to ref-lock mode (force lock to that reference).
* If no reference is valid and the DPLL is unlocked, switch to freerun.
* Otherwise, switch to Holdover.
2) Transition to automatic:
* If the currently selected reference pin was previously marked
as non-selectable (likely during a previous manual forcing
operation), restore its priority and selectability in the hardware.
* Switch the hardware to Automatic selection mode.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/dpll.c | 106 ++++++++++++++++++++++++++++++++++++
1 file changed, 106 insertions(+)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index 9879d85d29af0..d0a9c361dc1d8 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -100,6 +100,20 @@ zl3073x_dpll_pin_direction_get(const struct dpll_pin *dpll_pin, void *pin_priv,
return 0;
}
+static struct zl3073x_dpll_pin *
+zl3073x_dpll_pin_get_by_ref(struct zl3073x_dpll *zldpll, u8 ref_id)
+{
+ struct zl3073x_dpll_pin *pin;
+
+ list_for_each_entry(pin, &zldpll->pins, list) {
+ if (zl3073x_dpll_is_input_pin(pin) &&
+ zl3073x_input_pin_ref_get(pin->id) == ref_id)
+ return pin;
+ }
+
+ return NULL;
+}
+
static int
zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin,
void *pin_priv,
@@ -1137,6 +1151,26 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
return 0;
}
+static int
+zl3073x_dpll_supported_modes_get(const struct dpll_device *dpll,
+ void *dpll_priv, unsigned long *modes,
+ struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dpll *zldpll = dpll_priv;
+
+ /* We support switching between automatic and manual mode, except in
+ * a case where the DPLL channel is configured to run in NCO mode.
+ * In this case, report only the manual mode to which the NCO is mapped
+ * as the only supported one.
+ */
+ if (zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_NCO)
+ __set_bit(DPLL_MODE_AUTOMATIC, modes);
+
+ __set_bit(DPLL_MODE_MANUAL, modes);
+
+ return 0;
+}
+
static int
zl3073x_dpll_mode_get(const struct dpll_device *dpll, void *dpll_priv,
enum dpll_mode *mode, struct netlink_ext_ack *extack)
@@ -1217,6 +1251,76 @@ zl3073x_dpll_phase_offset_avg_factor_set(const struct dpll_device *dpll,
return 0;
}
+static int
+zl3073x_dpll_mode_set(const struct dpll_device *dpll, void *dpll_priv,
+ enum dpll_mode mode, struct netlink_ext_ack *extack)
+{
+ struct zl3073x_dpll *zldpll = dpll_priv;
+ u8 hw_mode, mode_refsel, ref;
+ int rc;
+
+ rc = zl3073x_dpll_selected_ref_get(zldpll, &ref);
+ if (rc) {
+ NL_SET_ERR_MSG_MOD(extack, "failed to get selected reference");
+ return rc;
+ }
+
+ if (mode == DPLL_MODE_MANUAL) {
+ /* We are switching from automatic to manual mode:
+ * - if we have a valid reference selected during auto mode then
+ * we will switch to forced reference lock mode and use this
+ * reference for selection
+ * - if NO valid reference is selected, we will switch to forced
+ * holdover mode or freerun mode, depending on the current
+ * lock status
+ */
+ if (ZL3073X_DPLL_REF_IS_VALID(ref))
+ hw_mode = ZL_DPLL_MODE_REFSEL_MODE_REFLOCK;
+ else if (zldpll->lock_status == DPLL_LOCK_STATUS_UNLOCKED)
+ hw_mode = ZL_DPLL_MODE_REFSEL_MODE_FREERUN;
+ else
+ hw_mode = ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER;
+ } else {
+ /* We are switching from manual to automatic mode:
+ * - if there is a valid reference selected then ensure that
+ * it is selectable after switch to automatic mode
+ * - switch to automatic mode
+ */
+ struct zl3073x_dpll_pin *pin;
+
+ pin = zl3073x_dpll_pin_get_by_ref(zldpll, ref);
+ if (pin && !pin->selectable) {
+ /* Restore pin priority in HW */
+ rc = zl3073x_dpll_ref_prio_set(pin, pin->prio);
+ if (rc)
+ return rc;
+
+ pin->selectable = true;
+ }
+
+ hw_mode = ZL_DPLL_MODE_REFSEL_MODE_AUTO;
+ }
+
+ /* Build mode_refsel value */
+ mode_refsel = FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, hw_mode);
+
+ if (ZL3073X_DPLL_REF_IS_VALID(ref))
+ mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref);
+
+ /* Update dpll_mode_refsel register */
+ rc = zl3073x_write_u8(zldpll->dev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id),
+ mode_refsel);
+ if (rc)
+ return rc;
+
+ zldpll->refsel_mode = hw_mode;
+
+ if (ZL3073X_DPLL_REF_IS_VALID(ref))
+ zldpll->forced_ref = ref;
+
+ return 0;
+}
+
static int
zl3073x_dpll_phase_offset_monitor_get(const struct dpll_device *dpll,
void *dpll_priv,
@@ -1276,10 +1380,12 @@ static const struct dpll_pin_ops zl3073x_dpll_output_pin_ops = {
static const struct dpll_device_ops zl3073x_dpll_device_ops = {
.lock_status_get = zl3073x_dpll_lock_status_get,
.mode_get = zl3073x_dpll_mode_get,
+ .mode_set = zl3073x_dpll_mode_set,
.phase_offset_avg_factor_get = zl3073x_dpll_phase_offset_avg_factor_get,
.phase_offset_avg_factor_set = zl3073x_dpll_phase_offset_avg_factor_set,
.phase_offset_monitor_get = zl3073x_dpll_phase_offset_monitor_get,
.phase_offset_monitor_set = zl3073x_dpll_phase_offset_monitor_set,
+ .supported_modes_get = zl3073x_dpll_supported_modes_get,
};
/**
--
2.52.0
next prev parent reply other threads:[~2026-01-12 10:14 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-12 10:14 [PATCH net-next 0/3] dpll: support mode switching Ivan Vecera
2026-01-12 10:14 ` [PATCH net-next 1/3] dpll: add dpll_device op to get supported modes Ivan Vecera
2026-01-12 11:44 ` Vadim Fedorenko
2026-01-12 10:14 ` [PATCH net-next 2/3] dpll: add dpll_device op to set working mode Ivan Vecera
2026-01-12 11:35 ` Vadim Fedorenko
2026-01-12 13:10 ` Ivan Vecera
2026-01-12 10:14 ` Ivan Vecera [this message]
2026-01-12 11:37 ` [PATCH net-next 3/3] dpll: zl3073x: Implement device mode setting support Vadim Fedorenko
2026-01-12 13:27 ` Ivan Vecera
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260112101409.804206-4-ivecera@redhat.com \
--to=ivecera@redhat.com \
--cc=Prathosh.Satish@microchip.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=davem@davemloft.net \
--cc=donald.hunter@gmail.com \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=poros@redhat.com \
--cc=vadim.fedorenko@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.