]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dpll: zl3073x: add DPLL channel status fields to zl3073x_chan
authorIvan Vecera <ivecera@redhat.com>
Sun, 15 Mar 2026 17:42:22 +0000 (18:42 +0100)
committerJakub Kicinski <kuba@kernel.org>
Wed, 18 Mar 2026 02:05:12 +0000 (19:05 -0700)
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>
Link: https://patch.msgid.link/20260315174224.399074-5-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/dpll/zl3073x/chan.c
drivers/dpll/zl3073x/chan.h
drivers/dpll/zl3073x/core.c
drivers/dpll/zl3073x/dpll.c

index 8019b8ce73514aab5c2e7e00e528aa511ad83f53..71fb60a9859bf44d196d09f9c0d65162168ab0ad 100644 (file)
@@ -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;
 }
 
index 3e6ffaef0c7436a28c98a0de88e6c0035e54425f..f73a0761085510d2f8014ad0eca75222d02bcefc 100644 (file)
@@ -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 */
index b03e59fa0834bc9430d3df930856a91b50163559..6363002d48d46c15428443b0db65692a88d9ff45 100644 (file)
@@ -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)
index f56f073e57df4a018858039f194274db76f1e278..49e3f9f1308487fa21f922f493a96ff08d1d2d07 100644 (file)
@@ -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;
        }