mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 05:31:37 -04:00
dpll: zl3073x: add DPLL channel status fields to zl3073x_chan
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>
This commit is contained in:
committed by
Jakub Kicinski
parent
3032e95987
commit
41bab554d7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user