[PATCH net-next v9 00/15] dpll: add SiTime SiT9531x DPLL clock driver
From: Ali Rouhi <hidden>
Date: 2026-09-15 00:00:29
Also in:
linux-devicetree, lkml
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) The driver was a single 5.6k-line patch through v7. Vadim and Ivan asked for it to be split into logical parts, with the first zl3073x series as the model, so v8 introduced it feature by feature and v9 keeps that shape: 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 esync on outputs 12 phase offset through the TDC 13 fractional frequency offset of the selected reference 14 the inter-PLL sync net as a pair of pins 15 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 thirteen 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. On process, and on Paolo's note against v8: the v8 AI review raised 86 comments across the series, and each one now has an individual reply in its own sub-thread -- fixed, or answered with the reason it is not a bug. The second half of that guidance is the more useful half, and we had not been following it. We now run the same review locally before posting rather than after; v9 has been through it twice over the whole series, and what it found is folded into the patches below instead of being left for the bots to raise again. We intend to keep doing this for any further revision. Changes in v9: - Put the cost and the constraints in the commit messages, next to the code they apply to, rather than only in replies on the list. A priority-table rewrite forces holdover and takes ten to twenty milliseconds, because the device cannot change one slot in isolation. Programming an output divider costs about a hundred milliseconds under the DPLL core's global lock, most of it the settling time the part requires after the loop-lock command. The phase flush that follows a divider write realigns every output on that PLL, not only the one that changed. The clock_id carries the I2C adapter number in eight bits, so the collision it admits is stated rather than designed around. The debug window returns the previous latch, which is why every read of it triggers three times. The running feedback divider is two taps sampled separately and can tear; on a locked loop it moves below what the measurement resolves, and the part offers no way to latch both at once. - Never leave the device armed when a sequence fails partway. The programming state, the debug window, the on-demand phase flush and forced holdover are each entered by one write and left by another, and every fallible step in between now exits through the common path that issues the second write. The first error is the one returned, so a transient I2C failure can no longer leave the chip with its loops open, its debug block unlocked, its flush armed or a PLL parked in holdover. - Answer from the device rather than from a cache where the cache can be wrong. Whether an output is muted now reads both the force bit and the state bit, and picks the register bank from the pad's own CMOS enables, so a single-ended pad is no longer interrogated through the differential bank or the reverse. State that a write may have invalidated is marked stale and re-read on the next get instead of being reported from the last poll. Priority-table membership is asked of the table. - Make .mode_set() idempotent. It reads the outer-loop disable bit before writing it and does nothing when the PLL is already in automatic mode. Without that, setting the only mode the driver advertises a second time, followed by one failed latch, would restore a disable the PLL never had and drop a running loop into free-run. - Park the poll worker and the INTRB interrupt across system suspend and take a fresh sample on resume. The tick talks to the device over I2C, and one landing mid-suspend could tear a paged sequence between the page-selector write and the register access. - Check a PLL's VCO frequency against the device's two bands before using it, so a value that fell in the gap between them cannot reach the divider arithmetic. - Binding: accept clock-frequency as an alternative to the clocks phandle, for platforms whose firmware does not expose the crystal through the clock framework; exactly one of the two is now required. The sitime,pll-fvco description was also rewritten to say why the property carries no unit suffix: the values exceed 32 bits and so need an explicit uint64-array type, and the dtschema meta-schema does not permit a type $ref on a "-hz" property. That was a review suggestion we tried and dt_binding_check rejected, so the reason is recorded in the binding itself. The schema changed, so Krzysztof's Reviewed-by is not carried across it. Patch 1 is unchanged since v8 and keeps Conor's Acked-by. One finding from the v8 review is declined rather than fixed, and the reply on patch 8 gives the argument: a frequency request of 0 Hz is refused with -EINVAL instead of being 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 review also turned up one bug that is not ours: dpll_pin_freq_set() reads the requested frequency as a u64 and validates it through a helper that takes a u32, so a rate of U32_MAX + 1 + N is accepted as N against the supported ranges, which are themselves u64. That affects every driver behind the interface, not just this one. It is a separate patch against the core and will be posted on its own rather than buried in a driver series; 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 (13): 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 and set esync on pins 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 | 181 + .../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 | 4130 +++++++++++++++++ drivers/dpll/sit9531x/core.h | 407 ++ drivers/dpll/sit9531x/dpll.c | 1486 ++++++ drivers/dpll/sit9531x/dpll.h | 70 + drivers/dpll/sit9531x/prop.c | 437 ++ drivers/dpll/sit9531x/prop.h | 39 + drivers/dpll/sit9531x/regs.h | 394 ++ 14 files changed, 7177 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: d0ec95a8a4e79f2fd6063fc8932415db8c227689 -- 2.39.2 (Apple Git-143)