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

dpll: zl3073x: Cache all reference properties in zl3073x_ref

Expand the zl3073x_ref structure to cache all reference-related
hardware registers, including frequency components, embedded-sync
settings and phase compensation. Previously, these registers were
read on-demand from various functions in dpll.c leading to frequent
mailbox operations.

Modify zl3073x_ref_state_fetch() to read and populate all these new
fields at once. Refactor all "getter" functions in dpll.c to read
from this new cached state instead of performing direct register
access.

Remove the standalone zl3073x_dpll_input_ref_frequency_get() helper,
as its functionality is now replaced by zl3073x_ref_freq_get() which
operates on the cached state and add a corresponding zl3073x_dev_...
wrapper.

Introduce a new function, zl3073x_ref_state_set(), to handle
writing changes back to the hardware. This function compares the
provided state with the current cached state and writes *only* the
modified register values to the device via a single mailbox sequence
before updating the local cache.

Refactor all dpll "setter" functions to modify a local copy of the
ref state and then call zl3073x_ref_state_set() to commit the changes.

As a cleanup, update callers in dpll.c that already have
a struct zl3073x_ref * to use the direct helpers instead of the
zl3073x_dev_... wrappers.

This change centralizes all reference-related register I/O into ref.c,
significantly reduces bus traffic, and simplifies the logic in dpll.c.

Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20251113074105.141379-5-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Ivan Vecera and committed by
Jakub Kicinski
5bc02b19 5534a820

