From: Ivan Vecera <ivecera@redhat.com>
To: netdev@vger.kernel.org
Cc: Prathosh Satish <Prathosh.Satish@microchip.com>,
Vadim Fedorenko <vadim.fedorenko@linux.dev>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Jiri Pirko <jiri@resnulli.us>, Petr Oros <poros@redhat.com>,
Michal Schmidt <mschmidt@redhat.com>,
Simon Horman <horms@kernel.org>,
linux-kernel@vger.kernel.org
Subject: [PATCH net-next 4/6] dpll: zl3073x: add DPLL channel status fields to zl3073x_chan
Date: Wed, 11 Mar 2026 20:00:53 +0100 [thread overview]
Message-ID: <20260311190055.139006-5-ivecera@redhat.com> (raw)
In-Reply-To: <20260311190055.139006-1-ivecera@redhat.com>
Add mon_status and refsel_status fields to struct zl3073x_chan in a
stat group to cache the 'dpll_mon_status' and 'dpll_refsel_status'
registers.
Add zl3073x_chan_lock_state_get(), zl3073x_chan_is_ho_ready(),
zl3073x_chan_refsel_state_get() and zl3073x_chan_refsel_ref_get()
inline helpers for reading cached state, and zl3073x_chan_state_update()
for refreshing both registers from hardware. Call it from
zl3073x_chan_state_fetch() as well so that channel status is
initialized at device startup.
Call zl3073x_dev_chan_states_update() from the periodic work to
keep the cached state up to date and convert
zl3073x_dpll_lock_status_get() and zl3073x_dpll_selected_ref_get()
to use the cached state via the new helpers instead of direct register
reads.
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/zl3073x/chan.c | 32 +++++++++++++++++++++++
drivers/dpll/zl3073x/chan.h | 52 +++++++++++++++++++++++++++++++++++++
drivers/dpll/zl3073x/core.c | 17 ++++++++++++
drivers/dpll/zl3073x/dpll.c | 41 +++++++----------------------
4 files changed, 111 insertions(+), 31 deletions(-)
diff --git a/drivers/dpll/zl3073x/chan.c b/drivers/dpll/zl3073x/chan.c
index 6f383d489fab7..10189c8a5ded3 100644
--- a/drivers/dpll/zl3073x/chan.c
+++ b/drivers/dpll/zl3073x/chan.c
@@ -7,6 +7,27 @@
#include "chan.h"
#include "core.h"
+/**
+ * zl3073x_chan_state_update - update DPLL channel status from HW
+ * @zldev: pointer to zl3073x_dev structure
+ * @index: DPLL channel index
+ *
+ * Return: 0 on success, <0 on error
+ */
+int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index)
+{
+ struct zl3073x_chan *chan = &zldev->chan[index];
+ int rc;
+
+ rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index),
+ &chan->mon_status);
+ if (rc)
+ return rc;
+
+ return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index),
+ &chan->refsel_status);
+}
+
/**
* zl3073x_chan_state_fetch - fetch DPLL channel state from hardware
* @zldev: pointer to zl3073x_dev structure
@@ -30,6 +51,17 @@ int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index)
dev_dbg(zldev->dev, "DPLL%u mode: %u, ref: %u\n", index,
zl3073x_chan_mode_get(chan), zl3073x_chan_ref_get(chan));
+ rc = zl3073x_chan_state_update(zldev, index);
+ if (rc)
+ return rc;
+
+ dev_dbg(zldev->dev,
+ "DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n",
+ index, zl3073x_chan_lock_state_get(chan),
+ zl3073x_chan_is_ho_ready(chan) ? 1 : 0,
+ zl3073x_chan_refsel_state_get(chan),
+ zl3073x_chan_refsel_ref_get(chan));
+
return 0;
}
diff --git a/drivers/dpll/zl3073x/chan.h b/drivers/dpll/zl3073x/chan.h
index 3e6ffaef0c743..f73a076108551 100644
--- a/drivers/dpll/zl3073x/chan.h
+++ b/drivers/dpll/zl3073x/chan.h
@@ -14,11 +14,17 @@ struct zl3073x_dev;
/**
* struct zl3073x_chan - DPLL channel state
* @mode_refsel: mode and reference selection register value
+ * @mon_status: monitor status register value
+ * @refsel_status: reference selection status register value
*/
struct zl3073x_chan {
struct_group(cfg,
u8 mode_refsel;
);
+ struct_group(stat,
+ u8 mon_status;
+ u8 refsel_status;
+ );
};
int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index);
@@ -27,6 +33,8 @@ const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev,
int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index,
const struct zl3073x_chan *chan);
+int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index);
+
/**
* zl3073x_chan_mode_get - get DPLL channel operating mode
* @chan: pointer to channel state
@@ -71,4 +79,48 @@ static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref)
chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref);
}
+/**
+ * zl3073x_chan_lock_state_get - get DPLL channel lock state
+ * @chan: pointer to channel state
+ *
+ * Return: lock state of the given DPLL channel
+ */
+static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan)
+{
+ return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status);
+}
+
+/**
+ * zl3073x_chan_is_ho_ready - check if holdover is ready
+ * @chan: pointer to channel state
+ *
+ * Return: true if holdover is ready, false otherwise
+ */
+static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan)
+{
+ return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status);
+}
+
+/**
+ * zl3073x_chan_refsel_state_get - get reference selection state
+ * @chan: pointer to channel state
+ *
+ * Return: reference selection state of the given DPLL channel
+ */
+static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan)
+{
+ return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status);
+}
+
+/**
+ * zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode
+ * @chan: pointer to channel state
+ *
+ * Return: reference selected by the DPLL in automatic mode
+ */
+static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan)
+{
+ return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status);
+}
+
#endif /* _ZL3073X_CHAN_H */
diff --git a/drivers/dpll/zl3073x/core.c b/drivers/dpll/zl3073x/core.c
index b03e59fa0834b..6363002d48d46 100644
--- a/drivers/dpll/zl3073x/core.c
+++ b/drivers/dpll/zl3073x/core.c
@@ -566,6 +566,20 @@ zl3073x_dev_ref_states_update(struct zl3073x_dev *zldev)
}
}
+static void
+zl3073x_dev_chan_states_update(struct zl3073x_dev *zldev)
+{
+ int i, rc;
+
+ for (i = 0; i < zldev->info->num_channels; i++) {
+ rc = zl3073x_chan_state_update(zldev, i);
+ if (rc)
+ dev_warn(zldev->dev,
+ "Failed to get DPLL%u state: %pe\n", i,
+ ERR_PTR(rc));
+ }
+}
+
/**
* zl3073x_ref_phase_offsets_update - update reference phase offsets
* @zldev: pointer to zl3073x_dev structure
@@ -691,6 +705,9 @@ zl3073x_dev_periodic_work(struct kthread_work *work)
/* Update input references' states */
zl3073x_dev_ref_states_update(zldev);
+ /* Update DPLL channels' states */
+ zl3073x_dev_chan_states_update(zldev);
+
/* Update DPLL-to-connected-ref phase offsets registers */
rc = zl3073x_ref_phase_offsets_update(zldev, -1);
if (rc)
diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c
index f56f073e57df4..49e3f9f130848 100644
--- a/drivers/dpll/zl3073x/dpll.c
+++ b/drivers/dpll/zl3073x/dpll.c
@@ -258,28 +258,16 @@ zl3073x_dpll_input_pin_frequency_set(const struct dpll_pin *dpll_pin,
static int
zl3073x_dpll_selected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref)
{
- struct zl3073x_dev *zldev = zldpll->dev;
const struct zl3073x_chan *chan;
- u8 state, value;
- int rc;
- chan = zl3073x_chan_state_get(zldev, zldpll->id);
+ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
switch (zl3073x_chan_mode_get(chan)) {
case ZL_DPLL_MODE_REFSEL_MODE_AUTO:
- /* For automatic mode read refsel_status register */
- rc = zl3073x_read_u8(zldev,
- ZL_REG_DPLL_REFSEL_STATUS(zldpll->id),
- &value);
- if (rc)
- return rc;
-
- /* Extract reference state */
- state = FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, value);
-
/* Return the reference only if the DPLL is locked to it */
- if (state == ZL_DPLL_REFSEL_STATUS_STATE_LOCK)
- *ref = FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, value);
+ if (zl3073x_chan_refsel_state_get(chan) ==
+ ZL_DPLL_REFSEL_STATUS_STATE_LOCK)
+ *ref = zl3073x_chan_refsel_ref_get(chan);
else
*ref = ZL3073X_DPLL_REF_NONE;
break;
@@ -1089,12 +1077,9 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
struct netlink_ext_ack *extack)
{
struct zl3073x_dpll *zldpll = dpll_priv;
- struct zl3073x_dev *zldev = zldpll->dev;
const struct zl3073x_chan *chan;
- u8 mon_status, state;
- int rc;
- chan = zl3073x_chan_state_get(zldev, zldpll->id);
+ chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id);
switch (zl3073x_chan_mode_get(chan)) {
case ZL_DPLL_MODE_REFSEL_MODE_FREERUN:
@@ -1107,16 +1092,9 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
break;
}
- /* Read DPLL monitor status */
- rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(zldpll->id),
- &mon_status);
- if (rc)
- return rc;
- state = FIELD_GET(ZL_DPLL_MON_STATUS_STATE, mon_status);
-
- switch (state) {
+ switch (zl3073x_chan_lock_state_get(chan)) {
case ZL_DPLL_MON_STATUS_STATE_LOCK:
- if (FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, mon_status))
+ if (zl3073x_chan_is_ho_ready(chan))
*status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ;
else
*status = DPLL_LOCK_STATUS_LOCKED;
@@ -1126,8 +1104,9 @@ zl3073x_dpll_lock_status_get(const struct dpll_device *dpll, void *dpll_priv,
*status = DPLL_LOCK_STATUS_HOLDOVER;
break;
default:
- dev_warn(zldev->dev, "Unknown DPLL monitor status: 0x%02x\n",
- mon_status);
+ dev_warn(zldpll->dev->dev,
+ "Unknown DPLL monitor status: 0x%02x\n",
+ chan->mon_status);
*status = DPLL_LOCK_STATUS_UNLOCKED;
break;
}
--
2.52.0
next prev parent reply other threads:[~2026-03-11 19:01 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-11 19:00 [PATCH net-next 0/6] dpll: zl3073x: refactor state management Ivan Vecera
2026-03-11 19:00 ` [PATCH net-next 1/6] dpll: zl3073x: use struct_group to partition states Ivan Vecera
2026-03-11 19:00 ` [PATCH net-next 2/6] dpll: zl3073x: add zl3073x_ref_state_update helper Ivan Vecera
2026-03-11 19:00 ` [PATCH net-next 3/6] dpll: zl3073x: introduce zl3073x_chan for DPLL channel state Ivan Vecera
2026-03-11 19:00 ` Ivan Vecera [this message]
2026-03-11 19:00 ` [PATCH net-next 5/6] dpll: zl3073x: add reference priority to zl3073x_chan Ivan Vecera
2026-03-14 19:53 ` [net-next,5/6] " Jakub Kicinski
2026-03-15 17:38 ` Ivan Vecera
2026-03-11 19:00 ` [PATCH net-next 6/6] dpll: zl3073x: drop selected and simplify connected ref getter 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=20260311190055.139006-5-ivecera@redhat.com \
--to=ivecera@redhat.com \
--cc=Prathosh.Satish@microchip.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=horms@kernel.org \
--cc=jiri@resnulli.us \
--cc=linux-kernel@vger.kernel.org \
--cc=mschmidt@redhat.com \
--cc=netdev@vger.kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox