[PATCH v10 00/14] dpll: add SiTime SiT9531x DPLL clock driver
From: Ali Rouhi <hidden>
Date: 2026-09-21 20:11:26
Also in:
lkml, netdev
This series adds a DPLL subsystem driver for the SiTime SiT95316 and SiT95317 I2C clock generators. Each device integrates four PLLs with automatic reference selection and on-chip TDC phase-offset measurement, and is used for synchronization in telecom, networking, and data-center timing. The series contains the device-tree binding, the driver under drivers/dpll/sit9531x/, and the MAINTAINERS entry. v1: https://lore.kernel.org/netdev/20260511211143.19792-1-arouhi@sitime.com/ (local) v2: https://lore.kernel.org/netdev/20260520191943.73938-1-arouhi@sitime.com/ (local) v3: https://lore.kernel.org/netdev/20260731180951.65725-1-arouhi@sitime.com/ (local) v4: https://lore.kernel.org/netdev/20260806232439.27551-1-arouhi@sitime.com/ (local) v5: https://lore.kernel.org/netdev/20260810230439.22866-1-arouhi@sitime.com/ (local) v6: https://lore.kernel.org/netdev/20260812175337.18155-1-arouhi@sitime.com/ (local) v7: https://lore.kernel.org/netdev/20260815221919.64226-1-arouhi@sitime.com/ (local) v8: https://lore.kernel.org/netdev/20260902214030.20955-1-arouhi@sitime.com/ (local) v9: https://lore.kernel.org/netdev/20260915000015.80480-1-arouhi@sitime.com/ (local) v10 follows v9 by less than a week because three things did not want to wait for a longer cycle. Carolina Jubran ran v9 on a board and found two defects in input handling. A divide-error in the frequency path turned out to be reachable from an ordinary pin get. And the embedded-sync patch is withdrawn, which takes the series from fifteen patches to fourteen. 1-2 bindings: vendor prefix, then the device schema 3 basic support: paged regmap, variant detection, probe 4 DPLL types and pin properties from system firmware 5 register the DPLL devices and pins, and keep their state 6 input pin state on a DPLL, with the pin-state contract 7 input pin priority 8 pin frequency, both directions 9 output pin state (mute) 10 output phase adjust 11 phase offset through the TDC 12 fractional frequency offset of the selected reference 13 the inter-PLL sync net as a pair of pins 14 optional device-tree overrides for two board facts The two bindings patches come first, so the driver never matches on a compatible string before the schema that describes it is in the tree. Each of the twelve driver patches builds and links on its own: no patch calls something a later patch introduces, so a bisect cannot land on a tree that fails to compile. For this posting that was re-checked patch by patch with W=1 and with sparse. checkpatch --strict is clean except for the "does MAINTAINERS need updating?" hint on patches 4 and 5, which add files under drivers/dpll/sit9531x/ -- patch 3 already covers that directory with an F: entry. Three things are worth reading before the changelog. The first is a divide-error, found by inspection rather than on a board. The feedback divider is a fraction, and the frequency path divided by its denominator without first establishing that the numerator was below it. The device can hold that combination from a profile the driver did not program, and the quotient then leaves what the division helper can return, which on x86 faults rather than yielding a value the caller could reject. An ordinary pin get reaches that path, so we did not want to leave it standing for a cycle. There is no trace to show; the argument is the one in the comment on sit9531x_divn_static(). The fraction is now refused instead of divided. The second is a change in behaviour that userspace can see. An output rate the divider cannot produce exactly is now refused with -EINVAL. Until v9 the driver programmed the nearest rate it could reach and reported success, so a request for a frequency this device cannot make came back as though it had been honoured. Refusing it is the smaller surprise: a caller that asked for a rate and got zero errors has no other way to learn that it is not running at that rate. The third is the withdrawal of embedded sync. Patch 11 of v9, embedded sync on pins, is dropped and not replaced. This device does not implement embedded sync. What it has in that area is SYSREF-triggered output gating with a per-output burst count, which is a different function: the byte patch 11 programmed sets how many pulses an output emits per trigger, so the 50 it wrote was a pulse count and not the 50 percent duty the getter reported. The patch had been written to the shape of the ABI rather than derived from the register, and the two quantities happen to share a literal, which is what let it look right. The automated review of v8 asked whether that write could take effect at all, given that the path never selects the SYSREF or SYNCB mode the byte belongs to. This was the right question, and the answer we gave then, and gave again for v9, was wrong. The patch is withdrawn rather than fixed, and we are not planning to resubmit it. Nothing else in the series depended on it. Changes in v10: - Arithmetic. Besides the feedback-divider fraction above, the runtime tap of that divider is now guarded the same way as the configured one, and the denominator's high bit has its own name instead of borrowing the integer field's. The device-tree override arrays are checked against the part: the VCO override needs an entry per PLL, and an output map shorter than the variant's output count is ignored rather than read as a run of unmapped outputs. - Input selection and state, from Carolina's bench report. Disconnecting the last reference now empties the priority table instead of being refused, so a DPLL can be left with no source at all. The slot encoding has codes for an input pair this part does not have, which read back as no valid reference, and every slot is given one rather than being left to read as input zero. Connected now means the device has selected the pin, not that the loop has locked to it -- those are different questions and only the first one is what the pin state answers. - Answer from the device rather than from a cache. An output's current rate comes from its divider instead of the first entry in the list of rates the board supports. The programmed phase delay is decoded from the device at probe, so a delay a profile carries can be cleared through the ABI, and it is re-read when a request could not be confirmed. The reference a phase measurement is taken against is read at the point of measurement rather than from a poll that may be a period old. The input receiver refcounts are re-derived from the priority tables the poll reads, so a request that failed part way cannot leave a receiver gated off while another PLL is still using it. - Leave the device in a state the caller can describe. A priority table that was written only in part is put back rather than latched, and the mask that is reported describes what reached the device rather than what was asked for. The forced Hi-Z pair value is written before the override, so the pad is never briefly pinned driven between the two, and the half that reached the device is released when the other did not. Ownership of the inter-PLL sync net is recorded before the read-back that can fail, and a disable that fails part way leaves the state describable so the request can be repeated. Entering the programming state closes the loops and the debug key when it fails. - Interrupt and notification. The driver gives up the interrupt line after repeated failures to clear the notification latch, rather than re-entering the handler behind a still-asserted INTRB. A change in the lock-status error is treated like a change in the status itself. Priority changes notify the sibling pins through the helper meant for a caller that already holds the device lock, leave the pin the request named to the core, and skip a pin that is being unregistered. - Output pin identity. Output pins are named and matched by the chip pin they drive rather than by the driver's index for them. The two differ on the variant whose outputs are bonded out from a subset of the slots, which is where the wrong pin would otherwise be programmed. - Binding. dpll-types is bounded to the four PLLs the part has. The example is made self-consistent with the driver: the Fvco override is on a PLL whose band the value belongs to, and is a rate the example's own output pin divides down from exactly. Patch 1 is unchanged since v8 and keeps Conor's Acked-by. Patch 2 has changed again, so Krzysztof's Reviewed-by is still not carried across it. - Housekeeping. The page selector is cached; it is the only register in the map that is not volatile, which removes a selector write per register access on a paged device. The sign handling in the output phase encoder is folded into one abs() and a remainder, and a zero offset skips the coarse and fine encoding entirely. Both of those came from Ivan Vecera. Two per-input status flags and the register read that filled them are dropped, along with a cached per-pin phase offset that was written on every path of the getter and read on none. Text that described registering DPLL devices moved to the patch that registers them. kernel-doc that had stopped listing members the structs still have is corrected. Four items from earlier rounds are unchanged and are repeated here so they are not re-raised. The phase-adjust granularity stays at 1 ps rather than the 30 ps fine step. The delays this device can reach are not a lattice of 30 ps: a request is split between a coarse delay counted in VCO cycles and a three-bit fine field of 30 ps steps, and the two are added, so the spacing depends on the VCO period in force. Advertising 30 would name a step the device does not have. A request is accepted at 1 ps and rounded to the nearest delay the registers can hold, and the getter reports what they hold rather than what was asked for, so a caller that needs the exact figure reads it back. A frequency request of 0 Hz is still refused with -EINVAL rather than treated as a request to stop the output. Nothing in the ABI says zero means off, and this device already has a mute control that says so explicitly. The use-after-free report on the pin properties remains a false positive: dpll_pin_alloc() calls dpll_pin_prop_dup(), which copies freq_supported with kmemdup() and the labels with kstrdup(), so the core owns its copies and the driver has to free its own. The u64 truncation in dpll_pin_freq_set() is still there and is still not ours to fix in this series: the requested frequency is read as a u64 and validated through a helper that takes a u32, so a rate of U32_MAX + 1 + N is accepted as N against ranges that are themselves u64. That affects every driver behind the interface. It will be posted as its own patch against the core rather than buried here; this driver range-checks its own input in the meantime. Ali Rouhi (2): dt-bindings: vendor-prefixes: add SiTime Corporation dt-bindings: dpll: add SiTime SiT95316 clock generator Oleg Zadorozhnyi (12): dpll: add basic SiTime SiT9531x support dpll: sit9531x: read DPLL types and pin properties from system firmware dpll: sit9531x: register DPLL devices and pins dpll: sit9531x: implement input pin state on a DPLL dpll: sit9531x: add support to get and set priority on input pins dpll: sit9531x: add support to get and set frequency on pins dpll: sit9531x: implement output pin state on a DPLL dpll: sit9531x: add support to adjust output phase dpll: sit9531x: add support to get phase offset on the connected input pin dpll: sit9531x: add support to get fractional frequency offset dpll: sit9531x: model the inter-PLL sync net as a pair of pins dpll: sit9531x: allow the device tree to override two board facts .../bindings/dpll/sitime,sit95316.yaml | 183 + .../devicetree/bindings/vendor-prefixes.yaml | 2 + MAINTAINERS | 7 + drivers/dpll/Kconfig | 2 + drivers/dpll/Makefile | 1 + drivers/dpll/sit9531x/Kconfig | 17 + drivers/dpll/sit9531x/Makefile | 4 + drivers/dpll/sit9531x/core.c | 4553 +++++++++++++++++ drivers/dpll/sit9531x/core.h | 429 ++ drivers/dpll/sit9531x/dpll.c | 1445 ++++++ drivers/dpll/sit9531x/dpll.h | 66 + drivers/dpll/sit9531x/prop.c | 469 ++ drivers/dpll/sit9531x/prop.h | 37 + drivers/dpll/sit9531x/regs.h | 364 ++ 14 files changed, 7579 insertions(+) create mode 100644 Documentation/devicetree/bindings/dpll/sitime,sit95316.yaml create mode 100644 drivers/dpll/sit9531x/Kconfig create mode 100644 drivers/dpll/sit9531x/Makefile create mode 100644 drivers/dpll/sit9531x/core.c create mode 100644 drivers/dpll/sit9531x/core.h create mode 100644 drivers/dpll/sit9531x/dpll.c create mode 100644 drivers/dpll/sit9531x/dpll.h create mode 100644 drivers/dpll/sit9531x/prop.c create mode 100644 drivers/dpll/sit9531x/prop.h create mode 100644 drivers/dpll/sit9531x/regs.h base-commit: 4bb9710c6a68d35207f123aef55dcd50e7195ec5 -- 2.43.0