Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'dpll-zl3073x-refactor-state-management'

Ivan Vecera says:

====================
dpll: zl3073x: refactor state management

This series refactors the zl3073x DPLL driver to centralize hardware
state management behind dedicated per-module state interfaces, replacing
scattered direct register accesses in dpll.c with cached state and
proper accessor functions.

The driver already uses a fetch/get/set pattern for ref, out, and synth
modules. This series extends and refines that pattern:

First, struct_group() is applied to the existing ref, out, and synth
structures to partition fields into cfg (mutable configuration), inv
(invariants set at init), and stat (read-only status) groups. This
enables group-level memcmp for short-circuit checks and bulk copies in
state_set, and adds invariant validation guards.

A ref_state_update() helper is extracted to encapsulate the per-reference
monitor status register read, keeping direct register access behind the
ref module interface.

A new zl3073x_chan module is introduced following the same pattern,
caching the DPLL channel mode_refsel register with inline getters and
setters. The refsel_mode and forced_ref fields are removed from struct
zl3073x_dpll in favor of the cached channel state.

The chan module is then extended with cached mon_status and refsel_status
registers, converting lock_status_get and selected_ref_get from direct
HW reads to cached state lookups refreshed by the periodic worker.

Reference priority registers are cached in the chan cfg group, removing
the ad-hoc ref_prio_get/set functions and the redundant pin->selectable
flag, which is now derived from the cached priority. The
selected_ref_set function is inlined into input_pin_state_on_dpll_set,
unifying all mode paths through a single chan_state_set commit point.

Finally, selected_ref_get is dropped entirely since the refsel_status
register provides the selected reference regardless of mode, and
connected_ref_get is simplified to a direct refsel_state check.
====================

