1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/cleanup.h> 4 #include <linux/delay.h> 5 #include <linux/dev_printk.h> 6 #include <linux/ptp_clock_kernel.h> 7 #include <linux/string.h> 8 #include <linux/types.h> 9 10 #include "chan.h" 11 #include "core.h" 12 13 /** 14 * zl3073x_chan_state_update - update DPLL channel status from HW 15 * @zldev: pointer to zl3073x_dev structure 16 * @index: DPLL channel index 17 * 18 * Return: 0 on success, <0 on error 19 */ 20 int zl3073x_chan_state_update(struct zl3073x_dev *zldev, u8 index) 21 { 22 struct zl3073x_chan *chan = &zldev->chan[index]; 23 u64 val; 24 int rc; 25 26 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MON_STATUS(index), 27 &chan->mon_status); 28 if (rc) 29 return rc; 30 31 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REFSEL_STATUS(index), 32 &chan->refsel_status); 33 if (rc) 34 return rc; 35 36 /* Read df_offset only when locked to a reference. In NCO mode 37 * df_offset was captured at entry by nco_mode_set() - preserve it. 38 */ 39 if (!zl3073x_chan_is_locked(chan)) { 40 if (!zl3073x_chan_mode_is_nco(chan)) 41 chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN; 42 return 0; 43 } 44 45 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index), 46 ZL_DPLL_DF_READ_SEM, 47 ZL_POLL_DF_READ_TIMEOUT_US); 48 if (rc) 49 return rc; 50 51 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index), 52 ZL_DPLL_DF_READ_SEM | ZL_DPLL_DF_READ_REF_OFST); 53 if (rc) 54 return rc; 55 56 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_DF_READ(index), 57 ZL_DPLL_DF_READ_SEM, 58 ZL_POLL_DF_READ_TIMEOUT_US); 59 if (rc) 60 return rc; 61 62 rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val); 63 if (rc) 64 return rc; 65 66 chan->df_offset = sign_extend64(val, 47); 67 68 return 0; 69 } 70 71 /** 72 * zl3073x_chan_nco_mode_set - switch DPLL channel to NCO mode 73 * @zldev: pointer to zl3073x_dev structure 74 * @index: DPLL channel index 75 * 76 * Switches the channel to NCO mode and reads the df_offset 77 * auto-captured by nco_auto_read directly from the register. 78 * No DF_READ handshake is needed as nco_auto_read populates 79 * the register before the mode switch completes. 80 * 81 * Return: 0 on success, <0 on error 82 */ 83 int zl3073x_chan_nco_mode_set(struct zl3073x_dev *zldev, u8 index) 84 { 85 struct zl3073x_chan *chan = &zldev->chan[index]; 86 u8 prev_mode, df_read; 87 u64 val; 88 int rc; 89 90 prev_mode = zl3073x_chan_mode_get(chan); 91 92 /* nco_auto_read captures the tracking offset at NCO entry only 93 * from reflock, auto or holdover mode. From freerun the captured 94 * value is not meaningful. 95 */ 96 if (prev_mode == ZL_DPLL_MODE_REFSEL_MODE_FREERUN) { 97 zl3073x_chan_mode_set(chan, ZL_DPLL_MODE_REFSEL_MODE_NCO); 98 99 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 100 chan->mode_refsel); 101 if (rc) { 102 zl3073x_chan_mode_set(chan, prev_mode); 103 return rc; 104 } 105 106 chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN; 107 return 0; 108 } 109 110 /* Configure df_read for nco_auto_read: 111 * ref_ofst=0 - reads offset relative to master clock (not input ref) 112 * cmd=CMD_ACC_I - accumulated I-part covering both locked and 113 * holdover entry. 114 * 115 * No semaphore is set - this only configures what the df_offset 116 * value represents after the mode switch; nco_auto_read performs 117 * the actual read automatically. 118 */ 119 df_read = FIELD_PREP(ZL_DPLL_DF_READ_REF_OFST, 0) | 120 FIELD_PREP(ZL_DPLL_DF_READ_CMD, ZL_DPLL_DF_READ_CMD_ACC_I); 121 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_DF_READ(index), df_read); 122 if (rc) 123 return rc; 124 125 /* Wait for df_read configuration to take effect before 126 * triggering nco_auto_read via mode switch. The worst-case 127 * internal register update time is 25 ms. 128 */ 129 fsleep(25000); 130 131 zl3073x_chan_mode_set(chan, ZL_DPLL_MODE_REFSEL_MODE_NCO); 132 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 133 chan->mode_refsel); 134 if (rc) { 135 zl3073x_chan_mode_set(chan, prev_mode); 136 return rc; 137 } 138 139 /* Wait for nco_auto_read to populate df_offset. The worst-case 140 * internal register update time is 25 ms. 141 */ 142 fsleep(25000); 143 144 /* Read df_offset captured by nco_auto_read during mode switch. 145 * No DF_READ semaphore handshake needed. Mode switch already 146 * succeeded, so don't propagate a read failure back to userspace. 147 */ 148 rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_DF_OFFSET(index), &val); 149 if (rc) { 150 dev_warn(zldev->dev, 151 "Failed to read DPLL%u df_offset: %pe\n", 152 index, ERR_PTR(rc)); 153 chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN; 154 } else { 155 chan->df_offset = sign_extend64(val, 47); 156 } 157 158 return 0; 159 } 160 161 /** 162 * zl3073x_chan_state_fetch - fetch DPLL channel state from hardware 163 * @zldev: pointer to zl3073x_dev structure 164 * @index: DPLL channel index to fetch state for 165 * 166 * Reads the mode_refsel, status and reference priority registers for 167 * the given DPLL channel and stores the values for later use. 168 * 169 * Return: 0 on success, <0 on error 170 */ 171 int zl3073x_chan_state_fetch(struct zl3073x_dev *zldev, u8 index) 172 { 173 struct zl3073x_chan *chan = &zldev->chan[index]; 174 int rc, i; 175 176 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_CTRL(index), &chan->ctrl); 177 if (rc) 178 return rc; 179 180 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 181 &chan->mode_refsel); 182 if (rc) 183 return rc; 184 185 dev_dbg(zldev->dev, "DPLL%u mode: %u, ref: %u\n", index, 186 zl3073x_chan_mode_get(chan), zl3073x_chan_ref_get(chan)); 187 188 rc = zl3073x_chan_state_update(zldev, index); 189 if (rc) 190 return rc; 191 192 /* If firmware left the channel in NCO mode, mark df_offset as 193 * unknown - we cannot know whether the preconditions for a valid 194 * nco_auto_read capture were met. 195 */ 196 if (zl3073x_chan_mode_is_nco(chan)) 197 chan->df_offset = ZL_DPLL_DF_OFFSET_UNKNOWN; 198 199 dev_dbg(zldev->dev, 200 "DPLL%u lock_state: %u, ho: %u, sel_state: %u, sel_ref: %u\n", 201 index, zl3073x_chan_lock_state_get(chan), 202 zl3073x_chan_is_ho_ready(chan) ? 1 : 0, 203 zl3073x_chan_refsel_state_get(chan), 204 zl3073x_chan_refsel_ref_get(chan)); 205 206 guard(mutex)(&zldev->multiop_lock); 207 208 /* Read DPLL configuration from mailbox */ 209 rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 210 ZL_REG_DPLL_MB_MASK, BIT(index)); 211 if (rc) 212 return rc; 213 214 /* Read reference priority registers */ 215 for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { 216 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_REF_PRIO(i), 217 &chan->ref_prio[i]); 218 if (rc) 219 return rc; 220 } 221 222 return 0; 223 } 224 225 /** 226 * zl3073x_chan_state_get - get current DPLL channel state 227 * @zldev: pointer to zl3073x_dev structure 228 * @index: DPLL channel index to get state for 229 * 230 * Return: pointer to given DPLL channel state 231 */ 232 const struct zl3073x_chan *zl3073x_chan_state_get(struct zl3073x_dev *zldev, 233 u8 index) 234 { 235 return &zldev->chan[index]; 236 } 237 238 /** 239 * zl3073x_chan_tod_ready_wait - wait for ToD semaphore to clear 240 * @zldev: pointer to zl3073x device 241 * @ch: DPLL channel index 242 * 243 * Checks the ToD control register semaphore bit. If clear, returns 244 * immediately. Otherwise polls until the bit is cleared by the device. 245 * 246 * Return: 247 * * 0 - success 248 * * %-EBUSY - timeout 249 * * %-EOPNOTSUPP - unknown command detected 250 * * negative - other error 251 */ 252 int zl3073x_chan_tod_ready_wait(struct zl3073x_dev *zldev, u8 ch) 253 { 254 unsigned int timeout; 255 u8 tod_ctrl; 256 int rc; 257 258 rc = zl3073x_read_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), &tod_ctrl); 259 if (rc) 260 return rc; 261 262 if (!(tod_ctrl & ZL_DPLL_TOD_CTRL_SEM)) 263 return 0; 264 265 switch (FIELD_GET(ZL_DPLL_TOD_CTRL_CMD, tod_ctrl)) { 266 case ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ: 267 timeout = ZL_POLL_TOD_WR_TIMEOUT_US; 268 break; 269 case ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT: 270 case ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ: 271 timeout = ZL_POLL_TOD_RD_TIMEOUT_US; 272 break; 273 default: 274 return -EOPNOTSUPP; 275 } 276 277 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), 278 ZL_DPLL_TOD_CTRL_SEM, timeout); 279 280 return rc == -ETIMEDOUT ? -EBUSY : rc; 281 } 282 283 /** 284 * zl3073x_chan_tod_ctrl - issue ToD command 285 * @zldev: pointer to zl3073x device 286 * @ch: DPLL channel index 287 * @cmd: ToD command to execute 288 * 289 * Writes the semaphore and command to dpll_tod_ctrl. The caller must 290 * ensure the device is ready (semaphore clear) before calling and 291 * must wait for completion if needed. 292 * 293 * Return: 0 on success, <0 on error 294 */ 295 static int zl3073x_chan_tod_ctrl(struct zl3073x_dev *zldev, u8 ch, u8 cmd) 296 { 297 return zl3073x_write_u8(zldev, ZL_REG_DPLL_TOD_CTRL(ch), 298 ZL_DPLL_TOD_CTRL_SEM | cmd); 299 } 300 301 /** 302 * zl3073x_chan_tod_read - read ToD registers after issuing a command 303 * @zldev: pointer to zl3073x device 304 * @ch: DPLL channel index 305 * @next_hz: if true, read predicted ToD at next 1 Hz; otherwise read current 306 * @ts: timespec to store the result 307 * @sts: optional system timestamp pair for cross-timestamping 308 * 309 * Context: Caller must serialize all zl3073x_chan_tod_* calls externally. 310 * Return: 0 on success, <0 on error 311 */ 312 int zl3073x_chan_tod_read(struct zl3073x_dev *zldev, u8 ch, 313 bool next_hz, struct timespec64 *ts, 314 struct ptp_system_timestamp *sts) 315 { 316 u32 nsec; 317 u64 sec; 318 u8 cmd; 319 int rc; 320 321 if (next_hz) 322 cmd = ZL_DPLL_TOD_CTRL_CMD_RD_NEXT_1HZ; 323 else 324 cmd = ZL_DPLL_TOD_CTRL_CMD_RD_CURRENT; 325 326 /* Wait for any previous ToD operation to complete */ 327 rc = zl3073x_chan_tod_ready_wait(zldev, ch); 328 if (rc) 329 return rc; 330 331 ptp_read_system_prets(sts); 332 rc = zl3073x_chan_tod_ctrl(zldev, ch, cmd); 333 if (rc) 334 return rc; 335 336 rc = zl3073x_chan_tod_ready_wait(zldev, ch); 337 if (rc) 338 return rc; 339 ptp_read_system_postts(sts); 340 341 rc = zl3073x_read_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), &sec); 342 if (rc) 343 return rc; 344 345 /* HW nanoseconds are always in [0, NSEC_PER_SEC) range */ 346 rc = zl3073x_read_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), &nsec); 347 if (rc) 348 return rc; 349 350 ts->tv_sec = sec; 351 ts->tv_nsec = nsec; 352 353 return 0; 354 } 355 356 /** 357 * zl3073x_chan_tod_write - write ToD registers and trigger 1 Hz update 358 * @zldev: pointer to zl3073x device 359 * @ch: DPLL channel index 360 * @ts: time to set 361 * 362 * Context: Caller must serialize all zl3073x_chan_tod_* calls externally. 363 * Return: 0 on success, <0 on error 364 */ 365 int zl3073x_chan_tod_write(struct zl3073x_dev *zldev, u8 ch, 366 struct timespec64 ts) 367 { 368 int rc; 369 370 /* Wait for any previous ToD operation to complete */ 371 rc = zl3073x_chan_tod_ready_wait(zldev, ch); 372 if (rc) 373 return rc; 374 375 rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TOD_SEC(ch), ts.tv_sec); 376 if (rc) 377 return rc; 378 379 rc = zl3073x_write_u32(zldev, ZL_REG_DPLL_TOD_NS(ch), ts.tv_nsec); 380 if (rc) 381 return rc; 382 383 return zl3073x_chan_tod_ctrl(zldev, ch, 384 ZL_DPLL_TOD_CTRL_CMD_WR_NEXT_1HZ); 385 } 386 387 /** 388 * zl3073x_chan_tod_adjust - atomic ToD read-modify-write with rollover guard 389 * @zldev: pointer to zl3073x device 390 * @ch: DPLL channel index 391 * @delta: time adjustment to apply 392 * 393 * Reads the next-Hz ToD and current ToD, then checks whether enough time 394 * remains before the next 1 Hz rollover to safely complete the write. 395 * Re-reads if the 1 Hz tick crossed between the two reads or if less 396 * than 20 ms remains before the next rollover. Applies @delta and writes 397 * the result back. 398 * 399 * Context: Caller must serialize all zl3073x_chan_tod_* calls externally. 400 * Return: 0 on success, <0 on error 401 */ 402 int zl3073x_chan_tod_adjust(struct zl3073x_dev *zldev, u8 ch, 403 struct timespec64 delta) 404 { 405 #define ZL_TOD_MAX_RETRIES 20 406 static const long threshold_ns = 20 * NSEC_PER_MSEC; 407 struct timespec64 ts_next, ts_cur, diff; 408 int rc, i; 409 410 for (i = 0; i < ZL_TOD_MAX_RETRIES; i++) { 411 rc = zl3073x_chan_tod_read(zldev, ch, true, &ts_next, NULL); 412 if (rc) 413 return rc; 414 415 rc = zl3073x_chan_tod_read(zldev, ch, false, &ts_cur, NULL); 416 if (rc) 417 return rc; 418 419 /* Ensure the 1 Hz tick did not cross between the two reads 420 * and that enough margin remains to complete the write. 421 */ 422 diff = timespec64_sub(ts_next, ts_cur); 423 if (diff.tv_sec > 0 || 424 (!diff.tv_sec && diff.tv_nsec >= threshold_ns)) 425 break; 426 } 427 if (i == ZL_TOD_MAX_RETRIES) { 428 dev_warn(zldev->dev, 429 "DPLL%u ToD adjust failed to get stable margin\n", 430 ch); 431 return -EBUSY; 432 } 433 434 /* Apply delta to the next-Hz ToD */ 435 ts_next = timespec64_add(ts_next, delta); 436 if (!timespec64_valid_settod(&ts_next)) 437 return -EINVAL; 438 439 return zl3073x_chan_tod_write(zldev, ch, ts_next); 440 #undef ZL_TOD_MAX_RETRIES 441 } 442 443 /** 444 * zl3073x_chan_df_offset_set - write delta frequency offset to hardware 445 * @zldev: pointer to zl3073x device 446 * @ch: DPLL channel index 447 * @offset: frequency offset in 2^-48 steps 448 * 449 * Context: Caller must hold the per-DPLL lock. 450 * Return: 0 on success, <0 on error 451 */ 452 int zl3073x_chan_df_offset_set(struct zl3073x_dev *zldev, u8 ch, s64 offset) 453 { 454 int rc; 455 456 rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_DF_OFFSET(ch), offset); 457 if (!rc) 458 zldev->chan[ch].df_offset = offset; 459 460 return rc; 461 } 462 463 /** 464 * zl3073x_chan_tie_write - adjust DPLL phase using TIE write 465 * @zldev: pointer to zl3073x device 466 * @ch: DPLL channel index 467 * @delta_ns: phase adjustment in nanoseconds (must be in (-1s, 1s)) 468 * 469 * Converts nanoseconds to TIE units (0.01 ps) and writes TIE data 470 * to the specified channel. 471 * 472 * Return: 0 on success, <0 on error 473 */ 474 int zl3073x_chan_tie_write(struct zl3073x_dev *zldev, u8 ch, s64 delta_ns) 475 { 476 s64 tie_data; 477 int rc; 478 479 guard(mutex)(&zldev->tie_lock); 480 481 /* Wait for any previous TIE operation to complete */ 482 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_DPLL_TIE_CTRL, 483 ZL_DPLL_TIE_CTRL_OP, 484 ZL_POLL_TIE_WR_TIMEOUT_US); 485 if (rc) 486 return rc; 487 488 /* Convert ns to TIE units (0.01 ps = 10^-14 s) */ 489 tie_data = delta_ns * 100000LL; 490 491 rc = zl3073x_write_u48(zldev, ZL_REG_DPLL_TIE_DATA(ch), tie_data); 492 if (rc) 493 return rc; 494 495 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL_MASK, BIT(ch)); 496 if (rc) 497 return rc; 498 499 return zl3073x_write_u8(zldev, ZL_REG_DPLL_TIE_CTRL, 500 ZL_DPLL_TIE_CTRL_OP_WR); 501 } 502 503 /** 504 * zl3073x_chan_phase_step - execute one output phase step operation 505 * @zldev: pointer to zl3073x device 506 * @ch: DPLL channel index 507 * @out_mask: bitmask of outputs to step 508 * @step_cycles: phase step in synthesizer clock cycles 509 * @tod_step: also step the ToD counter 510 * 511 * All masked outputs must use synthesizers of the same frequency since 512 * the step value is in synthesizer clock cycles. 513 * 514 * Return: 0 on success, <0 on error 515 */ 516 int zl3073x_chan_phase_step(struct zl3073x_dev *zldev, u8 ch, 517 u16 out_mask, s32 step_cycles, 518 bool tod_step) 519 { 520 u8 ctrl; 521 int rc; 522 523 guard(mutex)(&zldev->phase_step_lock); 524 525 /* Wait for any previous phase step operation to complete */ 526 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL, 527 ZL_OUTPUT_PHASE_STEP_CTRL_OP, 528 ZL_POLL_PHASE_STEP_TIMEOUT_US); 529 if (rc) 530 return rc; 531 532 rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_STEP_DATA, 533 step_cycles); 534 if (rc) 535 return rc; 536 537 rc = zl3073x_write_u16(zldev, ZL_REG_OUTPUT_PHASE_STEP_MASK, out_mask); 538 if (rc) 539 return rc; 540 541 rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_NUMBER, 1); 542 if (rc) 543 return rc; 544 545 ctrl = FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_DPLL, ch) | 546 FIELD_PREP(ZL_OUTPUT_PHASE_STEP_CTRL_OP, 547 ZL_OUTPUT_PHASE_STEP_CTRL_OP_WRITE); 548 if (tod_step) 549 ctrl |= ZL_OUTPUT_PHASE_STEP_CTRL_TOD_STEP; 550 551 return zl3073x_write_u8(zldev, ZL_REG_OUTPUT_PHASE_STEP_CTRL, ctrl); 552 } 553 554 /** 555 * zl3073x_chan_state_set - commit DPLL channel state changes to hardware 556 * @zldev: pointer to zl3073x_dev structure 557 * @index: DPLL channel index to set state for 558 * @chan: desired channel state 559 * 560 * Skips the HW write if the configuration is unchanged, and otherwise 561 * writes only the changed registers to hardware. The mode_refsel register 562 * is written directly, while the reference priority registers are written 563 * via the DPLL mailbox interface. 564 * 565 * Return: 0 on success, <0 on HW error 566 */ 567 int zl3073x_chan_state_set(struct zl3073x_dev *zldev, u8 index, 568 const struct zl3073x_chan *chan) 569 { 570 struct zl3073x_chan *dchan = &zldev->chan[index]; 571 int rc, i; 572 573 /* Skip HW write if configuration hasn't changed */ 574 if (!memcmp(&dchan->cfg, &chan->cfg, sizeof(chan->cfg))) 575 return 0; 576 577 /* Direct register writes for ctrl and mode_refsel */ 578 if (dchan->ctrl != chan->ctrl) { 579 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_CTRL(index), 580 chan->ctrl); 581 if (rc) 582 return rc; 583 dchan->ctrl = chan->ctrl; 584 } 585 586 if (dchan->mode_refsel != chan->mode_refsel) { 587 rc = zl3073x_write_u8(zldev, ZL_REG_DPLL_MODE_REFSEL(index), 588 chan->mode_refsel); 589 if (rc) 590 return rc; 591 dchan->mode_refsel = chan->mode_refsel; 592 } 593 594 /* Mailbox write for ref_prio if changed */ 595 if (!memcmp(dchan->ref_prio, chan->ref_prio, sizeof(chan->ref_prio))) { 596 dchan->cfg = chan->cfg; 597 return 0; 598 } 599 600 guard(mutex)(&zldev->multiop_lock); 601 602 /* Read DPLL configuration into mailbox */ 603 rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_RD, 604 ZL_REG_DPLL_MB_MASK, BIT(index)); 605 if (rc) 606 return rc; 607 608 /* Update changed ref_prio registers */ 609 for (i = 0; i < ARRAY_SIZE(chan->ref_prio); i++) { 610 if (dchan->ref_prio[i] != chan->ref_prio[i]) { 611 rc = zl3073x_write_u8(zldev, 612 ZL_REG_DPLL_REF_PRIO(i), 613 chan->ref_prio[i]); 614 if (rc) 615 return rc; 616 } 617 } 618 619 /* Commit DPLL configuration */ 620 rc = zl3073x_mb_op(zldev, ZL_REG_DPLL_MB_SEM, ZL_DPLL_MB_SEM_WR, 621 ZL_REG_DPLL_MB_MASK, BIT(index)); 622 if (rc) 623 return rc; 624 625 /* After successful write store new state */ 626 dchan->cfg = chan->cfg; 627 628 return 0; 629 } 630