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-add-frequency-monitoring-feature'

Ivan Vecera says:

====================
dpll: add frequency monitoring feature

This series adds support for monitoring the measured input frequency
of DPLL input pins via the DPLL netlink interface.

Some DPLL devices can measure the actual frequency being received on
input pins. The approach mirrors the existing phase-offset-monitor
feature: a device-level attribute (DPLL_A_FREQUENCY_MONITOR) enables
or disables monitoring, and a per-pin attribute
(DPLL_A_PIN_MEASURED_FREQUENCY) exposes the measured frequency in
millihertz (mHz) when monitoring is enabled.

Patch 1 adds the new attributes to the DPLL netlink spec (dpll.yaml),
the DPLL_PIN_MEASURED_FREQUENCY_DIVIDER constant, regenerates the
auto-generated UAPI header and netlink policy, and updates
Documentation/driver-api/dpll.rst.

Patch 2 adds the callback operations (freq_monitor_get/set for
devices, measured_freq_get for pins) and the corresponding netlink
GET/SET handlers in the DPLL core. The core only invokes
measured_freq_get when the frequency monitor is enabled on the parent
device. The freq_monitor_get callback is required when measured_freq_get
is provided.

Patch 3 implements the feature in the ZL3073x driver by extracting
a common measurement latch helper from the existing FFO update path,
adding a frequency measurement function, and wiring up the new
callbacks.
====================

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