+239 -232
+15
drivers/dpll/zl3073x/core.h
··· 198 198 } 199 199 200 200 /** 201 + * zl3073x_dev_ref_freq_get - get input reference frequency 202 + * @zldev: pointer to zl3073x device 203 + * @index: input reference index 204 + * 205 + * Return: frequency of given input reference 206 + */ 207 + static inline u32 208 + zl3073x_dev_ref_freq_get(struct zl3073x_dev *zldev, u8 index) 209 + { 210 + const struct zl3073x_ref *ref = zl3073x_ref_state_get(zldev, index); 211 + 212 + return zl3073x_ref_freq_get(ref); 213 + } 214 + 215 + /** 201 216 * zl3073x_dev_ref_is_diff - check if the given input reference is differential 202 217 * @zldev: pointer to zl3073x device 203 218 * @index: input reference index
+77 -231
drivers/dpll/zl3073x/dpll.c
··· 100 100 return 0; 101 101 } 102 102 103 - /** 104 - * zl3073x_dpll_input_ref_frequency_get - get input reference frequency 105 - * @zldpll: pointer to zl3073x_dpll 106 - * @ref_id: reference id 107 - * @frequency: pointer to variable to store frequency 108 - * 109 - * Reads frequency of given input reference. 110 - * 111 - * Return: 0 on success, <0 on error 112 - */ 113 - static int 114 - zl3073x_dpll_input_ref_frequency_get(struct zl3073x_dpll *zldpll, u8 ref_id, 115 - u32 *frequency) 116 - { 117 - struct zl3073x_dev *zldev = zldpll->dev; 118 - u16 base, mult, num, denom; 119 - int rc; 120 - 121 - guard(mutex)(&zldev->multiop_lock); 122 - 123 - /* Read reference configuration */ 124 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 125 - ZL_REG_REF_MB_MASK, BIT(ref_id)); 126 - if (rc) 127 - return rc; 128 - 129 - /* Read registers to compute resulting frequency */ 130 - rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &base); 131 - if (rc) 132 - return rc; 133 - rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &mult); 134 - if (rc) 135 - return rc; 136 - rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &num); 137 - if (rc) 138 - return rc; 139 - rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &denom); 140 - if (rc) 141 - return rc; 142 - 143 - /* Sanity check that HW has not returned zero denominator */ 144 - if (!denom) { 145 - dev_err(zldev->dev, 146 - "Zero divisor for ref %u frequency got from device\n", 147 - ref_id); 148 - return -EINVAL; 149 - } 150 - 151 - /* Compute the frequency */ 152 - *frequency = mul_u64_u32_div(base * mult, num, denom); 153 - 154 - return rc; 155 - } 156 - 157 103 static int 158 104 zl3073x_dpll_input_pin_esync_get(const struct dpll_pin *dpll_pin, 159 105 void *pin_priv, ··· 111 165 struct zl3073x_dpll *zldpll = dpll_priv; 112 166 struct zl3073x_dev *zldev = zldpll->dev; 113 167 struct zl3073x_dpll_pin *pin = pin_priv; 114 - u8 ref, ref_sync_ctrl, sync_mode; 115 - u32 esync_div, ref_freq; 116 - int rc; 168 + const struct zl3073x_ref *ref; 169 + u8 ref_id; 117 170 118 - /* Get reference frequency */ 119 - ref = zl3073x_input_pin_ref_get(pin->id); 120 - rc = zl3073x_dpll_input_ref_frequency_get(zldpll, pin->id, &ref_freq); 121 - if (rc) 122 - return rc; 171 + ref_id = zl3073x_input_pin_ref_get(pin->id); 172 + ref = zl3073x_ref_state_get(zldev, ref_id); 123 173 124 - guard(mutex)(&zldev->multiop_lock); 125 - 126 - /* Read reference configuration into mailbox */ 127 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 128 - ZL_REG_REF_MB_MASK, BIT(ref)); 129 - if (rc) 130 - return rc; 131 - 132 - /* Get ref sync mode */ 133 - rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl); 134 - if (rc) 135 - return rc; 136 - 137 - /* Get esync divisor */ 138 - rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &esync_div); 139 - if (rc) 140 - return rc; 141 - 142 - sync_mode = FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref_sync_ctrl); 143 - 144 - switch (sync_mode) { 174 + switch (FIELD_GET(ZL_REF_SYNC_CTRL_MODE, ref->sync_ctrl)) { 145 175 case ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75: 146 - esync->freq = (esync_div == ZL_REF_ESYNC_DIV_1HZ) ? 1 : 0; 176 + esync->freq = ref->esync_n_div == ZL_REF_ESYNC_DIV_1HZ ? 1 : 0; 147 177 esync->pulse = 25; 148 178 break; 149 179 default: ··· 131 209 /* If the pin supports esync control expose its range but only 132 210 * if the current reference frequency is > 1 Hz. 133 211 */ 134 - if (pin->esync_control && ref_freq > 1) { 212 + if (pin->esync_control && zl3073x_ref_freq_get(ref) > 1) { 135 213 esync->range = esync_freq_ranges; 136 214 esync->range_num = ARRAY_SIZE(esync_freq_ranges); 137 215 } else { ··· 139 217 esync->range_num = 0; 140 218 } 141 219 142 - return rc; 220 + return 0; 143 221 } 144 222 145 223 static int ··· 152 230 struct zl3073x_dpll *zldpll = dpll_priv; 153 231 struct zl3073x_dev *zldev = zldpll->dev; 154 232 struct zl3073x_dpll_pin *pin = pin_priv; 155 - u8 ref, ref_sync_ctrl, sync_mode; 156 - int rc; 233 + struct zl3073x_ref ref; 234 + u8 ref_id, sync_mode; 157 235 158 - guard(mutex)(&zldev->multiop_lock); 159 - 160 - /* Read reference configuration into mailbox */ 161 - ref = zl3073x_input_pin_ref_get(pin->id); 162 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 163 - ZL_REG_REF_MB_MASK, BIT(ref)); 164 - if (rc) 165 - return rc; 166 - 167 - /* Get ref sync mode */ 168 - rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref_sync_ctrl); 169 - if (rc) 170 - return rc; 236 + ref_id = zl3073x_input_pin_ref_get(pin->id); 237 + ref = *zl3073x_ref_state_get(zldev, ref_id); 171 238 172 239 /* Use freq == 0 to disable esync */ 173 240 if (!freq) ··· 164 253 else 165 254 sync_mode = ZL_REF_SYNC_CTRL_MODE_50_50_ESYNC_25_75; 166 255 167 - ref_sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE; 168 - ref_sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode); 169 - 170 - /* Update ref sync control register */ 171 - rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, ref_sync_ctrl); 172 - if (rc) 173 - return rc; 256 + ref.sync_ctrl &= ~ZL_REF_SYNC_CTRL_MODE; 257 + ref.sync_ctrl |= FIELD_PREP(ZL_REF_SYNC_CTRL_MODE, sync_mode); 174 258 175 259 if (freq) { 176 - /* 1 Hz is only supported frequnecy currently */ 177 - rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV, 178 - ZL_REF_ESYNC_DIV_1HZ); 179 - if (rc) 180 - return rc; 260 + /* 1 Hz is only supported frequency now */ 261 + ref.esync_n_div = ZL_REF_ESYNC_DIV_1HZ; 181 262 } 182 263 183 - /* Commit reference configuration */ 184 - return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 185 - ZL_REG_REF_MB_MASK, BIT(ref)); 264 + /* Update reference configuration */ 265 + return zl3073x_ref_state_set(zldev, ref_id, &ref); 186 266 } 187 267 188 268 static int ··· 197 295 { 198 296 struct zl3073x_dpll *zldpll = dpll_priv; 199 297 struct zl3073x_dpll_pin *pin = pin_priv; 200 - u32 ref_freq; 201 - u8 ref; 202 - int rc; 298 + u8 ref_id; 203 299 204 - /* Read and return ref frequency */ 205 - ref = zl3073x_input_pin_ref_get(pin->id); 206 - rc = zl3073x_dpll_input_ref_frequency_get(zldpll, ref, &ref_freq); 207 - if (!rc) 208 - *frequency = ref_freq; 300 + ref_id = zl3073x_input_pin_ref_get(pin->id); 301 + *frequency = zl3073x_dev_ref_freq_get(zldpll->dev, ref_id); 209 302 210 - return rc; 303 + return 0; 211 304 } 212 305 213 306 static int ··· 215 318 struct zl3073x_dpll *zldpll = dpll_priv; 216 319 struct zl3073x_dev *zldev = zldpll->dev; 217 320 struct zl3073x_dpll_pin *pin = pin_priv; 218 - u16 base, mult; 219 - u8 ref; 220 - int rc; 321 + struct zl3073x_ref ref; 322 + u8 ref_id; 221 323 222 - /* Get base frequency and multiplier for the requested frequency */ 223 - rc = zl3073x_ref_freq_factorize(frequency, &base, &mult); 224 - if (rc) 225 - return rc; 324 + /* Get reference state */ 325 + ref_id = zl3073x_input_pin_ref_get(pin->id); 326 + ref = *zl3073x_ref_state_get(zldev, ref_id); 226 327 227 - guard(mutex)(&zldev->multiop_lock); 328 + /* Update frequency */ 329 + zl3073x_ref_freq_set(&ref, frequency); 228 330 229 - /* Load reference configuration */ 230 - ref = zl3073x_input_pin_ref_get(pin->id); 231 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 232 - ZL_REG_REF_MB_MASK, BIT(ref)); 233 - 234 - /* Update base frequency, multiplier, numerator & denominator */ 235 - rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, base); 236 - if (rc) 237 - return rc; 238 - rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, mult); 239 - if (rc) 240 - return rc; 241 - rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, 1); 242 - if (rc) 243 - return rc; 244 - rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, 1); 245 - if (rc) 246 - return rc; 247 - 248 - /* Commit reference configuration */ 249 - return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 250 - ZL_REG_REF_MB_MASK, BIT(ref)); 331 + /* Commit reference state */ 332 + return zl3073x_ref_state_set(zldev, ref_id, &ref); 251 333 } 252 334 253 335 /** ··· 391 515 struct zl3073x_dpll *zldpll = dpll_priv; 392 516 struct zl3073x_dev *zldev = zldpll->dev; 393 517 struct zl3073x_dpll_pin *pin = pin_priv; 394 - u8 conn_ref, ref; 518 + const struct zl3073x_ref *ref; 519 + u8 conn_id, ref_id; 395 520 s64 ref_phase; 396 521 int rc; 397 522 398 523 /* Get currently connected reference */ 399 - rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_ref); 524 + rc = zl3073x_dpll_connected_ref_get(zldpll, &conn_id); 400 525 if (rc) 401 526 return rc; 402 527 403 528 /* Report phase offset only for currently connected pin if the phase 404 - * monitor feature is disabled. 529 + * monitor feature is disabled and only if the input pin signal is 530 + * present. 405 531 */ 406 - ref = zl3073x_input_pin_ref_get(pin->id); 407 - if ((!zldpll->phase_monitor && ref != conn_ref) || 408 - !zl3073x_dev_ref_is_status_ok(zldev, ref)) { 532 + ref_id = zl3073x_input_pin_ref_get(pin->id); 533 + ref = zl3073x_ref_state_get(zldev, ref_id); 534 + if ((!zldpll->phase_monitor && ref_id != conn_id) || 535 + !zl3073x_ref_is_status_ok(ref)) { 409 536 *phase_offset = 0; 410 537 return 0; 411 538 } ··· 419 540 * the phase offset is modded to the period of the signal 420 541 * the dpll is locked to. 421 542 */ 422 - if (ZL3073X_DPLL_REF_IS_VALID(conn_ref) && conn_ref != ref) { 543 + if (ZL3073X_DPLL_REF_IS_VALID(conn_id) && conn_id != ref_id) { 423 544 u32 conn_freq, ref_freq; 424 545 425 - /* Get frequency of connected ref */ 426 - rc = zl3073x_dpll_input_ref_frequency_get(zldpll, conn_ref, 427 - &conn_freq); 428 - if (rc) 429 - return rc; 430 - 431 - /* Get frequency of given ref */ 432 - rc = zl3073x_dpll_input_ref_frequency_get(zldpll, ref, 433 - &ref_freq); 434 - if (rc) 435 - return rc; 546 + /* Get frequency of connected and given ref */ 547 + conn_freq = zl3073x_dev_ref_freq_get(zldev, conn_id); 548 + ref_freq = zl3073x_ref_freq_get(ref); 436 549 437 550 if (conn_freq > ref_freq) { 438 551 s64 conn_period, div_factor; ··· 451 580 struct zl3073x_dpll *zldpll = dpll_priv; 452 581 struct zl3073x_dev *zldev = zldpll->dev; 453 582 struct zl3073x_dpll_pin *pin = pin_priv; 583 + const struct zl3073x_ref *ref; 454 584 s64 phase_comp; 455 - u8 ref; 456 - int rc; 457 - 458 - guard(mutex)(&zldev->multiop_lock); 585 + u8 ref_id; 459 586 460 587 /* Read reference configuration */ 461 - ref = zl3073x_input_pin_ref_get(pin->id); 462 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 463 - ZL_REG_REF_MB_MASK, BIT(ref)); 464 - if (rc) 465 - return rc; 466 - 467 - /* Read current phase offset compensation */ 468 - rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, &phase_comp); 469 - if (rc) 470 - return rc; 588 + ref_id = zl3073x_input_pin_ref_get(pin->id); 589 + ref = zl3073x_ref_state_get(zldev, ref_id); 471 590 472 591 /* Perform sign extension for 48bit signed value */ 473 - phase_comp = sign_extend64(phase_comp, 47); 592 + phase_comp = sign_extend64(ref->phase_comp, 47); 474 593 475 594 /* Reverse two's complement negation applied during set and convert 476 595 * to 32bit signed int 477 596 */ 478 597 *phase_adjust = (s32)-phase_comp; 479 598 480 - return rc; 599 + return 0; 481 600 } 482 601 483 602 static int ··· 481 620 struct zl3073x_dpll *zldpll = dpll_priv; 482 621 struct zl3073x_dev *zldev = zldpll->dev; 483 622 struct zl3073x_dpll_pin *pin = pin_priv; 484 - s64 phase_comp; 485 - u8 ref; 486 - int rc; 623 + struct zl3073x_ref ref; 624 + u8 ref_id; 625 + 626 + /* Read reference configuration */ 627 + ref_id = zl3073x_input_pin_ref_get(pin->id); 628 + ref = *zl3073x_ref_state_get(zldev, ref_id); 487 629 488 630 /* The value in the register is stored as two's complement negation 489 631 * of requested value. 490 632 */ 491 - phase_comp = -phase_adjust; 633 + ref.phase_comp = -phase_adjust; 492 634 493 - guard(mutex)(&zldev->multiop_lock); 494 - 495 - /* Read reference configuration */ 496 - ref = zl3073x_input_pin_ref_get(pin->id); 497 - rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 498 - ZL_REG_REF_MB_MASK, BIT(ref)); 499 - if (rc) 500 - return rc; 501 - 502 - /* Write the requested value into the compensation register */ 503 - rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, phase_comp); 504 - if (rc) 505 - return rc; 506 - 507 - /* Commit reference configuration */ 508 - return zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 509 - ZL_REG_REF_MB_MASK, BIT(ref)); 635 + /* Update reference configuration */ 636 + return zl3073x_ref_state_set(zldev, ref_id, &ref); 510 637 } 511 638 512 639 /** ··· 1665 1816 const char *name; 1666 1817 1667 1818 if (dir == DPLL_PIN_DIRECTION_INPUT) { 1668 - u8 ref = zl3073x_input_pin_ref_get(index); 1669 - 1670 - name = "REF"; 1819 + u8 ref_id = zl3073x_input_pin_ref_get(index); 1820 + const struct zl3073x_ref *ref; 1671 1821 1672 1822 /* Skip the pin if the DPLL is running in NCO mode */ 1673 1823 if (zldpll->refsel_mode == ZL_DPLL_MODE_REFSEL_MODE_NCO) 1674 1824 return false; 1675 1825 1676 - is_diff = zl3073x_dev_ref_is_diff(zldev, ref); 1677 - is_enabled = zl3073x_dev_ref_is_enabled(zldev, ref); 1826 + name = "REF"; 1827 + ref = zl3073x_ref_state_get(zldev, ref_id); 1828 + is_diff = zl3073x_ref_is_diff(ref); 1829 + is_enabled = zl3073x_ref_is_enabled(ref); 1678 1830 } else { 1679 1831 /* Output P&N pair shares single HW output */ 1680 1832 u8 out = zl3073x_output_pin_out_get(index); ··· 1849 1999 struct zl3073x_dev *zldev = zldpll->dev; 1850 2000 unsigned int reg; 1851 2001 s64 phase_offset; 1852 - u8 ref; 2002 + u8 ref_id; 1853 2003 int rc; 1854 2004 1855 - ref = zl3073x_input_pin_ref_get(pin->id); 1856 - 1857 2005 /* No phase offset if the ref monitor reports signal errors */ 1858 - if (!zl3073x_dev_ref_is_status_ok(zldev, ref)) 2006 + ref_id = zl3073x_input_pin_ref_get(pin->id); 2007 + if (!zl3073x_dev_ref_is_status_ok(zldev, ref_id)) 1859 2008 return false; 1860 2009 1861 2010 /* Select register to read phase offset value depending on pin and ··· 1866 2017 if (pin->pin_state == DPLL_PIN_STATE_CONNECTED) 1867 2018 reg = ZL_REG_DPLL_PHASE_ERR_DATA(zldpll->id); 1868 2019 else if (zldpll->phase_monitor) 1869 - reg = ZL_REG_REF_PHASE(ref); 2020 + reg = ZL_REG_REF_PHASE(ref_id); 1870 2021 else 1871 - /* The pin is not connected or phase monitor disabled */ 1872 2022 return false; 1873 2023 1874 2024 /* Read measured phase offset value */ ··· 1907 2059 { 1908 2060 struct zl3073x_dpll *zldpll = pin->dpll; 1909 2061 struct zl3073x_dev *zldev = zldpll->dev; 1910 - s64 ffo; 1911 - u8 ref; 2062 + const struct zl3073x_ref *ref; 2063 + u8 ref_id; 1912 2064 1913 2065 /* Get reference monitor status */ 1914 - ref = zl3073x_input_pin_ref_get(pin->id); 2066 + ref_id = zl3073x_input_pin_ref_get(pin->id); 2067 + ref = zl3073x_ref_state_get(zldev, ref_id); 1915 2068 1916 2069 /* Do not report ffo changes if the reference monitor report errors */ 1917 - if (!zl3073x_dev_ref_is_status_ok(zldev, ref)) 2070 + if (!zl3073x_ref_is_status_ok(ref)) 1918 2071 return false; 1919 2072 1920 - /* Get the latest measured ref's ffo */ 1921 - ffo = zl3073x_dev_ref_ffo_get(zldev, ref); 1922 - 1923 2073 /* Compare with previous value */ 1924 - if (pin->freq_offset != ffo) { 2074 + if (pin->freq_offset != ref->ffo) { 1925 2075 dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n", 1926 - pin->label, pin->freq_offset, ffo); 1927 - pin->freq_offset = ffo; 2076 + pin->label, pin->freq_offset, ref->ffo); 2077 + pin->freq_offset = ref->ffo; 1928 2078 1929 2079 return true; 1930 2080 }
+93 -1
drivers/dpll/zl3073x/ref.c
··· 70 70 * part of the configuration with the P-pin counterpart. 71 71 */ 72 72 if (zl3073x_is_n_pin(index) && zl3073x_ref_is_diff(ref - 1)) { 73 - struct zl3073x_ref *p_ref = &zldev->ref[index - 1]; 73 + struct zl3073x_ref *p_ref = ref - 1; /* P-pin counterpart*/ 74 74 75 75 /* Copy the shared items from the P-pin */ 76 76 ref->config = p_ref->config; 77 + ref->esync_n_div = p_ref->esync_n_div; 78 + ref->freq_base = p_ref->freq_base; 79 + ref->freq_mult = p_ref->freq_mult; 80 + ref->freq_ratio_m = p_ref->freq_ratio_m; 81 + ref->freq_ratio_n = p_ref->freq_ratio_n; 82 + ref->phase_comp = p_ref->phase_comp; 83 + ref->sync_ctrl = p_ref->sync_ctrl; 77 84 78 85 return 0; /* Finish - no non-shared items for now */ 79 86 } ··· 95 88 96 89 /* Read ref_config register */ 97 90 rc = zl3073x_read_u8(zldev, ZL_REG_REF_CONFIG, &ref->config); 91 + if (rc) 92 + return rc; 93 + 94 + /* Read frequency related registers */ 95 + rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_BASE, &ref->freq_base); 96 + if (rc) 97 + return rc; 98 + rc = zl3073x_read_u16(zldev, ZL_REG_REF_FREQ_MULT, &ref->freq_mult); 99 + if (rc) 100 + return rc; 101 + rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_M, &ref->freq_ratio_m); 102 + if (rc) 103 + return rc; 104 + rc = zl3073x_read_u16(zldev, ZL_REG_REF_RATIO_N, &ref->freq_ratio_n); 105 + if (rc) 106 + return rc; 107 + 108 + /* Read eSync and N-div rated registers */ 109 + rc = zl3073x_read_u32(zldev, ZL_REG_REF_ESYNC_DIV, &ref->esync_n_div); 110 + if (rc) 111 + return rc; 112 + rc = zl3073x_read_u8(zldev, ZL_REG_REF_SYNC_CTRL, &ref->sync_ctrl); 113 + if (rc) 114 + return rc; 115 + 116 + /* Read phase compensation register */ 117 + rc = zl3073x_read_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, 118 + &ref->phase_comp); 98 119 if (rc) 99 120 return rc; 100 121 ··· 144 109 zl3073x_ref_state_get(struct zl3073x_dev *zldev, u8 index) 145 110 { 146 111 return &zldev->ref[index]; 112 + } 113 + 114 + int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 115 + const struct zl3073x_ref *ref) 116 + { 117 + struct zl3073x_ref *dref = &zldev->ref[index]; 118 + int rc; 119 + 120 + guard(mutex)(&zldev->multiop_lock); 121 + 122 + /* Read reference configuration into mailbox */ 123 + rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_RD, 124 + ZL_REG_REF_MB_MASK, BIT(index)); 125 + if (rc) 126 + return rc; 127 + 128 + /* Update mailbox with changed values */ 129 + if (dref->freq_base != ref->freq_base) 130 + rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_BASE, 131 + ref->freq_base); 132 + if (!rc && dref->freq_mult != ref->freq_mult) 133 + rc = zl3073x_write_u16(zldev, ZL_REG_REF_FREQ_MULT, 134 + ref->freq_mult); 135 + if (!rc && dref->freq_ratio_m != ref->freq_ratio_m) 136 + rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_M, 137 + ref->freq_ratio_m); 138 + if (!rc && dref->freq_ratio_n != ref->freq_ratio_n) 139 + rc = zl3073x_write_u16(zldev, ZL_REG_REF_RATIO_N, 140 + ref->freq_ratio_n); 141 + if (!rc && dref->esync_n_div != ref->esync_n_div) 142 + rc = zl3073x_write_u32(zldev, ZL_REG_REF_ESYNC_DIV, 143 + ref->esync_n_div); 144 + if (!rc && dref->sync_ctrl != ref->sync_ctrl) 145 + rc = zl3073x_write_u8(zldev, ZL_REG_REF_SYNC_CTRL, 146 + ref->sync_ctrl); 147 + if (!rc && dref->phase_comp != ref->phase_comp) 148 + rc = zl3073x_write_u48(zldev, ZL_REG_REF_PHASE_OFFSET_COMP, 149 + ref->phase_comp); 150 + if (rc) 151 + return rc; 152 + 153 + /* Commit reference configuration */ 154 + rc = zl3073x_mb_op(zldev, ZL_REG_REF_MB_SEM, ZL_REF_MB_SEM_WR, 155 + ZL_REG_REF_MB_MASK, BIT(index)); 156 + if (rc) 157 + return rc; 158 + 159 + /* After successful commit store new state */ 160 + dref->freq_base = ref->freq_base; 161 + dref->freq_mult = ref->freq_mult; 162 + dref->freq_ratio_m = ref->freq_ratio_m; 163 + dref->freq_ratio_n = ref->freq_ratio_n; 164 + dref->esync_n_div = ref->esync_n_div; 165 + dref->sync_ctrl = ref->sync_ctrl; 166 + dref->phase_comp = ref->phase_comp; 167 + 168 + return 0; 147 169 }
+54
drivers/dpll/zl3073x/ref.h
··· 4 4 #define _ZL3073X_REF_H 5 5 6 6 #include <linux/bitfield.h> 7 + #include <linux/math64.h> 7 8 #include <linux/types.h> 8 9 9 10 #include "regs.h" ··· 14 13 /** 15 14 * struct zl3073x_ref - input reference state 16 15 * @ffo: current fractional frequency offset 16 + * @phase_comp: phase compensation 17 + * @esync_n_div: divisor for embedded sync or n-divided signal formats 18 + * @freq_base: frequency base 19 + * @freq_mult: frequnecy multiplier 20 + * @freq_ratio_m: FEC mode multiplier 21 + * @freq_ratio_n: FEC mode divisor 17 22 * @config: reference config 23 + * @sync_ctrl: reference sync control 18 24 * @mon_status: reference monitor status 19 25 */ 20 26 struct zl3073x_ref { 21 27 s64 ffo; 28 + u64 phase_comp; 29 + u32 esync_n_div; 30 + u16 freq_base; 31 + u16 freq_mult; 32 + u16 freq_ratio_m; 33 + u16 freq_ratio_n; 22 34 u8 config; 35 + u8 sync_ctrl; 23 36 u8 mon_status; 24 37 }; 25 38 ··· 41 26 42 27 const struct zl3073x_ref *zl3073x_ref_state_get(struct zl3073x_dev *zldev, 43 28 u8 index); 29 + 30 + int zl3073x_ref_state_set(struct zl3073x_dev *zldev, u8 index, 31 + const struct zl3073x_ref *ref); 44 32 45 33 int zl3073x_ref_freq_factorize(u32 freq, u16 *base, u16 *mult); 46 34 ··· 57 39 zl3073x_ref_ffo_get(const struct zl3073x_ref *ref) 58 40 { 59 41 return ref->ffo; 42 + } 43 + 44 + /** 45 + * zl3073x_ref_freq_get - get given input reference frequency 46 + * @ref: pointer to ref state 47 + * 48 + * Return: frequency of the given input reference 49 + */ 50 + static inline u32 51 + zl3073x_ref_freq_get(const struct zl3073x_ref *ref) 52 + { 53 + return mul_u64_u32_div(ref->freq_base * ref->freq_mult, 54 + ref->freq_ratio_m, ref->freq_ratio_n); 55 + } 56 + 57 + /** 58 + * zl3073x_ref_freq_set - set given input reference frequency 59 + * @ref: pointer to ref state 60 + * @freq: frequency to be set 61 + * 62 + * Return: 0 on success, <0 when frequency cannot be factorized 63 + */ 64 + static inline int 65 + zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq) 66 + { 67 + u16 base, mult; 68 + int rc; 69 + 70 + rc = zl3073x_ref_freq_factorize(freq, &base, &mult); 71 + if (rc) 72 + return rc; 73 + 74 + ref->freq_base = base; 75 + ref->freq_mult = mult; 76 + 77 + return 0; 60 78 } 61 79 62 80 /**