[PATCH v10 00/14] dpll: add SiTime SiT9531x DPLL clock driver
From: Ali Rouhi
Date: Mon Sep 21 2026 - 16:35:52 EST
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@xxxxxxxxxx/
v2: https://lore.kernel.org/netdev/20260520191943.73938-1-arouhi@xxxxxxxxxx/
v3: https://lore.kernel.org/netdev/20260731180951.65725-1-arouhi@xxxxxxxxxx/
v4: https://lore.kernel.org/netdev/20260806232439.27551-1-arouhi@xxxxxxxxxx/
v5: https://lore.kernel.org/netdev/20260810230439.22866-1-arouhi@xxxxxxxxxx/
v6: https://lore.kernel.org/netdev/20260812175337.18155-1-arouhi@xxxxxxxxxx/
v7: https://lore.kernel.org/netdev/20260815221919.64226-1-arouhi@xxxxxxxxxx/
v8: https://lore.kernel.org/netdev/20260902214030.20955-1-arouhi@xxxxxxxxxx/
v9: https://lore.kernel.org/netdev/20260915000015.80480-1-arouhi@xxxxxxxxxx/
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