+353 -21
+20
Documentation/driver-api/dpll.rst
··· 250 250 ``DPLL_A_PHASE_OFFSET_MONITOR`` attr state of a feature 251 251 =============================== ======================== 252 252 253 + Frequency monitor 254 + ================= 255 + 256 + Some DPLL devices may offer the capability to measure the actual 257 + frequency of all available input pins. The attribute and current feature state 258 + shall be included in the response message of the ``DPLL_CMD_DEVICE_GET`` 259 + command for supported DPLL devices. In such cases, users can also control 260 + the feature using the ``DPLL_CMD_DEVICE_SET`` command by setting the 261 + ``enum dpll_feature_state`` values for the attribute. 262 + Once enabled the measured input frequency for each input pin shall be 263 + returned in the ``DPLL_A_PIN_MEASURED_FREQUENCY`` attribute. The value 264 + is in millihertz (mHz), using ``DPLL_PIN_MEASURED_FREQUENCY_DIVIDER`` 265 + as the divider. 266 + 267 + =============================== ======================== 268 + ``DPLL_A_FREQUENCY_MONITOR`` attr state of a feature 269 + =============================== ======================== 270 + 253 271 Embedded SYNC 254 272 ============= 255 273 ··· 429 411 ``DPLL_A_PIN_STATE`` attr state of pin on the parent 430 412 pin 431 413 ``DPLL_A_PIN_CAPABILITIES`` attr bitmask of pin capabilities 414 + ``DPLL_A_PIN_MEASURED_FREQUENCY`` attr measured frequency of 415 + an input pin in mHz 432 416 ==================================== ================================== 433 417 434 418 ==================================== =================================
+35
Documentation/netlink/specs/dpll.yaml
··· 241 241 Value of (DPLL_A_PHASE_OFFSET % DPLL_PHASE_OFFSET_DIVIDER) is a 242 242 fractional part of a measured phase offset value. 243 243 - 244 + type: const 245 + name: pin-measured-frequency-divider 246 + value: 1000 247 + doc: | 248 + pin measured frequency divider allows userspace to calculate 249 + a value of measured input frequency as a fractional value with 250 + three digit decimal precision (millihertz). 251 + Value of (DPLL_A_PIN_MEASURED_FREQUENCY / 252 + DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part of 253 + a measured frequency value. 254 + Value of (DPLL_A_PIN_MEASURED_FREQUENCY % 255 + DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part of 256 + a measured frequency value. 257 + - 244 258 type: enum 245 259 name: feature-state 246 260 doc: | ··· 333 319 name: phase-offset-avg-factor 334 320 type: u32 335 321 doc: Averaging factor applied to calculation of reported phase offset. 322 + - 323 + name: frequency-monitor 324 + type: u32 325 + enum: feature-state 326 + doc: Current or desired state of the frequency monitor feature. 327 + If enabled, dpll device shall measure all currently available 328 + inputs for their actual input frequency. 336 329 - 337 330 name: pin 338 331 enum-name: dpll_a_pin ··· 477 456 Value is in PPT (parts per trillion, 10^-12). 478 457 Note: This attribute provides higher resolution than the standard 479 458 fractional-frequency-offset (which is in PPM). 459 + - 460 + name: measured-frequency 461 + type: u64 462 + doc: | 463 + The measured frequency of the input pin in millihertz (mHz). 464 + Value of (DPLL_A_PIN_MEASURED_FREQUENCY / 465 + DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is an integer part (Hz) 466 + of a measured frequency value. 467 + Value of (DPLL_A_PIN_MEASURED_FREQUENCY % 468 + DPLL_PIN_MEASURED_FREQUENCY_DIVIDER) is a fractional part 469 + of a measured frequency value. 480 470 481 471 - 482 472 name: pin-parent-device ··· 576 544 - type 577 545 - phase-offset-monitor 578 546 - phase-offset-avg-factor 547 + - frequency-monitor 579 548 580 549 dump: 581 550 reply: *dev-attrs ··· 596 563 - mode 597 564 - phase-offset-monitor 598 565 - phase-offset-avg-factor 566 + - frequency-monitor 599 567 - 600 568 name: device-create-ntf 601 569 doc: Notification about device appearing ··· 677 643 - esync-frequency-supported 678 644 - esync-pulse 679 645 - reference-sync 646 + - measured-frequency 680 647 681 648 dump: 682 649 request:
+4 -1
drivers/dpll/dpll_core.c
··· 876 876 877 877 if (WARN_ON(!ops) || 878 878 WARN_ON(!ops->state_on_dpll_get) || 879 - WARN_ON(!ops->direction_get)) 879 + WARN_ON(!ops->direction_get) || 880 + WARN_ON(ops->measured_freq_get && 881 + (!dpll_device_ops(dpll)->freq_monitor_get || 882 + !dpll_device_ops(dpll)->freq_monitor_set))) 880 883 return -EINVAL; 881 884 882 885 mutex_lock(&dpll_lock);
+90
drivers/dpll/dpll_netlink.c
··· 176 176 } 177 177 178 178 static int 179 + dpll_msg_add_freq_monitor(struct sk_buff *msg, struct dpll_device *dpll, 180 + struct netlink_ext_ack *extack) 181 + { 182 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 183 + enum dpll_feature_state state; 184 + int ret; 185 + 186 + if (ops->freq_monitor_set && ops->freq_monitor_get) { 187 + ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), 188 + &state, extack); 189 + if (ret) 190 + return ret; 191 + if (nla_put_u32(msg, DPLL_A_FREQUENCY_MONITOR, state)) 192 + return -EMSGSIZE; 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + static int 179 199 dpll_msg_add_phase_offset_avg_factor(struct sk_buff *msg, 180 200 struct dpll_device *dpll, 181 201 struct netlink_ext_ack *extack) ··· 418 398 return -EMSGSIZE; 419 399 return nla_put_sint(msg, DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, 420 400 ffo); 401 + } 402 + 403 + static int dpll_msg_add_measured_freq(struct sk_buff *msg, struct dpll_pin *pin, 404 + struct dpll_pin_ref *ref, 405 + struct netlink_ext_ack *extack) 406 + { 407 + const struct dpll_device_ops *dev_ops = dpll_device_ops(ref->dpll); 408 + const struct dpll_pin_ops *ops = dpll_pin_ops(ref); 409 + struct dpll_device *dpll = ref->dpll; 410 + enum dpll_feature_state state; 411 + u64 measured_freq; 412 + int ret; 413 + 414 + if (!ops->measured_freq_get) 415 + return 0; 416 + ret = dev_ops->freq_monitor_get(dpll, dpll_priv(dpll), 417 + &state, extack); 418 + if (ret) 419 + return ret; 420 + if (state == DPLL_FEATURE_STATE_DISABLE) 421 + return 0; 422 + ret = ops->measured_freq_get(pin, dpll_pin_on_dpll_priv(dpll, pin), 423 + dpll, dpll_priv(dpll), &measured_freq, 424 + extack); 425 + if (ret) 426 + return ret; 427 + if (nla_put_64bit(msg, DPLL_A_PIN_MEASURED_FREQUENCY, 428 + sizeof(measured_freq), &measured_freq, 429 + DPLL_A_PIN_PAD)) 430 + return -EMSGSIZE; 431 + 432 + return 0; 421 433 } 422 434 423 435 static int ··· 724 672 ret = dpll_msg_add_ffo(msg, pin, ref, extack); 725 673 if (ret) 726 674 return ret; 675 + ret = dpll_msg_add_measured_freq(msg, pin, ref, extack); 676 + if (ret) 677 + return ret; 727 678 ret = dpll_msg_add_pin_esync(msg, pin, ref, extack); 728 679 if (ret) 729 680 return ret; ··· 777 722 if (ret) 778 723 return ret; 779 724 ret = dpll_msg_add_phase_offset_avg_factor(msg, dpll, extack); 725 + if (ret) 726 + return ret; 727 + ret = dpll_msg_add_freq_monitor(msg, dpll, extack); 780 728 if (ret) 781 729 return ret; 782 730 ··· 1004 946 1005 947 return ops->phase_offset_avg_factor_set(dpll, dpll_priv(dpll), factor, 1006 948 extack); 949 + } 950 + 951 + static int 952 + dpll_freq_monitor_set(struct dpll_device *dpll, struct nlattr *a, 953 + struct netlink_ext_ack *extack) 954 + { 955 + const struct dpll_device_ops *ops = dpll_device_ops(dpll); 956 + enum dpll_feature_state state = nla_get_u32(a), old_state; 957 + int ret; 958 + 959 + if (!(ops->freq_monitor_set && ops->freq_monitor_get)) { 960 + NL_SET_ERR_MSG_ATTR(extack, a, 961 + "dpll device not capable of frequency monitor"); 962 + return -EOPNOTSUPP; 963 + } 964 + ret = ops->freq_monitor_get(dpll, dpll_priv(dpll), &old_state, 965 + extack); 966 + if (ret) { 967 + NL_SET_ERR_MSG(extack, 968 + "unable to get current state of frequency monitor"); 969 + return ret; 970 + } 971 + if (state == old_state) 972 + return 0; 973 + 974 + return ops->freq_monitor_set(dpll, dpll_priv(dpll), state, extack); 1007 975 } 1008 976 1009 977 static int ··· 1959 1875 case DPLL_A_PHASE_OFFSET_AVG_FACTOR: 1960 1876 ret = dpll_phase_offset_avg_factor_set(dpll, a, 1961 1877 info->extack); 1878 + if (ret) 1879 + return ret; 1880 + break; 1881 + case DPLL_A_FREQUENCY_MONITOR: 1882 + ret = dpll_freq_monitor_set(dpll, a, 1883 + info->extack); 1962 1884 if (ret) 1963 1885 return ret; 1964 1886 break;
+3 -2
drivers/dpll/dpll_nl.c
··· 43 43 }; 44 44 45 45 /* DPLL_CMD_DEVICE_SET - do */ 46 - static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_PHASE_OFFSET_AVG_FACTOR + 1] = { 46 + static const struct nla_policy dpll_device_set_nl_policy[DPLL_A_FREQUENCY_MONITOR + 1] = { 47 47 [DPLL_A_ID] = { .type = NLA_U32, }, 48 48 [DPLL_A_MODE] = NLA_POLICY_RANGE(NLA_U32, 1, 2), 49 49 [DPLL_A_PHASE_OFFSET_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1), 50 50 [DPLL_A_PHASE_OFFSET_AVG_FACTOR] = { .type = NLA_U32, }, 51 + [DPLL_A_FREQUENCY_MONITOR] = NLA_POLICY_MAX(NLA_U32, 1), 51 52 }; 52 53 53 54 /* DPLL_CMD_PIN_ID_GET - do */ ··· 116 115 .doit = dpll_nl_device_set_doit, 117 116 .post_doit = dpll_post_doit, 118 117 .policy = dpll_device_set_nl_policy, 119 - .maxattr = DPLL_A_PHASE_OFFSET_AVG_FACTOR, 118 + .maxattr = DPLL_A_FREQUENCY_MONITOR, 120 119 .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 121 120 }, 122 121 {
+75 -13
drivers/dpll/zl3073x/core.c
··· 632 632 } 633 633 634 634 /** 635 - * zl3073x_ref_ffo_update - update reference fractional frequency offsets 635 + * zl3073x_ref_freq_meas_latch - latch reference frequency measurements 636 636 * @zldev: pointer to zl3073x_dev structure 637 + * @type: measurement type (ZL_REF_FREQ_MEAS_CTRL_*) 637 638 * 638 - * The function asks device to update fractional frequency offsets latch 639 - * registers the latest measured values, reads and stores them into 639 + * The function waits for the previous measurement to finish, selects all 640 + * references and requests a new measurement of the given type. 640 641 * 641 642 * Return: 0 on success, <0 on error 642 643 */ 643 644 static int 644 - zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) 645 + zl3073x_ref_freq_meas_latch(struct zl3073x_dev *zldev, u8 type) 645 646 { 646 - int i, rc; 647 + int rc; 647 648 648 - /* Per datasheet we have to wait for 'ref_freq_meas_ctrl' to be zero 649 - * to ensure that the measured data are coherent. 650 - */ 649 + /* Wait for previous measurement to finish */ 651 650 rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, 652 651 ZL_REF_FREQ_MEAS_CTRL); 653 652 if (rc) ··· 662 663 if (rc) 663 664 return rc; 664 665 665 - /* Request frequency offset measurement */ 666 - rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, 667 - ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); 666 + /* Request measurement */ 667 + rc = zl3073x_write_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, type); 668 668 if (rc) 669 669 return rc; 670 670 671 671 /* Wait for finish */ 672 - rc = zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, 673 - ZL_REF_FREQ_MEAS_CTRL); 672 + return zl3073x_poll_zero_u8(zldev, ZL_REG_REF_FREQ_MEAS_CTRL, 673 + ZL_REF_FREQ_MEAS_CTRL); 674 + } 675 + 676 + /** 677 + * zl3073x_ref_freq_meas_update - update measured input reference frequencies 678 + * @zldev: pointer to zl3073x_dev structure 679 + * 680 + * The function asks device to latch measured input reference frequencies 681 + * and stores the results in the ref state. 682 + * 683 + * Return: 0 on success, <0 on error 684 + */ 685 + static int 686 + zl3073x_ref_freq_meas_update(struct zl3073x_dev *zldev) 687 + { 688 + int i, rc; 689 + 690 + rc = zl3073x_ref_freq_meas_latch(zldev, ZL_REF_FREQ_MEAS_CTRL_REF_FREQ); 691 + if (rc) 692 + return rc; 693 + 694 + /* Read measured frequencies in Hz (unsigned 32-bit, LSB = 1 Hz) */ 695 + for (i = 0; i < ZL3073X_NUM_REFS; i++) { 696 + u32 value; 697 + 698 + rc = zl3073x_read_u32(zldev, ZL_REG_REF_FREQ(i), &value); 699 + if (rc) 700 + return rc; 701 + 702 + zldev->ref[i].meas_freq = value; 703 + } 704 + 705 + return 0; 706 + } 707 + 708 + /** 709 + * zl3073x_ref_ffo_update - update reference fractional frequency offsets 710 + * @zldev: pointer to zl3073x_dev structure 711 + * 712 + * The function asks device to latch the latest measured fractional 713 + * frequency offset values, reads and stores them into the ref state. 714 + * 715 + * Return: 0 on success, <0 on error 716 + */ 717 + static int 718 + zl3073x_ref_ffo_update(struct zl3073x_dev *zldev) 719 + { 720 + int i, rc; 721 + 722 + rc = zl3073x_ref_freq_meas_latch(zldev, 723 + ZL_REF_FREQ_MEAS_CTRL_REF_FREQ_OFF); 674 724 if (rc) 675 725 return rc; 676 726 ··· 761 713 if (rc) 762 714 dev_warn(zldev->dev, "Failed to update phase offsets: %pe\n", 763 715 ERR_PTR(rc)); 716 + 717 + /* Update measured input reference frequencies if any DPLL has 718 + * frequency monitoring enabled. 719 + */ 720 + list_for_each_entry(zldpll, &zldev->dplls, list) { 721 + if (zldpll->freq_monitor) { 722 + rc = zl3073x_ref_freq_meas_update(zldev); 723 + if (rc) 724 + dev_warn(zldev->dev, 725 + "Failed to update measured frequencies: %pe\n", 726 + ERR_PTR(rc)); 727 + break; 728 + } 729 + } 764 730 765 731 /* Update references' fractional frequency offsets */ 766 732 rc = zl3073x_ref_ffo_update(zldev);
+96 -4
drivers/dpll/zl3073x/dpll.c
··· 39 39 * @pin_state: last saved pin state 40 40 * @phase_offset: last saved pin phase offset 41 41 * @freq_offset: last saved fractional frequency offset 42 + * @measured_freq: last saved measured frequency 42 43 */ 43 44 struct zl3073x_dpll_pin { 44 45 struct list_head list; ··· 55 54 enum dpll_pin_state pin_state; 56 55 s64 phase_offset; 57 56 s64 freq_offset; 57 + u32 measured_freq; 58 58 }; 59 59 60 60 /* ··· 200 198 struct zl3073x_dpll_pin *pin = pin_priv; 201 199 202 200 *ffo = pin->freq_offset; 201 + 202 + return 0; 203 + } 204 + 205 + static int 206 + zl3073x_dpll_input_pin_measured_freq_get(const struct dpll_pin *dpll_pin, 207 + void *pin_priv, 208 + const struct dpll_device *dpll, 209 + void *dpll_priv, u64 *measured_freq, 210 + struct netlink_ext_ack *extack) 211 + { 212 + struct zl3073x_dpll_pin *pin = pin_priv; 213 + 214 + *measured_freq = pin->measured_freq; 215 + *measured_freq *= DPLL_PIN_MEASURED_FREQUENCY_DIVIDER; 203 216 204 217 return 0; 205 218 } ··· 1133 1116 return 0; 1134 1117 } 1135 1118 1119 + static int 1120 + zl3073x_dpll_freq_monitor_get(const struct dpll_device *dpll, 1121 + void *dpll_priv, 1122 + enum dpll_feature_state *state, 1123 + struct netlink_ext_ack *extack) 1124 + { 1125 + struct zl3073x_dpll *zldpll = dpll_priv; 1126 + 1127 + if (zldpll->freq_monitor) 1128 + *state = DPLL_FEATURE_STATE_ENABLE; 1129 + else 1130 + *state = DPLL_FEATURE_STATE_DISABLE; 1131 + 1132 + return 0; 1133 + } 1134 + 1135 + static int 1136 + zl3073x_dpll_freq_monitor_set(const struct dpll_device *dpll, 1137 + void *dpll_priv, 1138 + enum dpll_feature_state state, 1139 + struct netlink_ext_ack *extack) 1140 + { 1141 + struct zl3073x_dpll *zldpll = dpll_priv; 1142 + 1143 + zldpll->freq_monitor = (state == DPLL_FEATURE_STATE_ENABLE); 1144 + 1145 + return 0; 1146 + } 1147 + 1136 1148 static const struct dpll_pin_ops zl3073x_dpll_input_pin_ops = { 1137 1149 .direction_get = zl3073x_dpll_pin_direction_get, 1138 1150 .esync_get = zl3073x_dpll_input_pin_esync_get, ··· 1169 1123 .ffo_get = zl3073x_dpll_input_pin_ffo_get, 1170 1124 .frequency_get = zl3073x_dpll_input_pin_frequency_get, 1171 1125 .frequency_set = zl3073x_dpll_input_pin_frequency_set, 1126 + .measured_freq_get = zl3073x_dpll_input_pin_measured_freq_get, 1172 1127 .phase_offset_get = zl3073x_dpll_input_pin_phase_offset_get, 1173 1128 .phase_adjust_get = zl3073x_dpll_input_pin_phase_adjust_get, 1174 1129 .phase_adjust_set = zl3073x_dpll_input_pin_phase_adjust_set, ··· 1198 1151 .phase_offset_avg_factor_set = zl3073x_dpll_phase_offset_avg_factor_set, 1199 1152 .phase_offset_monitor_get = zl3073x_dpll_phase_offset_monitor_get, 1200 1153 .phase_offset_monitor_set = zl3073x_dpll_phase_offset_monitor_set, 1154 + .freq_monitor_get = zl3073x_dpll_freq_monitor_get, 1155 + .freq_monitor_set = zl3073x_dpll_freq_monitor_set, 1201 1156 .supported_modes_get = zl3073x_dpll_supported_modes_get, 1202 1157 }; 1203 1158 ··· 1621 1572 struct zl3073x_dev *zldev = zldpll->dev; 1622 1573 const struct zl3073x_ref *ref; 1623 1574 u8 ref_id; 1575 + s64 ffo; 1624 1576 1625 1577 /* Get reference monitor status */ 1626 1578 ref_id = zl3073x_input_pin_ref_get(pin->id); ··· 1632 1582 return false; 1633 1583 1634 1584 /* Compare with previous value */ 1635 - if (pin->freq_offset != ref->ffo) { 1585 + ffo = zl3073x_ref_ffo_get(ref); 1586 + if (pin->freq_offset != ffo) { 1636 1587 dev_dbg(zldev->dev, "%s freq offset changed: %lld -> %lld\n", 1637 - pin->label, pin->freq_offset, ref->ffo); 1638 - pin->freq_offset = ref->ffo; 1588 + pin->label, pin->freq_offset, ffo); 1589 + pin->freq_offset = ffo; 1590 + 1591 + return true; 1592 + } 1593 + 1594 + return false; 1595 + } 1596 + 1597 + /** 1598 + * zl3073x_dpll_pin_measured_freq_check - check for pin measured frequency 1599 + * change 1600 + * @pin: pin to check 1601 + * 1602 + * Check for the given pin's measured frequency change. 1603 + * 1604 + * Return: true on measured frequency change, false otherwise 1605 + */ 1606 + static bool 1607 + zl3073x_dpll_pin_measured_freq_check(struct zl3073x_dpll_pin *pin) 1608 + { 1609 + struct zl3073x_dpll *zldpll = pin->dpll; 1610 + struct zl3073x_dev *zldev = zldpll->dev; 1611 + const struct zl3073x_ref *ref; 1612 + u8 ref_id; 1613 + u32 freq; 1614 + 1615 + if (!zldpll->freq_monitor) 1616 + return false; 1617 + 1618 + ref_id = zl3073x_input_pin_ref_get(pin->id); 1619 + ref = zl3073x_ref_state_get(zldev, ref_id); 1620 + 1621 + freq = zl3073x_ref_meas_freq_get(ref); 1622 + if (pin->measured_freq != freq) { 1623 + dev_dbg(zldev->dev, "%s measured freq changed: %u -> %u\n", 1624 + pin->label, pin->measured_freq, freq); 1625 + pin->measured_freq = freq; 1639 1626 1640 1627 return true; 1641 1628 } ··· 1764 1677 pin_changed = true; 1765 1678 } 1766 1679 1767 - /* Check for phase offset and ffo change once per second */ 1680 + /* Check for phase offset, ffo, and measured freq change 1681 + * once per second. 1682 + */ 1768 1683 if (zldpll->check_count % 2 == 0) { 1769 1684 if (zl3073x_dpll_pin_phase_offset_check(pin)) 1770 1685 pin_changed = true; 1771 1686 1772 1687 if (zl3073x_dpll_pin_ffo_check(pin)) 1688 + pin_changed = true; 1689 + 1690 + if (zl3073x_dpll_pin_measured_freq_check(pin)) 1773 1691 pin_changed = true; 1774 1692 } 1775 1693
+2
drivers/dpll/zl3073x/dpll.h
··· 15 15 * @id: DPLL index 16 16 * @check_count: periodic check counter 17 17 * @phase_monitor: is phase offset monitor enabled 18 + * @freq_monitor: is frequency monitor enabled 18 19 * @ops: DPLL device operations for this instance 19 20 * @dpll_dev: pointer to registered DPLL device 20 21 * @tracker: tracking object for the acquired reference ··· 29 28 u8 id; 30 29 u8 check_count; 31 30 bool phase_monitor; 31 + bool freq_monitor; 32 32 struct dpll_device_ops ops; 33 33 struct dpll_device *dpll_dev; 34 34 dpll_tracker tracker;
+14
drivers/dpll/zl3073x/ref.h
··· 23 23 * @sync_ctrl: reference sync control 24 24 * @config: reference config 25 25 * @ffo: current fractional frequency offset 26 + * @meas_freq: measured input frequency in Hz 26 27 * @mon_status: reference monitor status 27 28 */ 28 29 struct zl3073x_ref { ··· 41 40 ); 42 41 struct_group(stat, /* Status */ 43 42 s64 ffo; 43 + u32 meas_freq; 44 44 u8 mon_status; 45 45 ); 46 46 }; ··· 68 66 zl3073x_ref_ffo_get(const struct zl3073x_ref *ref) 69 67 { 70 68 return ref->ffo; 69 + } 70 + 71 + /** 72 + * zl3073x_ref_meas_freq_get - get measured input frequency 73 + * @ref: pointer to ref state 74 + * 75 + * Return: measured input frequency in Hz 76 + */ 77 + static inline u32 78 + zl3073x_ref_meas_freq_get(const struct zl3073x_ref *ref) 79 + { 80 + return ref->meas_freq; 71 81 } 72 82 73 83 /**
+10
include/linux/dpll.h
··· 52 52 int (*phase_offset_avg_factor_get)(const struct dpll_device *dpll, 53 53 void *dpll_priv, u32 *factor, 54 54 struct netlink_ext_ack *extack); 55 + int (*freq_monitor_set)(const struct dpll_device *dpll, void *dpll_priv, 56 + enum dpll_feature_state state, 57 + struct netlink_ext_ack *extack); 58 + int (*freq_monitor_get)(const struct dpll_device *dpll, void *dpll_priv, 59 + enum dpll_feature_state *state, 60 + struct netlink_ext_ack *extack); 55 61 }; 56 62 57 63 struct dpll_pin_ops { ··· 116 110 int (*ffo_get)(const struct dpll_pin *pin, void *pin_priv, 117 111 const struct dpll_device *dpll, void *dpll_priv, 118 112 s64 *ffo, struct netlink_ext_ack *extack); 113 + int (*measured_freq_get)(const struct dpll_pin *pin, void *pin_priv, 114 + const struct dpll_device *dpll, 115 + void *dpll_priv, u64 *measured_freq, 116 + struct netlink_ext_ack *extack); 119 117 int (*esync_set)(const struct dpll_pin *pin, void *pin_priv, 120 118 const struct dpll_device *dpll, void *dpll_priv, 121 119 u64 freq, struct netlink_ext_ack *extack);
+4 -1
include/uapi/linux/dpll.h
··· 191 191 DPLL_PIN_CAPABILITIES_STATE_CAN_CHANGE = 4, 192 192 }; 193 193 194 - #define DPLL_PHASE_OFFSET_DIVIDER 1000 194 + #define DPLL_PHASE_OFFSET_DIVIDER 1000 195 + #define DPLL_PIN_MEASURED_FREQUENCY_DIVIDER 1000 195 196 196 197 /** 197 198 * enum dpll_feature_state - Allow control (enable/disable) and status checking ··· 219 218 DPLL_A_CLOCK_QUALITY_LEVEL, 220 219 DPLL_A_PHASE_OFFSET_MONITOR, 221 220 DPLL_A_PHASE_OFFSET_AVG_FACTOR, 221 + DPLL_A_FREQUENCY_MONITOR, 222 222 223 223 __DPLL_A_MAX, 224 224 DPLL_A_MAX = (__DPLL_A_MAX - 1) ··· 256 254 DPLL_A_PIN_REFERENCE_SYNC, 257 255 DPLL_A_PIN_PHASE_ADJUST_GRAN, 258 256 DPLL_A_PIN_FRACTIONAL_FREQUENCY_OFFSET_PPT, 257 + DPLL_A_PIN_MEASURED_FREQUENCY, 259 258 260 259 __DPLL_A_PIN_MAX, 261 260 DPLL_A_PIN_MAX = (__DPLL_A_PIN_MAX - 1)