From: Ali Rouhi <arouhi@sitime.com>
To: Jiri Pirko <jiri@resnulli.us>
Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Ivan Vecera <ivecera@redhat.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Carolina Jubran <cjubran@nvidia.com>,
Oleg Zadorozhnyi <Oleg.Zadorozhnyi@devoxsoftware.com>,
"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
"netdev@vger.kernel.org" <netdev@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: [PATCH net-next v12 00/12] dpll: add SiTime SiT9531x DPLL clock driver
Date: Fri, 9 Oct 2026 18:31:52 +0000 [thread overview]
Message-ID: <20261009183151.78497-1-arouhi@sitime.com> (raw)
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.
Patch 1 of v11 was applied to net-next as commit 45ad84d2800e
("dt-bindings: dpll: allow hex unit addresses on output pins"). This
series is the remaining twelve patches rebased on it, so the count
falling from thirteen to twelve is this commit. What
is left is 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/
v2: https://lore.kernel.org/netdev/20260520191943.73938-1-arouhi@sitime.com/
v3: https://lore.kernel.org/netdev/20260731180951.65725-1-arouhi@sitime.com/
v4: https://lore.kernel.org/netdev/20260806232439.27551-1-arouhi@sitime.com/
v5: https://lore.kernel.org/netdev/20260810230439.22866-1-arouhi@sitime.com/
v6: https://lore.kernel.org/netdev/20260812175337.18155-1-arouhi@sitime.com/
v7: https://lore.kernel.org/netdev/20260815221919.64226-1-arouhi@sitime.com/
v8: https://lore.kernel.org/netdev/20260902214030.20955-1-arouhi@sitime.com/
v9: https://lore.kernel.org/netdev/20260915000015.80480-1-arouhi@sitime.com/
v10: https://lore.kernel.org/netdev/20260921201108.42676-1-arouhi@sitime.com/
v11: https://lore.kernel.org/netdev/20260930233714.87679-1-arouhi@sitime.com/
The review of v11 raised fifty-five points across eleven messages.
Forty-three are fixed here, one is fixed in part, and eleven are
answered on the thread. Every fix is folded into the patch that
introduces the code rather than added as a follow-up, so each patch
still reads as the one change it describes. The replies go out with
this series.
1 bindings: vendor prefix
2 bindings: 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 and operational state on a DPLL
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 the inter-PLL sync net as a pair of pins
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 ten 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. That was re-checked for this posting 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.
Four things are worth reading before the changelog.
The first is that the reporting limitation the v11 cover letter
described is gone.
v11 said that when the device fails over on its own to another source
in its priority table, the registers the driver read did not name the
source it had moved to, so no pin was reported active. The driver now
reads the PLL's debug status bus, which names the source the input
subsystem feeds the PLL. A pin is reported active when the status bus
names it, the PLL is locked to it with its outer loop running and not
frozen, and that lane's monitor reports signal. After an autonomous
failover the pin the PLL moved to reports active and the one it left
reports no signal, so userspace gets identity and not just a change
notification. The status bus names what is fed to the PLL rather than
what the PLL has locked to, which is why the lane monitor has to agree.
It is read only for a PLL that is tracking a reference, six transfers
per such PLL per poll tick.
The second is the one High finding, which was a real bug.
sit9531x_dpll_pin_unregister() cleared a pin's core handle and then
blocked on the DPLL core lock, while the output state setter read that
handle more than a hundred milliseconds of I2C transfers after
validating it, with no NULL test in between. Dereferencing it during
teardown would have oopsed with the core lock held, which takes every
later DPLL netlink call with it. The clear and the read are now a
WRITE_ONCE/READ_ONCE pair and the setter sends no notification when the
handle is gone. The poll's own notifications need no guard: the poll is
cancelled before any pin is unregistered.
The third is an arithmetic trap on the same class of input.
A feedback divider of less than one cycle yields a derived VCO rate
small enough that the picosecond conversions in the phase code and the
TDC path overflow their 64-bit divide, which traps on x86 and returns a
nonsense quotient elsewhere. Such a rate is not a programmed VCO rate
at all, so sit9531x_get_fvco() now reports no data below the low band
and nothing downstream divides by it. Separately, a frequency set
computed against a rate outside the PLL's band is refused with -EINVAL
rather than programmed and reported as success.
The fourth is the binding, which now describes the power supplies.
With unevaluatedProperties: false the schema did not merely omit the
rails, it rejected any board that tried to describe them. The supplies
are named by their pins: vdd-supply for the PLL core rail, vddin-supply
for the input receivers and dividers, vdds-supply for the GPIO rail the
SiT95317 has, and one per output-driver pin -- vddo0 to vddo7 on the
SiT95317, and vddo0_1, vddo2 through vddo9 and vddo10_11 on the
SiT95316, where the two shared pins each power the pair of outputs they
are named after. The variant conditional refuses the names the other
part does not have. The driver does not enable them; the binding gives
a board with switchable rails a way to describe them.
Changes in v12:
- The active input pin is reported from the device's routed
reference rather than from the selection the driver last wrote,
as described above.
- The priority table commit's error paths. A failed write on a PLL
whose table was empty keeps the forced holdover rather than
releasing it and leaving the PLL following a source every pin
reports disconnected. A forced-holdover write that fails goes to
the release path instead of returning, because the write may have
landed. A release that fails after the write and the latch is owed
and retried from the poll until it lands. A monitor read that
fails rolls the commit back rather than letting the selection be
picked from loss-of-signal state that may be a poll period old.
The rollback restores the register whose write failed as well as
the ones before it. The configured priority and its known flag are
saved before the apply and put back when it fails, so nothing
reports a priority the device never took.
- A forced holdover the driver did not set -- one found set with a
non-empty table, so placed by the loaded configuration or by a
tool -- is left alone by a table write. Only the hold the driver
itself set for an empty table is released.
- When the driver forced holdover for an empty table and the device
has not marked its holdover estimate valid, the lock status is
UNLOCKED rather than HOLDOVER, which is what the uAPI text asks
for. Holdover freeze is now tested before the lock bit, matching
the order the pin-state contract uses.
- Baselines are taken at registration. The device's lock status and
each pin's state, operational state and priority are seeded under
the device lock when the object is registered, rather than by the
first poll tick, so a change between the probe-time fetch and that
tick is reported instead of absorbed. The per-pin "seen" flag is
gone with it.
- An input the firmware gives no rate for has no frequency attribute
rather than reporting 0 Hz, through an ops table without the
getter. The core abandons a whole pin dump on an error from one
pin, which is why the attribute is left out rather than failed.
- Output state. A request for the state an output already has reads
the Hi-Z pair first and returns without entering the programming
state. A change whose read-back failed is announced as well as one
whose cached state moved, so a subscriber is not left holding the
old value.
- Phase. The fold of a requested delay into one output period is
counted in VCO cycles modulo the output divider, which is exactly
the period, instead of modulo a period truncated to whole
picoseconds; 100 us on a 128 MHz output of a 5.12 GHz VCO now
folds to zero. The quantizer evaluates one cycle fewer, the floor
and one cycle more, each with the fine steps capped, so 210 ps at
5 GHz encodes exactly. A bus error from the divider read fails the
read-back instead of being treated as "no divider programmed". A
flush that failed after the delay was committed is remembered in
its own flag that the setter honors, since the core drops a repeat
request whose bytes match the cache. A delay the loaded
configuration left beyond the advertised window is reported
clamped and not armed, so a later rate change cannot write the
clamp into the device. A rate change on an output with a
programmed delay re-times the delay inside the rate change's own
programming window, one sequence and one flush instead of two of
each, and when the commit fails after the divider was written an
armed delay is marked stale.
- The phase-flush error paths: a failed source select restores the
original source, a sibling is marked parked before it is cleared,
and a failed arm disarms rather than unparks. A failed entry into
the programming state now leaves the device the way a commit
leaves it rather than issuing a bare loop lock.
- Phase offset. An output whose cached state is marked stale is read
back from the device before it counts as driving. The lane
monitors are read live before the pin is judged active, so a lane
that lost its clock after the last poll cannot have a sample
credited to it. The conversion keeps the fraction of a picosecond
the converter resolves.
- The inter-PLL sync net. A destination pin whose net no PLL drives
reports no signal rather than standby, as an external input that
lost its clock does. A failure of the final per-PLL latch no
longer restores the global enable, and the rollback of a failed
enable uses a variant that does not restore it either, so a failed
enable cannot leave a global bit no PLL owns. A source whose
enable, rollback and rescan all failed is recorded as a partial
owner, so a retry re-runs the enable instead of being refused as
busy. The restore write is followed by the page-0 small update and
its settle, as every other write to that register is. A failed
request that moved the owner is announced. Resume re-detects the
net's owner and reads every output's mute back from the device.
- Binding. The power supplies, described above. The input pins'
supported-frequencies-hz now carries a description stating that
the property names the rate wired to the input, as a single entry;
maxItems: 1 would have been the stronger form, but dtschema types
every -hz property as a uint32 matrix, so the example's single
/bits/ 64 value reads as two cells to the tooling and the
constraint fails dt_binding_check.
- Comment and commit-message corrections where the text did not
describe the code: "qualified" where the predicate means "has
signal", "only the named pin changes" where the claim is about
priorities, a retry that named the wrong latch, a kernel-doc that
promised the advance form of a phase read-back unconditionally,
and a comment asserting the fine field tops out below one VCO
period when it does not.
- Tags. Patch 1 keeps Conor's Acked-by. Rob Herring reviewed the
device schema as it stood in v11; that patch is 2 here and it has
changed since, by thirty-eight lines of schema and a commit-message
paragraph, all of it the power supplies. He has not seen that
construction, so the tag is not carried and another look would be
welcome.
Two rounds of changes in this series answer reports from Carolina
Jubran. The probe path that accepts a clock-frequency property when
firmware exposes no oscillator through the clock framework, now patch
3, came from her report against v8; the input-handling work that went
into v10
-- emptying the priority table when the last reference is disconnected,
giving a meaning to every slot code including the input pair this part
does not have, and reporting connected as selected rather than locked
-- came from her report against v9. Both came by private mail. The v10
and v11 cover letters carried this credit, and neither series was taken
into the tree, so it is restated here.
Four items from earlier rounds are unchanged and are repeated so they
are not re-raised.
The selection moves only when the priority table is written. The device
re-runs its own selection when the source it follows loses signal; it
does not notice a table rewrite. Each move the driver makes is a
re-selection, which takes the PLL through holdover and unlocks it for
about ten seconds, so a priority change further down the table, or the
removal of a source the PLL is not on, must not move it. The rule is
therefore to move only when the highest-priority live source is a
different one than before. What that leaves open is the case where the
preferred source recovers, or a newly enabled receiver qualifies after
the pick ran, and nothing re-selects: the device's own revertive
switching returns only to the source the selection register names, so
the driver would have to re-pick from the poll, paying the unlock on a
timer rather than on a request. Whether to take that under AUTOMATIC or
to document the behavior as non-revertive is still open. The commit
message states the rule as implemented and the open point; the
mechanism follows in a later revision.
The phase-adjust granularity stays at 1 ps rather than the 30 ps fine
step. The delays this device can reach are not multiples 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 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 (10):
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: model the inter-PLL sync net as a pair of pins
.../bindings/dpll/sitime,sit95316.yaml | 213 +
.../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 | 5298 +++++++++++++++++
drivers/dpll/sit9531x/core.h | 453 ++
drivers/dpll/sit9531x/dpll.c | 1731 ++++++
drivers/dpll/sit9531x/dpll.h | 70 +
drivers/dpll/sit9531x/prop.c | 472 ++
drivers/dpll/sit9531x/prop.h | 37 +
drivers/dpll/sit9531x/regs.h | 425 ++
14 files changed, 8732 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: 45ad84d2800e4a092fb8d96006a533b2d0ab13f6
--
2.39.2 (Apple Git-143)
next reply other threads:[~2026-10-09 18:31 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-09 18:31 Ali Rouhi [this message]
2026-10-09 18:31 ` [PATCH net-next v12 02/12] dt-bindings: dpll: add SiTime SiT95316 clock generator Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 01/12] dt-bindings: vendor-prefixes: add SiTime Corporation Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 03/12] dpll: add basic SiTime SiT9531x support Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 04/12] dpll: sit9531x: read DPLL types and pin properties from system firmware Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 05/12] dpll: sit9531x: register DPLL devices and pins Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 06/12] dpll: sit9531x: implement input pin state on a DPLL Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 08/12] dpll: sit9531x: add support to get and set frequency on pins Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 07/12] dpll: sit9531x: add support to get and set priority on input pins Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 09/12] dpll: sit9531x: implement output pin state on a DPLL Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 10/12] dpll: sit9531x: add support to adjust output phase Ali Rouhi
2026-10-09 18:31 ` [PATCH net-next v12 11/12] dpll: sit9531x: add support to get phase offset on the connected input pin Ali Rouhi
2026-10-09 18:32 ` [PATCH net-next v12 12/12] dpll: sit9531x: model the inter-PLL sync net as a pair of pins Ali Rouhi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261009183151.78497-1-arouhi@sitime.com \
--to=arouhi@sitime.com \
--cc=Oleg.Zadorozhnyi@devoxsoftware.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=cjubran@nvidia.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=ivecera@redhat.com \
--cc=jiri@resnulli.us \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=robh@kernel.org \
--cc=vadim.fedorenko@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®