Link: https://patch.msgid.link/20260315174224.399074-1-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+626 -431
+2 -2
drivers/dpll/zl3073x/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 obj-$(CONFIG_ZL3073X) += zl3073x.o 4 - zl3073x-objs := core.o devlink.o dpll.o flash.o fw.o \ 5 - out.o prop.o ref.o synth.o 4 + zl3073x-objs := chan.o core.o devlink.o dpll.o \ 5 + flash.o fw.o out.o prop.o ref.o synth.o 6 6 7 7 obj-$(CONFIG_ZL3073X_I2C) += zl3073x_i2c.o 8 8 zl3073x_i2c-objs := i2c.o
+165
drivers/dpll/zl3073x/chan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <linux/cleanup.h> 4 + #include <linux/dev_printk.h> 5 + #include <linux/string.h> 6 + #include <linux/types.h> 7 + 8 + #include "chan.h" 9 + #include "core.h" 10 + 11 + /** 12 + * zl3073x_chan_state_update - update DPLL channel status from HW 13 + * @zldev: pointer to zl3073x_dev structure 14 + * @index: DPLL channel index 15 + * 16 + * Return: 0 on success, <0 on error 17 + */ 18 + int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index) 19 + { 20 + struct zl3073x_chan *chan = &zldev->chan[index]; 21 + int rc; 22 + 23 + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index), 24 + &chan->mon_status); 25 + if (rc) 26 + return rc; 27 + 28 + return zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index), 29 + &chan->refsel_status); 30 + } 31 + 32 + /** 33 + * zl3073x_chan_state_fetch - fetch DPLL channel state from hardware 34 + * @zldev: pointer to zl3073x_dev structure 35 + * @index: DPLL channel index to fetch state for 36 + * 37 + * Reads the mode_refsel register and reference priority registers for 38 + * the given DPLL channel and stores the raw values for later use. 39 + * 40 + * Return: 0 on success, <0 on error 41 + */ 42 + int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index) 43 + { 44 + struct zl3073x_chan *chan = &zldev->chan[index]; 45 + int rc, i; 46 + 47 + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 48 + &chan->mode_refsel); 49 + if (rc) 50 + return rc; 51 + 52 + dev_dbg(zldev->dev, "DPLL%u mode: %u, ref: %u\n", index, 53 + zl3073x_chan_mode_get(chan), zl3073x_chan_ref_get(chan)); 54 + 55 + rc = zl3073x_chan_state_update(zldev, index); 56 + if (rc) 57 + return rc; 58 + 59 + dev_dbg(zldev->dev, 60 + "DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n", 61 + index, zl3073x_chan_lock_state_get(chan), 62 + zl3073x_chan_is_ho_ready(chan) ? 1 : 0, 63 + zl3073x_chan_refsel_state_get(chan), 64 + zl3073x_chan_refsel_ref_get(chan)); 65 + 66 + guard(mutex)(&zldev->multiop_lock); 67 + 68 + /* Read DPLL configuration from mailbox */ 69 + rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 70 + ZL_REG_DPLL_MB_MASK, BIT(index)); 71 + if (rc) 72 + return rc; 73 + 74 + /* Read reference priority registers */ 75 + for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { 76 + rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(i), 77 + &chan->ref_prio[i]); 78 + if (rc) 79 + return rc; 80 + } 81 + 82 + return 0; 83 + } 84 + 85 + /** 86 + * zl3073x_chan_state_get - get current DPLL channel state 87 + * @zldev: pointer to zl3073x_dev structure 88 + * @index: DPLL channel index to get state for 89 + * 90 + * Return: pointer to given DPLL channel state 91 + */ 92 + const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, 93 + u8 index) 94 + { 95 + return &zldev->chan[index]; 96 + } 97 + 98 + /** 99 + * zl3073x_chan_state_set - commit DPLL channel state changes to hardware 100 + * @zldev: pointer to zl3073x_dev structure 101 + * @index: DPLL channel index to set state for 102 + * @chan: desired channel state 103 + * 104 + * Skips the HW write if the configuration is unchanged, and otherwise 105 + * writes only the changed registers to hardware. The mode_refsel register 106 + * is written directly, while the reference priority registers are written 107 + * via the DPLL mailbox interface. 108 + * 109 + * Return: 0 on success, <0 on HW error 110 + */ 111 + int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, 112 + const struct zl3073x_chan *chan) 113 + { 114 + struct zl3073x_chan *dchan = &zldev->chan[index]; 115 + int rc, i; 116 + 117 + /* Skip HW write if configuration hasn't changed */ 118 + if (!memcmp(&dchan->cfg, &chan->cfg, sizeof(chan->cfg))) 119 + return 0; 120 + 121 + /* Direct register write for mode_refsel */ 122 + if (dchan->mode_refsel != chan->mode_refsel) { 123 + rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 124 + chan->mode_refsel); 125 + if (rc) 126 + return rc; 127 + dchan->mode_refsel = chan->mode_refsel; 128 + } 129 + 130 + /* Mailbox write for ref_prio if changed */ 131 + if (!memcmp(dchan->ref_prio, chan->ref_prio, sizeof(chan->ref_prio))) { 132 + dchan->cfg = chan->cfg; 133 + return 0; 134 + } 135 + 136 + guard(mutex)(&zldev->multiop_lock); 137 + 138 + /* Read DPLL configuration into mailbox */ 139 + rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 140 + ZL_REG_DPLL_MB_MASK, BIT(index)); 141 + if (rc) 142 + return rc; 143 + 144 + /* Update changed ref_prio registers */ 145 + for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { 146 + if (dchan->ref_prio[i] != chan->ref_prio[i]) { 147 + rc = zl3073x_write_u8(zldev, 148 + ZL_REG_DPLL_REF_PRIO(i), 149 + chan->ref_prio[i]); 150 + if (rc) 151 + return rc; 152 + } 153 + } 154 + 155 + /* Commit DPLL configuration */ 156 + rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, 157 + ZL_REG_DPLL_MB_MASK, BIT(index)); 158 + if (rc) 159 + return rc; 160 + 161 + /* After successful write store new state */ 162 + dchan->cfg = chan->cfg; 163 + 164 + return 0; 165 + }
+179
drivers/dpll/zl3073x/chan.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + 3 + #ifndef _ZL3073X_CHAN_H 4 + #define _ZL3073X_CHAN_H 5 + 6 + #include <linux/bitfield.h> 7 + #include <linux/stddef.h> 8 + #include <linux/types.h> 9 + 10 + #include "regs.h" 11 + 12 + struct zl3073x_dev; 13 + 14 + /** 15 + * struct zl3073x_chan - DPLL channel state 16 + * @mode_refsel: mode and reference selection register value 17 + * @ref_prio: reference priority registers (4 bits per ref, P/N packed) 18 + * @mon_status: monitor status register value 19 + * @refsel_status: reference selection status register value 20 + */ 21 + struct zl3073x_chan { 22 + struct_group(cfg, 23 + u8 mode_refsel; 24 + u8 ref_prio[ZL3073X_NUM_REFS / 2]; 25 + ); 26 + struct_group(stat, 27 + u8 mon_status; 28 + u8 refsel_status; 29 + ); 30 + }; 31 + 32 + int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index); 33 + const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, 34 + u8 index); 35 + int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, 36 + const struct zl3073x_chan *chan); 37 + 38 + int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index); 39 + 40 + /** 41 + * zl3073x_chan_mode_get - get DPLL channel operating mode 42 + * @chan: pointer to channel state 43 + * 44 + * Return: reference selection mode of the given DPLL channel 45 + */ 46 + static inline u8 zl3073x_chan_mode_get(const struct zl3073x_chan *chan) 47 + { 48 + return FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, chan->mode_refsel); 49 + } 50 + 51 + /** 52 + * zl3073x_chan_ref_get - get manually selected reference 53 + * @chan: pointer to channel state 54 + * 55 + * Return: reference selected in forced reference lock mode 56 + */ 57 + static inline u8 zl3073x_chan_ref_get(const struct zl3073x_chan *chan) 58 + { 59 + return FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, chan->mode_refsel); 60 + } 61 + 62 + /** 63 + * zl3073x_chan_mode_set - set DPLL channel operating mode 64 + * @chan: pointer to channel state 65 + * @mode: mode to set 66 + */ 67 + static inline void zl3073x_chan_mode_set(struct zl3073x_chan *chan, u8 mode) 68 + { 69 + chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_MODE; 70 + chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, mode); 71 + } 72 + 73 + /** 74 + * zl3073x_chan_ref_set - set manually selected reference 75 + * @chan: pointer to channel state 76 + * @ref: reference to set 77 + */ 78 + static inline void zl3073x_chan_ref_set(struct zl3073x_chan *chan, u8 ref) 79 + { 80 + chan->mode_refsel &= ~ZL_DPLL_MODE_REFSEL_REF; 81 + chan->mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref); 82 + } 83 + 84 + /** 85 + * zl3073x_chan_ref_prio_get - get reference priority 86 + * @chan: pointer to channel state 87 + * @ref: input reference index 88 + * 89 + * Return: priority of the given reference <0, 15> 90 + */ 91 + static inline u8 92 + zl3073x_chan_ref_prio_get(const struct zl3073x_chan *chan, u8 ref) 93 + { 94 + u8 val = chan->ref_prio[ref / 2]; 95 + 96 + if (!(ref & 1)) 97 + return FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, val); 98 + else 99 + return FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, val); 100 + } 101 + 102 + /** 103 + * zl3073x_chan_ref_prio_set - set reference priority 104 + * @chan: pointer to channel state 105 + * @ref: input reference index 106 + * @prio: priority to set 107 + */ 108 + static inline void 109 + zl3073x_chan_ref_prio_set(struct zl3073x_chan *chan, u8 ref, u8 prio) 110 + { 111 + u8 *val = &chan->ref_prio[ref / 2]; 112 + 113 + if (!(ref & 1)) { 114 + *val &= ~ZL_DPLL_REF_PRIO_REF_P; 115 + *val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio); 116 + } else { 117 + *val &= ~ZL_DPLL_REF_PRIO_REF_N; 118 + *val |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio); 119 + } 120 + } 121 + 122 + /** 123 + * zl3073x_chan_ref_is_selectable - check if reference is selectable 124 + * @chan: pointer to channel state 125 + * @ref: input reference index 126 + * 127 + * Return: true if the reference priority is not NONE, false otherwise 128 + */ 129 + static inline bool 130 + zl3073x_chan_ref_is_selectable(const struct zl3073x_chan *chan, u8 ref) 131 + { 132 + return zl3073x_chan_ref_prio_get(chan, ref) != ZL_DPLL_REF_PRIO_NONE; 133 + } 134 + 135 + /** 136 + * zl3073x_chan_lock_state_get - get DPLL channel lock state 137 + * @chan: pointer to channel state 138 + * 139 + * Return: lock state of the given DPLL channel 140 + */ 141 + static inline u8 zl3073x_chan_lock_state_get(const struct zl3073x_chan *chan) 142 + { 143 + return FIELD_GET(ZL_DPLL_MON_STATUS_STATE, chan->mon_status); 144 + } 145 + 146 + /** 147 + * zl3073x_chan_is_ho_ready - check if holdover is ready 148 + * @chan: pointer to channel state 149 + * 150 + * Return: true if holdover is ready, false otherwise 151 + */ 152 + static inline bool zl3073x_chan_is_ho_ready(const struct zl3073x_chan *chan) 153 + { 154 + return !!FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, chan->mon_status); 155 + } 156 + 157 + /** 158 + * zl3073x_chan_refsel_state_get - get reference selection state 159 + * @chan: pointer to channel state 160 + * 161 + * Return: reference selection state of the given DPLL channel 162 + */ 163 + static inline u8 zl3073x_chan_refsel_state_get(const struct zl3073x_chan *chan) 164 + { 165 + return FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, chan->refsel_status); 166 + } 167 + 168 + /** 169 + * zl3073x_chan_refsel_ref_get - get currently selected reference in auto mode 170 + * @chan: pointer to channel state 171 + * 172 + * Return: reference selected by the DPLL in automatic mode 173 + */ 174 + static inline u8 zl3073x_chan_refsel_ref_get(const struct zl3073x_chan *chan) 175 + { 176 + return FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, chan->refsel_status); 177 + } 178 + 179 + #endif /* _ZL3073X_CHAN_H */
+31 -5
drivers/dpll/zl3073x/core.c
··· 539 539 } 540 540 } 541 541 542 + for (i = 0; i < zldev->info->num_channels; i++) { 543 + rc = zl3073x_chan_state_fetch(zldev, i); 544 + if (rc) { 545 + dev_err(zldev->dev, 546 + "Failed to fetch channel state: %pe\n", 547 + ERR_PTR(rc)); 548 + return rc; 549 + } 550 + } 551 + 542 552 return rc; 543 553 } 544 554 545 555 static void 546 - zl3073x_dev_ref_status_update(struct zl3073x_dev *zldev) 556 + zl3073x_dev_ref_states_update(struct zl3073x_dev *zldev) 547 557 { 548 558 int i, rc; 549 559 550 560 for (i = 0; i < ZL3073X_NUM_REFS; i++) { 551 - rc = zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(i), 552 - &zldev->ref[i].mon_status); 561 + rc = zl3073x_ref_state_update(zldev, i); 553 562 if (rc) 554 563 dev_warn(zldev->dev, 555 564 "Failed to get REF%u status: %pe\n", i, 565 + ERR_PTR(rc)); 566 + } 567 + } 568 + 569 + static void 570 + zl3073x_dev_chan_states_update(struct zl3073x_dev *zldev) 571 + { 572 + int i, rc; 573 + 574 + for (i = 0; i < zldev->info->num_channels; i++) { 575 + rc = zl3073x_chan_state_update(zldev, i); 576 + if (rc) 577 + dev_warn(zldev->dev, 578 + "Failed to get DPLL%u state: %pe\n", i, 556 579 ERR_PTR(rc)); 557 580 } 558 581 } ··· 702 679 struct zl3073x_dpll *zldpll; 703 680 int rc; 704 681 705 - /* Update input references status */ 706 - zl3073x_dev_ref_status_update(zldev); 682 + /* Update input references' states */ 683 + zl3073x_dev_ref_states_update(zldev); 684 + 685 + /* Update DPLL channels' states */ 686 + zl3073x_dev_chan_states_update(zldev); 707 687 708 688 /* Update DPLL-to-connected-ref phase offsets registers */ 709 689 rc = zl3073x_ref_phase_offsets_update(zldev, -1);
+3 -11
drivers/dpll/zl3073x/core.h
··· 9 9 #include <linux/mutex.h> 10 10 #include <linux/types.h> 11 11 12 + #include "chan.h" 12 13 #include "out.h" 13 14 #include "ref.h" 14 15 #include "regs.h" ··· 19 18 struct regmap; 20 19 struct zl3073x_dpll; 21 20 22 - /* 23 - * Hardware limits for ZL3073x chip family 24 - */ 25 - #define ZL3073X_MAX_CHANNELS 5 26 - #define ZL3073X_NUM_REFS 10 27 - #define ZL3073X_NUM_OUTS 10 28 - #define ZL3073X_NUM_SYNTHS 5 29 - #define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS 30 - #define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2) 31 - #define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ 32 - ZL3073X_NUM_OUTPUT_PINS) 33 21 34 22 enum zl3073x_flags { 35 23 ZL3073X_FLAG_REF_PHASE_COMP_32_BIT, ··· 51 61 * @ref: array of input references' invariants 52 62 * @out: array of outs' invariants 53 63 * @synth: array of synths' invariants 64 + * @chan: array of DPLL channels' state 54 65 * @dplls: list of DPLLs 55 66 * @kworker: thread for periodic work 56 67 * @work: periodic work ··· 68 77 struct zl3073x_ref ref[ZL3073X_NUM_REFS]; 69 78 struct zl3073x_out out[ZL3073X_NUM_OUTS]; 70 79 struct zl3073x_synth synth[ZL3073X_NUM_SYNTHS]; 80 + struct zl3073x_chan chan[ZL3073X_MAX_CHANNELS]; 71 81 72 82 /* DPLL channels */ 73 83 struct list_head dplls;
+128 -360
drivers/dpll/zl3073x/dpll.c
··· 34 34 * @dir: pin direction 35 35 * @id: pin id 36 36 * @prio: pin priority <0, 14> 37 - * @selectable: pin is selectable in automatic mode 38 37 * @esync_control: embedded sync is controllable 39 38 * @phase_gran: phase adjustment granularity 40 39 * @pin_state: last saved pin state ··· 49 50 enum dpll_pin_direction dir; 50 51 u8 id; 51 52 u8 prio; 52 - bool selectable; 53 53 bool esync_control; 54 54 s32 phase_gran; 55 55 enum dpll_pin_state pin_state; ··· 244 246 } 245 247 246 248 /** 247 - * zl3073x_dpll_selected_ref_get - get currently selected reference 248 - * @zldpll: pointer to zl3073x_dpll 249 - * @ref: place to store selected reference 250 - * 251 - * Check for currently selected reference the DPLL should be locked to 252 - * and stores its index to given @ref. 253 - * 254 - * Return: 0 on success, <0 on error 255 - */ 256 - static int 257 - zl3073x_dpll_selected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) 258 - { 259 - struct zl3073x_dev *zldev = zldpll->dev; 260 - u8 state, value; 261 - int rc; 262 - 263 - switch (zldpll->refsel_mode) { 264 - case ZL_DPLL_MODE_REFSEL_MODE_AUTO: 265 - /* For automatic mode read refsel_status register */ 266 - rc = zl3073x_read_u8(zldev, 267 - ZL_REG_DPLL_REFSEL_STATUS(zldpll->id), 268 - &value); 269 - if (rc) 270 - return rc; 271 - 272 - /* Extract reference state */ 273 - state = FIELD_GET(ZL_DPLL_REFSEL_STATUS_STATE, value); 274 - 275 - /* Return the reference only if the DPLL is locked to it */ 276 - if (state == ZL_DPLL_REFSEL_STATUS_STATE_LOCK) 277 - *ref = FIELD_GET(ZL_DPLL_REFSEL_STATUS_REFSEL, value); 278 - else 279 - *ref = ZL3073X_DPLL_REF_NONE; 280 - break; 281 - case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: 282 - /* For manual mode return stored value */ 283 - *ref = zldpll->forced_ref; 284 - break; 285 - default: 286 - /* For other modes like NCO, freerun... there is no input ref */ 287 - *ref = ZL3073X_DPLL_REF_NONE; 288 - break; 289 - } 290 - 291 - return 0; 292 - } 293 - 294 - /** 295 - * zl3073x_dpll_selected_ref_set - select reference in manual mode 296 - * @zldpll: pointer to zl3073x_dpll 297 - * @ref: input reference to be selected 298 - * 299 - * Selects the given reference for the DPLL channel it should be 300 - * locked to. 301 - * 302 - * Return: 0 on success, <0 on error 303 - */ 304 - static int 305 - zl3073x_dpll_selected_ref_set(struct zl3073x_dpll *zldpll, u8 ref) 306 - { 307 - struct zl3073x_dev *zldev = zldpll->dev; 308 - u8 mode, mode_refsel; 309 - int rc; 310 - 311 - mode = zldpll->refsel_mode; 312 - 313 - switch (mode) { 314 - case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: 315 - /* Manual mode with ref selected */ 316 - if (ref == ZL3073X_DPLL_REF_NONE) { 317 - switch (zldpll->lock_status) { 318 - case DPLL_LOCK_STATUS_LOCKED_HO_ACQ: 319 - case DPLL_LOCK_STATUS_HOLDOVER: 320 - /* Switch to forced holdover */ 321 - mode = ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER; 322 - break; 323 - default: 324 - /* Switch to freerun */ 325 - mode = ZL_DPLL_MODE_REFSEL_MODE_FREERUN; 326 - break; 327 - } 328 - /* Keep selected reference */ 329 - ref = zldpll->forced_ref; 330 - } else if (ref == zldpll->forced_ref) { 331 - /* No register update - same mode and same ref */ 332 - return 0; 333 - } 334 - break; 335 - case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: 336 - case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: 337 - /* Manual mode without no ref */ 338 - if (ref == ZL3073X_DPLL_REF_NONE) 339 - /* No register update - keep current mode */ 340 - return 0; 341 - 342 - /* Switch to reflock mode and update ref selection */ 343 - mode = ZL_DPLL_MODE_REFSEL_MODE_REFLOCK; 344 - break; 345 - default: 346 - /* For other modes like automatic or NCO ref cannot be selected 347 - * manually 348 - */ 349 - return -EOPNOTSUPP; 350 - } 351 - 352 - /* Build mode_refsel value */ 353 - mode_refsel = FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, mode) | 354 - FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref); 355 - 356 - /* Update dpll_mode_refsel register */ 357 - rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), 358 - mode_refsel); 359 - if (rc) 360 - return rc; 361 - 362 - /* Store new mode and forced reference */ 363 - zldpll->refsel_mode = mode; 364 - zldpll->forced_ref = ref; 365 - 366 - return rc; 367 - } 368 - 369 - /** 370 249 * zl3073x_dpll_connected_ref_get - get currently connected reference 371 250 * @zldpll: pointer to zl3073x_dpll 372 - * @ref: place to store selected reference 373 251 * 374 - * Looks for currently connected the DPLL is locked to and stores its index 375 - * to given @ref. 252 + * Looks for currently connected reference the DPLL is locked to. 376 253 * 377 - * Return: 0 on success, <0 on error 254 + * Return: reference index if locked, ZL3073X_DPLL_REF_NONE otherwise 378 255 */ 379 - static int 380 - zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll, u8 *ref) 256 + static u8 257 + zl3073x_dpll_connected_ref_get(struct zl3073x_dpll *zldpll) 381 258 { 382 - struct zl3073x_dev *zldev = zldpll->dev; 383 - int rc; 259 + const struct zl3073x_chan *chan = zl3073x_chan_state_get(zldpll->dev, 260 + zldpll->id); 261 + u8 state; 384 262 385 - /* Get currently selected input reference */ 386 - rc = zl3073x_dpll_selected_ref_get(zldpll, ref); 387 - if (rc) 388 - return rc; 263 + /* A reference is connected only when the DPLL is locked to it */ 264 + state = zl3073x_chan_refsel_state_get(chan); 265 + if (state == ZL_DPLL_REFSEL_STATUS_STATE_LOCK) 266 + return zl3073x_chan_refsel_ref_get(chan); 389 267 390 - /* If the monitor indicates an error nothing is connected */ 391 - if (ZL3073X_DPLL_REF_IS_VALID(*ref) && 392 - !zl3073x_dev_ref_is_status_ok(zldev, *ref)) 393 - *ref = ZL3073X_DPLL_REF_NONE; 394 - 395 - return 0; 268 + return ZL3073X_DPLL_REF_NONE; 396 269 } 397 270 398 271 static int ··· 279 410 const struct zl3073x_ref *ref; 280 411 u8 conn_id, ref_id; 281 412 s64 ref_phase; 282 - int rc; 283 413 284 414 /* Get currently connected reference */ 285 - rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_id); 286 - if (rc) 287 - return rc; 415 + conn_id = zl3073x_dpll_connected_ref_get(zldpll); 288 416 289 417 /* Report phase offset only for currently connected pin if the phase 290 418 * monitor feature is disabled and only if the input pin signal is ··· 319 453 320 454 *phase_offset = ref_phase * DPLL_PHASE_OFFSET_DIVIDER; 321 455 322 - return rc; 456 + return 0; 323 457 } 324 458 325 459 static int ··· 383 517 } 384 518 385 519 /** 386 - * zl3073x_dpll_ref_prio_get - get priority for given input pin 387 - * @pin: pointer to pin 388 - * @prio: place to store priority 389 - * 390 - * Reads current priority for the given input pin and stores the value 391 - * to @prio. 392 - * 393 - * Return: 0 on success, <0 on error 394 - */ 395 - static int 396 - zl3073x_dpll_ref_prio_get(struct zl3073x_dpll_pin *pin, u8 *prio) 397 - { 398 - struct zl3073x_dpll *zldpll = pin->dpll; 399 - struct zl3073x_dev *zldev = zldpll->dev; 400 - u8 ref, ref_prio; 401 - int rc; 402 - 403 - guard(mutex)(&zldev->multiop_lock); 404 - 405 - /* Read DPLL configuration */ 406 - rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 407 - ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); 408 - if (rc) 409 - return rc; 410 - 411 - /* Read reference priority - one value for P&N pins (4 bits/pin) */ 412 - ref = zl3073x_input_pin_ref_get(pin->id); 413 - rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), 414 - &ref_prio); 415 - if (rc) 416 - return rc; 417 - 418 - /* Select nibble according pin type */ 419 - if (zl3073x_dpll_is_p_pin(pin)) 420 - *prio = FIELD_GET(ZL_DPLL_REF_PRIO_REF_P, ref_prio); 421 - else 422 - *prio = FIELD_GET(ZL_DPLL_REF_PRIO_REF_N, ref_prio); 423 - 424 - return rc; 425 - } 426 - 427 - /** 428 - * zl3073x_dpll_ref_prio_set - set priority for given input pin 429 - * @pin: pointer to pin 430 - * @prio: place to store priority 431 - * 432 - * Sets priority for the given input pin. 433 - * 434 - * Return: 0 on success, <0 on error 435 - */ 436 - static int 437 - zl3073x_dpll_ref_prio_set(struct zl3073x_dpll_pin *pin, u8 prio) 438 - { 439 - struct zl3073x_dpll *zldpll = pin->dpll; 440 - struct zl3073x_dev *zldev = zldpll->dev; 441 - u8 ref, ref_prio; 442 - int rc; 443 - 444 - guard(mutex)(&zldev->multiop_lock); 445 - 446 - /* Read DPLL configuration into mailbox */ 447 - rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 448 - ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); 449 - if (rc) 450 - return rc; 451 - 452 - /* Read reference priority - one value shared between P&N pins */ 453 - ref = zl3073x_input_pin_ref_get(pin->id); 454 - rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), &ref_prio); 455 - if (rc) 456 - return rc; 457 - 458 - /* Update nibble according pin type */ 459 - if (zl3073x_dpll_is_p_pin(pin)) { 460 - ref_prio &= ~ZL_DPLL_REF_PRIO_REF_P; 461 - ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_P, prio); 462 - } else { 463 - ref_prio &= ~ZL_DPLL_REF_PRIO_REF_N; 464 - ref_prio |= FIELD_PREP(ZL_DPLL_REF_PRIO_REF_N, prio); 465 - } 466 - 467 - /* Update reference priority */ 468 - rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_REF_PRIO(ref / 2), ref_prio); 469 - if (rc) 470 - return rc; 471 - 472 - /* Commit configuration */ 473 - return zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, 474 - ZL_REG_DPLL_MB_MASK, BIT(zldpll->id)); 475 - } 476 - 477 - /** 478 520 * zl3073x_dpll_ref_state_get - get status for given input pin 479 521 * @pin: pointer to pin 480 522 * @state: place to store status ··· 398 624 { 399 625 struct zl3073x_dpll *zldpll = pin->dpll; 400 626 struct zl3073x_dev *zldev = zldpll->dev; 401 - u8 ref, ref_conn; 402 - int rc; 627 + const struct zl3073x_chan *chan; 628 + u8 ref; 403 629 630 + chan = zl3073x_chan_state_get(zldev, zldpll->id); 404 631 ref = zl3073x_input_pin_ref_get(pin->id); 405 632 406 - /* Get currently connected reference */ 407 - rc = zl3073x_dpll_connected_ref_get(zldpll, &ref_conn); 408 - if (rc) 409 - return rc; 410 - 411 - if (ref == ref_conn) { 633 + /* Check if the pin reference is connected */ 634 + if (ref == zl3073x_dpll_connected_ref_get(zldpll)) { 412 635 *state = DPLL_PIN_STATE_CONNECTED; 413 636 return 0; 414 637 } ··· 414 643 * selectable and its monitor does not report any error then report 415 644 * pin as selectable. 416 645 */ 417 - if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_AUTO && 418 - zl3073x_dev_ref_is_status_ok(zldev, ref) && pin->selectable) { 646 + if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_AUTO && 647 + zl3073x_dev_ref_is_status_ok(zldev, ref) && 648 + zl3073x_chan_ref_is_selectable(chan, ref)) { 419 649 *state = DPLL_PIN_STATE_SELECTABLE; 420 650 return 0; 421 651 } ··· 450 678 { 451 679 struct zl3073x_dpll *zldpll = dpll_priv; 452 680 struct zl3073x_dpll_pin *pin = pin_priv; 453 - u8 new_ref; 681 + struct zl3073x_chan chan; 682 + u8 mode, ref; 454 683 int rc; 455 684 456 - switch (zldpll->refsel_mode) { 685 + chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); 686 + ref = zl3073x_input_pin_ref_get(pin->id); 687 + mode = zl3073x_chan_mode_get(&chan); 688 + 689 + switch (mode) { 457 690 case ZL_DPLL_MODE_REFSEL_MODE_REFLOCK: 691 + if (state == DPLL_PIN_STATE_CONNECTED) { 692 + /* Choose the pin as new selected reference */ 693 + zl3073x_chan_ref_set(&chan, ref); 694 + } else if (state == DPLL_PIN_STATE_DISCONNECTED) { 695 + /* Choose new mode based on lock status */ 696 + switch (zldpll->lock_status) { 697 + case DPLL_LOCK_STATUS_LOCKED_HO_ACQ: 698 + case DPLL_LOCK_STATUS_HOLDOVER: 699 + mode = ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER; 700 + break; 701 + default: 702 + mode = ZL_DPLL_MODE_REFSEL_MODE_FREERUN; 703 + break; 704 + } 705 + zl3073x_chan_mode_set(&chan, mode); 706 + } else { 707 + goto invalid_state; 708 + } 709 + break; 458 710 case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: 459 711 case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: 460 712 if (state == DPLL_PIN_STATE_CONNECTED) { 461 713 /* Choose the pin as new selected reference */ 462 - new_ref = zl3073x_input_pin_ref_get(pin->id); 463 - } else if (state == DPLL_PIN_STATE_DISCONNECTED) { 464 - /* No reference */ 465 - new_ref = ZL3073X_DPLL_REF_NONE; 466 - } else { 467 - NL_SET_ERR_MSG_MOD(extack, 468 - "Invalid pin state for manual mode"); 469 - return -EINVAL; 714 + zl3073x_chan_ref_set(&chan, ref); 715 + /* Switch to reflock mode */ 716 + zl3073x_chan_mode_set(&chan, 717 + ZL_DPLL_MODE_REFSEL_MODE_REFLOCK); 718 + } else if (state != DPLL_PIN_STATE_DISCONNECTED) { 719 + goto invalid_state; 470 720 } 471 - 472 - rc = zl3073x_dpll_selected_ref_set(zldpll, new_ref); 473 721 break; 474 - 475 722 case ZL_DPLL_MODE_REFSEL_MODE_AUTO: 476 723 if (state == DPLL_PIN_STATE_SELECTABLE) { 477 - if (pin->selectable) 724 + if (zl3073x_chan_ref_is_selectable(&chan, ref)) 478 725 return 0; /* Pin is already selectable */ 479 726 480 727 /* Restore pin priority in HW */ 481 - rc = zl3073x_dpll_ref_prio_set(pin, pin->prio); 482 - if (rc) 483 - return rc; 484 - 485 - /* Mark pin as selectable */ 486 - pin->selectable = true; 728 + zl3073x_chan_ref_prio_set(&chan, ref, pin->prio); 487 729 } else if (state == DPLL_PIN_STATE_DISCONNECTED) { 488 - if (!pin->selectable) 730 + if (!zl3073x_chan_ref_is_selectable(&chan, ref)) 489 731 return 0; /* Pin is already disconnected */ 490 732 491 733 /* Set pin priority to none in HW */ 492 - rc = zl3073x_dpll_ref_prio_set(pin, 493 - ZL_DPLL_REF_PRIO_NONE); 494 - if (rc) 495 - return rc; 496 - 497 - /* Mark pin as non-selectable */ 498 - pin->selectable = false; 734 + zl3073x_chan_ref_prio_set(&chan, ref, 735 + ZL_DPLL_REF_PRIO_NONE); 499 736 } else { 500 - NL_SET_ERR_MSG(extack, 501 - "Invalid pin state for automatic mode"); 502 - return -EINVAL; 737 + goto invalid_state; 503 738 } 504 739 break; 505 - 506 740 default: 507 741 /* In other modes we cannot change input reference */ 508 742 NL_SET_ERR_MSG(extack, 509 743 "Pin state cannot be changed in current mode"); 510 - rc = -EOPNOTSUPP; 511 - break; 744 + return -EOPNOTSUPP; 512 745 } 513 746 514 - return rc; 747 + /* Commit DPLL channel changes */ 748 + rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); 749 + if (rc) 750 + return rc; 751 + 752 + return 0; 753 + invalid_state: 754 + NL_SET_ERR_MSG_MOD(extack, "Invalid pin state for this device mode"); 755 + return -EINVAL; 515 756 } 516 757 517 758 static int ··· 544 759 const struct dpll_device *dpll, void *dpll_priv, 545 760 u32 prio, struct netlink_ext_ack *extack) 546 761 { 762 + struct zl3073x_dpll *zldpll = dpll_priv; 547 763 struct zl3073x_dpll_pin *pin = pin_priv; 764 + struct zl3073x_chan chan; 765 + u8 ref; 548 766 int rc; 549 767 550 768 if (prio > ZL_DPLL_REF_PRIO_MAX) 551 769 return -EINVAL; 552 770 553 771 /* If the pin is selectable then update HW registers */ 554 - if (pin->selectable) { 555 - rc = zl3073x_dpll_ref_prio_set(pin, prio); 772 + chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); 773 + ref = zl3073x_input_pin_ref_get(pin->id); 774 + if (zl3073x_chan_ref_is_selectable(&chan, ref)) { 775 + zl3073x_chan_ref_prio_set(&chan, ref, prio); 776 + rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); 556 777 if (rc) 557 778 return rc; 558 779 } ··· 882 1091 struct netlink_ext_ack *extack) 883 1092 { 884 1093 struct zl3073x_dpll *zldpll = dpll_priv; 885 - struct zl3073x_dev *zldev = zldpll->dev; 886 - u8 mon_status, state; 887 - int rc; 1094 + const struct zl3073x_chan *chan; 888 1095 889 - switch (zldpll->refsel_mode) { 1096 + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); 1097 + 1098 + switch (zl3073x_chan_mode_get(chan)) { 890 1099 case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: 891 1100 case ZL_DPLL_MODE_REFSEL_MODE_NCO: 892 1101 /* In FREERUN and NCO modes the DPLL is always unlocked */ ··· 897 1106 break; 898 1107 } 899 1108 900 - /* Read DPLL monitor status */ 901 - rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(zldpll->id), 902 - &mon_status); 903 - if (rc) 904 - return rc; 905 - state = FIELD_GET(ZL_DPLL_MON_STATUS_STATE, mon_status); 906 - 907 - switch (state) { 1109 + switch (zl3073x_chan_lock_state_get(chan)) { 908 1110 case ZL_DPLL_MON_STATUS_STATE_LOCK: 909 - if (FIELD_GET(ZL_DPLL_MON_STATUS_HO_READY, mon_status)) 1111 + if (zl3073x_chan_is_ho_ready(chan)) 910 1112 *status = DPLL_LOCK_STATUS_LOCKED_HO_ACQ; 911 1113 else 912 1114 *status = DPLL_LOCK_STATUS_LOCKED; ··· 909 1125 *status = DPLL_LOCK_STATUS_HOLDOVER; 910 1126 break; 911 1127 default: 912 - dev_warn(zldev->dev, "Unknown DPLL monitor status: 0x%02x\n", 913 - mon_status); 1128 + dev_warn(zldpll->dev->dev, 1129 + "Unknown DPLL monitor status: 0x%02x\n", 1130 + chan->mon_status); 914 1131 *status = DPLL_LOCK_STATUS_UNLOCKED; 915 1132 break; 916 1133 } ··· 925 1140 struct netlink_ext_ack *extack) 926 1141 { 927 1142 struct zl3073x_dpll *zldpll = dpll_priv; 1143 + const struct zl3073x_chan *chan; 1144 + 1145 + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); 928 1146 929 1147 /* We support switching between automatic and manual mode, except in 930 1148 * a case where the DPLL channel is configured to run in NCO mode. 931 1149 * In this case, report only the manual mode to which the NCO is mapped 932 1150 * as the only supported one. 933 1151 */ 934 - if (zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_NCO) 1152 + if (zl3073x_chan_mode_get(chan) != ZL_DPLL_MODE_REFSEL_MODE_NCO) 935 1153 __set_bit(DPLL_MODE_AUTOMATIC, modes); 936 1154 937 1155 __set_bit(DPLL_MODE_MANUAL, modes); ··· 947 1159 enum dpll_mode *mode, struct netlink_ext_ack *extack) 948 1160 { 949 1161 struct zl3073x_dpll *zldpll = dpll_priv; 1162 + const struct zl3073x_chan *chan; 950 1163 951 - switch (zldpll->refsel_mode) { 1164 + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); 1165 + 1166 + switch (zl3073x_chan_mode_get(chan)) { 952 1167 case ZL_DPLL_MODE_REFSEL_MODE_FREERUN: 953 1168 case ZL_DPLL_MODE_REFSEL_MODE_HOLDOVER: 954 1169 case ZL_DPLL_MODE_REFSEL_MODE_NCO: ··· 1030 1239 enum dpll_mode mode, struct netlink_ext_ack *extack) 1031 1240 { 1032 1241 struct zl3073x_dpll *zldpll = dpll_priv; 1033 - u8 hw_mode, mode_refsel, ref; 1242 + struct zl3073x_chan chan; 1243 + u8 hw_mode, ref; 1034 1244 int rc; 1035 1245 1036 - rc = zl3073x_dpll_selected_ref_get(zldpll, &ref); 1037 - if (rc) { 1038 - NL_SET_ERR_MSG_MOD(extack, "failed to get selected reference"); 1039 - return rc; 1040 - } 1246 + chan = *zl3073x_chan_state_get(zldpll->dev, zldpll->id); 1247 + ref = zl3073x_chan_refsel_ref_get(&chan); 1041 1248 1042 1249 if (mode == DPLL_MODE_MANUAL) { 1043 1250 /* We are switching from automatic to manual mode: ··· 1058 1269 * it is selectable after switch to automatic mode 1059 1270 * - switch to automatic mode 1060 1271 */ 1061 - struct zl3073x_dpll_pin *pin; 1272 + if (ZL3073X_DPLL_REF_IS_VALID(ref) && 1273 + !zl3073x_chan_ref_is_selectable(&chan, ref)) { 1274 + struct zl3073x_dpll_pin *pin; 1062 1275 1063 - pin = zl3073x_dpll_pin_get_by_ref(zldpll, ref); 1064 - if (pin && !pin->selectable) { 1065 - /* Restore pin priority in HW */ 1066 - rc = zl3073x_dpll_ref_prio_set(pin, pin->prio); 1067 - if (rc) { 1068 - NL_SET_ERR_MSG_MOD(extack, 1069 - "failed to restore pin priority"); 1070 - return rc; 1276 + pin = zl3073x_dpll_pin_get_by_ref(zldpll, ref); 1277 + if (pin) { 1278 + /* Restore pin priority in HW */ 1279 + zl3073x_chan_ref_prio_set(&chan, ref, 1280 + pin->prio); 1071 1281 } 1072 - 1073 - pin->selectable = true; 1074 1282 } 1075 1283 1076 1284 hw_mode = ZL_DPLL_MODE_REFSEL_MODE_AUTO; 1077 1285 } 1078 1286 1079 - /* Build mode_refsel value */ 1080 - mode_refsel = FIELD_PREP(ZL_DPLL_MODE_REFSEL_MODE, hw_mode); 1081 - 1287 + zl3073x_chan_mode_set(&chan, hw_mode); 1082 1288 if (ZL3073X_DPLL_REF_IS_VALID(ref)) 1083 - mode_refsel |= FIELD_PREP(ZL_DPLL_MODE_REFSEL_REF, ref); 1289 + zl3073x_chan_ref_set(&chan, ref); 1084 1290 1085 - /* Update dpll_mode_refsel register */ 1086 - rc = zl3073x_write_u8(zldpll->dev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), 1087 - mode_refsel); 1291 + rc = zl3073x_chan_state_set(zldpll->dev, zldpll->id, &chan); 1088 1292 if (rc) { 1089 1293 NL_SET_ERR_MSG_MOD(extack, 1090 1294 "failed to set reference selection mode"); 1091 1295 return rc; 1092 1296 } 1093 - 1094 - zldpll->refsel_mode = hw_mode; 1095 - 1096 - if (ZL3073X_DPLL_REF_IS_VALID(ref)) 1097 - zldpll->forced_ref = ref; 1098 1297 1099 1298 return 0; 1100 1299 } ··· 1224 1447 pin->phase_gran = props->dpll_props.phase_gran; 1225 1448 1226 1449 if (zl3073x_dpll_is_input_pin(pin)) { 1227 - rc = zl3073x_dpll_ref_prio_get(pin, &pin->prio); 1228 - if (rc) 1229 - goto err_prio_get; 1450 + const struct zl3073x_chan *chan; 1451 + u8 ref; 1230 1452 1231 - if (pin->prio == ZL_DPLL_REF_PRIO_NONE) { 1232 - /* Clamp prio to max value & mark pin non-selectable */ 1453 + chan = zl3073x_chan_state_get(zldpll->dev, zldpll->id); 1454 + ref = zl3073x_input_pin_ref_get(pin->id); 1455 + pin->prio = zl3073x_chan_ref_prio_get(chan, ref); 1456 + 1457 + if (pin->prio == ZL_DPLL_REF_PRIO_NONE) 1458 + /* Clamp prio to max value */ 1233 1459 pin->prio = ZL_DPLL_REF_PRIO_MAX; 1234 - pin->selectable = false; 1235 - } else { 1236 - /* Mark pin as selectable */ 1237 - pin->selectable = true; 1238 - } 1239 1460 } 1240 1461 1241 1462 /* Create or get existing DPLL pin */ ··· 1262 1487 1263 1488 err_register: 1264 1489 dpll_pin_put(pin->dpll_pin, &pin->tracker); 1265 - err_prio_get: 1266 1490 pin->dpll_pin = NULL; 1267 1491 err_pin_get: 1268 1492 zl3073x_pin_props_put(props); ··· 1333 1559 enum dpll_pin_direction dir, u8 index) 1334 1560 { 1335 1561 struct zl3073x_dev *zldev = zldpll->dev; 1562 + const struct zl3073x_chan *chan; 1336 1563 bool is_diff, is_enabled; 1337 1564 const char *name; 1565 + 1566 + chan = zl3073x_chan_state_get(zldev, zldpll->id); 1338 1567 1339 1568 if (dir == DPLL_PIN_DIRECTION_INPUT) { 1340 1569 u8 ref_id = zl3073x_input_pin_ref_get(index); 1341 1570 const struct zl3073x_ref *ref; 1342 1571 1343 1572 /* Skip the pin if the DPLL is running in NCO mode */ 1344 - if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO) 1573 + if (zl3073x_chan_mode_get(chan) == ZL_DPLL_MODE_REFSEL_MODE_NCO) 1345 1574 return false; 1346 1575 1347 1576 name = "REF"; ··· 1452 1675 zl3073x_dpll_device_register(struct zl3073x_dpll *zldpll) 1453 1676 { 1454 1677 struct zl3073x_dev *zldev = zldpll->dev; 1455 - u8 dpll_mode_refsel; 1456 1678 int rc; 1457 - 1458 - /* Read DPLL mode and forcibly selected reference */ 1459 - rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(zldpll->id), 1460 - &dpll_mode_refsel); 1461 - if (rc) 1462 - return rc; 1463 - 1464 - /* Extract mode and selected input reference */ 1465 - zldpll->refsel_mode = FIELD_GET(ZL_DPLL_MODE_REFSEL_MODE, 1466 - dpll_mode_refsel); 1467 - zldpll->forced_ref = FIELD_GET(ZL_DPLL_MODE_REFSEL_REF, 1468 - dpll_mode_refsel); 1469 1679 1470 1680 zldpll->ops = zl3073x_dpll_device_ops; 1471 1681 if (zldev->info->flags & ZL3073X_FLAG_DIE_TEMP) ··· 1608 1844 struct zl3073x_dev *zldev = zldpll->dev; 1609 1845 enum dpll_lock_status lock_status; 1610 1846 struct device *dev = zldev->dev; 1847 + const struct zl3073x_chan *chan; 1611 1848 struct zl3073x_dpll_pin *pin; 1612 1849 int rc; 1850 + u8 mode; 1613 1851 1614 1852 zldpll->check_count++; 1615 1853 ··· 1633 1867 /* Input pin monitoring does make sense only in automatic 1634 1868 * or forced reference modes. 1635 1869 */ 1636 - if (zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO && 1637 - zldpll->refsel_mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK) 1870 + chan = zl3073x_chan_state_get(zldev, zldpll->id); 1871 + mode = zl3073x_chan_mode_get(chan); 1872 + if (mode != ZL_DPLL_MODE_REFSEL_MODE_AUTO && 1873 + mode != ZL_DPLL_MODE_REFSEL_MODE_REFLOCK) 1638 1874 return; 1639 1875 1640 1876 /* Update phase offset latch registers for this DPLL if the phase
-4
drivers/dpll/zl3073x/dpll.h
··· 13 13 * @list: this DPLL list entry 14 14 * @dev: pointer to multi-function parent device 15 15 * @id: DPLL index 16 - * @refsel_mode: reference selection mode 17 - * @forced_ref: selected reference in forced reference lock mode 18 16 * @check_count: periodic check counter 19 17 * @phase_monitor: is phase offset monitor enabled 20 18 * @ops: DPLL device operations for this instance ··· 26 28 struct list_head list; 27 29 struct zl3073x_dev *dev; 28 30 u8 id; 29 - u8 refsel_mode; 30 - u8 forced_ref; 31 31 u8 check_count; 32 32 bool phase_monitor; 33 33 struct dpll_device_ops ops;
+21 -6
drivers/dpll/zl3073x/out.c
··· 106 106 return &zldev->out[index]; 107 107 } 108 108 109 + /** 110 + * zl3073x_out_state_set - commit output state changes to hardware 111 + * @zldev: pointer to zl3073x_dev structure 112 + * @index: output index to set state for 113 + * @out: desired output state 114 + * 115 + * Validates that invariant fields have not been modified, skips the HW 116 + * write if the mutable configuration is unchanged, and otherwise writes 117 + * only the changed cfg fields to hardware via the mailbox interface. 118 + * 119 + * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error 120 + */ 109 121 int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, 110 122 const struct zl3073x_out *out) 111 123 { 112 124 struct zl3073x_out *dout = &zldev->out[index]; 113 125 int rc; 126 + 127 + /* Reject attempts to change invariant fields (set at fetch only) */ 128 + if (WARN_ON(memcmp(&dout->inv, &out->inv, sizeof(out->inv)))) 129 + return -EINVAL; 130 + 131 + /* Skip HW write if configuration hasn't changed */ 132 + if (!memcmp(&dout->cfg, &out->cfg, sizeof(out->cfg))) 133 + return 0; 114 134 115 135 guard(mutex)(&zldev->multiop_lock); 116 136 ··· 166 146 return rc; 167 147 168 148 /* After successful commit store new state */ 169 - dout->div = out->div; 170 - dout->width = out->width; 171 - dout->esync_n_period = out->esync_n_period; 172 - dout->esync_n_width = out->esync_n_width; 173 - dout->mode = out->mode; 174 - dout->phase_comp = out->phase_comp; 149 + dout->cfg = out->cfg; 175 150 176 151 return 0; 177 152 }
+13 -8
drivers/dpll/zl3073x/out.h
··· 4 4 #define _ZL3073X_OUT_H 5 5 6 6 #include <linux/bitfield.h> 7 + #include <linux/stddef.h> 7 8 #include <linux/types.h> 8 9 9 10 #include "regs.h" ··· 18 17 * @esync_n_period: embedded sync or n-pin period (for n-div formats) 19 18 * @esync_n_width: embedded sync or n-pin pulse width 20 19 * @phase_comp: phase compensation 21 - * @ctrl: output control 22 20 * @mode: output mode 21 + * @ctrl: output control 23 22 */ 24 23 struct zl3073x_out { 25 - u32 div; 26 - u32 width; 27 - u32 esync_n_period; 28 - u32 esync_n_width; 29 - s32 phase_comp; 30 - u8 ctrl; 31 - u8 mode; 24 + struct_group(cfg, /* Config */ 25 + u32 div; 26 + u32 width; 27 + u32 esync_n_period; 28 + u32 esync_n_width; 29 + s32 phase_comp; 30 + u8 mode; 31 + ); 32 + struct_group(inv, /* Invariants */ 33 + u8 ctrl; 34 + ); 32 35 }; 33 36 34 37 int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index);
+43 -15
drivers/dpll/zl3073x/ref.c
··· 52 52 } 53 53 54 54 /** 55 + * zl3073x_ref_state_update - update input reference status from HW 56 + * @zldev: pointer to zl3073x_dev structure 57 + * @index: input reference index 58 + * 59 + * Return: 0 on success, <0 on error 60 + */ 61 + int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index) 62 + { 63 + struct zl3073x_ref *ref = &zldev->ref[index]; 64 + 65 + return zl3073x_read_u8(zldev, ZL_REG_REF_MON_STATUS(index), 66 + &ref->mon_status); 67 + } 68 + 69 + /** 55 70 * zl3073x_ref_state_fetch - fetch input reference state from hardware 56 71 * @zldev: pointer to zl3073x_dev structure 57 72 * @index: input reference index to fetch state for ··· 88 73 struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ 89 74 90 75 /* Copy the shared items from the P-pin */ 91 - ref->config = p_ref->config; 92 - ref->esync_n_div = p_ref->esync_n_div; 93 - ref->freq_base = p_ref->freq_base; 94 - ref->freq_mult = p_ref->freq_mult; 95 - ref->freq_ratio_m = p_ref->freq_ratio_m; 96 - ref->freq_ratio_n = p_ref->freq_ratio_n; 97 - ref->phase_comp = p_ref->phase_comp; 98 - ref->sync_ctrl = p_ref->sync_ctrl; 76 + ref->cfg = p_ref->cfg; 77 + ref->inv = p_ref->inv; 99 78 100 79 return 0; /* Finish - no non-shared items for now */ 101 80 } 81 + 82 + /* Read reference status */ 83 + rc = zl3073x_ref_state_update(zldev, index); 84 + if (rc) 85 + return rc; 102 86 103 87 guard(mutex)(&zldev->multiop_lock); 104 88 ··· 168 154 return &zldev->ref[index]; 169 155 } 170 156 157 + /** 158 + * zl3073x_ref_state_set - commit input reference state changes to hardware 159 + * @zldev: pointer to zl3073x_dev structure 160 + * @index: input reference index to set state for 161 + * @ref: desired reference state 162 + * 163 + * Validates that invariant fields have not been modified, skips the HW 164 + * write if the mutable configuration is unchanged, and otherwise writes 165 + * only the changed cfg fields to hardware via the mailbox interface. 166 + * 167 + * Return: 0 on success, -EINVAL if invariants changed, <0 on HW error 168 + */ 171 169 int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 172 170 const struct zl3073x_ref *ref) 173 171 { 174 172 struct zl3073x_ref *dref = &zldev->ref[index]; 175 173 int rc; 174 + 175 + /* Reject attempts to change invariant fields (set at init only) */ 176 + if (WARN_ON(memcmp(&dref->inv, &ref->inv, sizeof(ref->inv)))) 177 + return -EINVAL; 178 + 179 + /* Skip HW write if configuration hasn't changed */ 180 + if (!memcmp(&dref->cfg, &ref->cfg, sizeof(ref->cfg))) 181 + return 0; 176 182 177 183 guard(mutex)(&zldev->multiop_lock); 178 184 ··· 241 207 return rc; 242 208 243 209 /* After successful commit store new state */ 244 - dref->freq_base = ref->freq_base; 245 - dref->freq_mult = ref->freq_mult; 246 - dref->freq_ratio_m = ref->freq_ratio_m; 247 - dref->freq_ratio_n = ref->freq_ratio_n; 248 - dref->esync_n_div = ref->esync_n_div; 249 - dref->sync_ctrl = ref->sync_ctrl; 250 - dref->phase_comp = ref->phase_comp; 210 + dref->cfg = ref->cfg; 251 211 252 212 return 0; 253 213 }
+21 -12
drivers/dpll/zl3073x/ref.h
··· 5 5 6 6 #include <linux/bitfield.h> 7 7 #include <linux/math64.h> 8 + #include <linux/stddef.h> 8 9 #include <linux/types.h> 9 10 10 11 #include "regs.h" ··· 14 13 15 14 /** 16 15 * struct zl3073x_ref - input reference state 17 - * @ffo: current fractional frequency offset 18 16 * @phase_comp: phase compensation 19 17 * @esync_n_div: divisor for embedded sync or n-divided signal formats 20 18 * @freq_base: frequency base 21 19 * @freq_mult: frequnecy multiplier 22 20 * @freq_ratio_m: FEC mode multiplier 23 21 * @freq_ratio_n: FEC mode divisor 24 - * @config: reference config 25 22 * @sync_ctrl: reference sync control 23 + * @config: reference config 24 + * @ffo: current fractional frequency offset 26 25 * @mon_status: reference monitor status 27 26 */ 28 27 struct zl3073x_ref { 29 - s64 ffo; 30 - u64 phase_comp; 31 - u32 esync_n_div; 32 - u16 freq_base; 33 - u16 freq_mult; 34 - u16 freq_ratio_m; 35 - u16 freq_ratio_n; 36 - u8 config; 37 - u8 sync_ctrl; 38 - u8 mon_status; 28 + struct_group(cfg, /* Configuration */ 29 + u64 phase_comp; 30 + u32 esync_n_div; 31 + u16 freq_base; 32 + u16 freq_mult; 33 + u16 freq_ratio_m; 34 + u16 freq_ratio_n; 35 + u8 sync_ctrl; 36 + ); 37 + struct_group(inv, /* Invariants */ 38 + u8 config; 39 + ); 40 + struct_group(stat, /* Status */ 41 + s64 ffo; 42 + u8 mon_status; 43 + ); 39 44 }; 40 45 41 46 int zl3073x_ref_state_fetch(struct zl3073x_dev *zldev, u8 index); ··· 51 44 52 45 int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 53 46 const struct zl3073x_ref *ref); 47 + 48 + int zl3073x_ref_state_update(struct zl3073x_dev *zldev, u8 index); 54 49 55 50 int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); 56 51
+12
drivers/dpll/zl3073x/regs.h
··· 7 7 #include <linux/bits.h> 8 8 9 9 /* 10 + * Hardware limits for ZL3073x chip family 11 + */ 12 + #define ZL3073X_MAX_CHANNELS 5 13 + #define ZL3073X_NUM_REFS 10 14 + #define ZL3073X_NUM_OUTS 10 15 + #define ZL3073X_NUM_SYNTHS 5 16 + #define ZL3073X_NUM_INPUT_PINS ZL3073X_NUM_REFS 17 + #define ZL3073X_NUM_OUTPUT_PINS (ZL3073X_NUM_OUTS * 2) 18 + #define ZL3073X_NUM_PINS (ZL3073X_NUM_INPUT_PINS + \ 19 + ZL3073X_NUM_OUTPUT_PINS) 20 + 21 + /* 10 22 * Register address structure: 11 23 * =========================== 12 24 * 25 19 18 16 15 7 6 0
+8 -8
drivers/dpll/zl3073x/synth.h
··· 5 5 6 6 #include <linux/bitfield.h> 7 7 #include <linux/math64.h> 8 + #include <linux/stddef.h> 8 9 #include <linux/types.h> 9 10 10 11 #include "regs.h" ··· 21 20 * @ctrl: synth control 22 21 */ 23 22 struct zl3073x_synth { 24 - u32 freq_mult; 25 - u16 freq_base; 26 - u16 freq_m; 27 - u16 freq_n; 28 - u8 ctrl; 23 + struct_group(inv, /* Invariants */ 24 + u32 freq_mult; 25 + u16 freq_base; 26 + u16 freq_m; 27 + u16 freq_n; 28 + u8 ctrl; 29 + ); 29 30 }; 30 31 31 32 int zl3073x_synth_state_fetch(struct zl3073x_dev *zldev, u8 synth_id); 32 33 33 34 const struct zl3073x_synth *zl3073x_synth_state_get(struct zl3073x_dev *zldev, 34 35 u8 synth_id); 35 - 36 - int zl3073x_synth_state_set(struct zl3073x_dev *zldev, u8 synth_id, 37 - const struct zl3073x_synth *synth); 38 36 39 37 /** 40 38 * zl3073x_synth_dpll_get - get DPLL ID the synth is driven by