drivers/ptp/ptp_dfl_tod.c
Source file repositories/reference/linux-study-clean/drivers/ptp/ptp_dfl_tod.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/ptp/ptp_dfl_tod.c- Extension
.c- Size
- 9704 bytes
- Lines
- 333
- Domain
- Driver Families
- Bucket
- drivers/ptp
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/bitfield.hlinux/delay.hlinux/dfl.hlinux/gcd.hlinux/iopoll.hlinux/module.hlinux/ptp_clock_kernel.hlinux/spinlock.hlinux/units.h
Detected Declarations
struct dfl_todfunction fine_adjust_tod_clockfunction coarse_adjust_tod_clockfunction dfl_tod_adjust_finefunction dfl_tod_adjust_timefunction dfl_tod_get_timexfunction dfl_tod_set_timefunction dfl_tod_probefunction dfl_tod_remove
Annotated Snippet
struct dfl_tod {
struct ptp_clock_info ptp_clock_ops;
struct device *dev;
struct ptp_clock *ptp_clock;
/* ToD Clock address space */
void __iomem *tod_ctrl;
/* ToD clock registers protection */
spinlock_t tod_lock;
};
/*
* A fine ToD HW clock offset adjustment. To perform the fine offset adjustment, the
* adjust_period and adjust_count argument are used to update the TOD_ADJUST_PERIOD
* and TOD_ADJUST_COUNT register for in hardware. The dt->tod_lock spinlock must be
* held when calling this function.
*/
static int fine_adjust_tod_clock(struct dfl_tod *dt, u32 adjust_period,
u32 adjust_count)
{
void __iomem *base = dt->tod_ctrl;
u32 val;
writel(adjust_period, base + TOD_ADJUST_PERIOD);
writel(adjust_count, base + TOD_ADJUST_COUNT);
/* Wait for present offset adjustment update to complete */
return readl_poll_timeout_atomic(base + TOD_ADJUST_COUNT, val, !val, TOD_ADJUST_INTERVAL_US,
TOD_ADJUST_MAX_US);
}
/*
* A coarse ToD HW clock offset adjustment. The coarse time adjustment performs by
* adding or subtracting the delta value from the current ToD HW clock time.
*/
static int coarse_adjust_tod_clock(struct dfl_tod *dt, s64 delta)
{
u32 seconds_msb, seconds_lsb, nanosec;
void __iomem *base = dt->tod_ctrl;
u64 seconds, now;
if (delta == 0)
return 0;
nanosec = readl(base + TOD_NANOSEC);
seconds_lsb = readl(base + TOD_SECONDSL);
seconds_msb = readl(base + TOD_SECONDSH);
/* Calculate new time */
seconds = CAL_SECONDS(seconds_msb, seconds_lsb);
now = seconds * NSEC_PER_SEC + nanosec + delta;
seconds = div_u64_rem(now, NSEC_PER_SEC, &nanosec);
seconds_msb = FIELD_GET(SECONDS_MSB, seconds);
seconds_lsb = FIELD_GET(SECONDS_LSB, seconds);
writel(seconds_msb, base + TOD_SECONDSH);
writel(seconds_lsb, base + TOD_SECONDSL);
writel(nanosec, base + TOD_NANOSEC);
return 0;
}
static int dfl_tod_adjust_fine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct dfl_tod *dt = container_of(ptp, struct dfl_tod, ptp_clock_ops);
u32 tod_period, tod_rem, tod_drift_adjust_fns, tod_drift_adjust_rate;
void __iomem *base = dt->tod_ctrl;
unsigned long flags, rate;
u64 ppb;
/* Get the clock rate from clock frequency register offset */
rate = readl(base + TOD_CLK_FREQ);
/* add GIGA as nominal ppb */
ppb = scaled_ppm_to_ppb(scaled_ppm) + GIGA;
tod_period = div_u64_rem(ppb << PERIOD_FRAC_OFFSET, rate, &tod_rem);
if (tod_period > TOD_PERIOD_MAX)
return -ERANGE;
/*
* The drift of ToD adjusted periodically by adding a drift_adjust_fns
* correction value every drift_adjust_rate count of clock cycles.
*/
tod_drift_adjust_fns = tod_rem / gcd(tod_rem, rate);
tod_drift_adjust_rate = rate / gcd(tod_rem, rate);
while ((tod_drift_adjust_fns > TOD_DRIFT_ADJUST_FNS_MAX) ||
Annotation
- Immediate include surface: `linux/bitfield.h`, `linux/delay.h`, `linux/dfl.h`, `linux/gcd.h`, `linux/iopoll.h`, `linux/module.h`, `linux/ptp_clock_kernel.h`, `linux/spinlock.h`.
- Detected declarations: `struct dfl_tod`, `function fine_adjust_tod_clock`, `function coarse_adjust_tod_clock`, `function dfl_tod_adjust_fine`, `function dfl_tod_adjust_time`, `function dfl_tod_get_timex`, `function dfl_tod_set_time`, `function dfl_tod_probe`, `function dfl_tod_remove`.
- Atlas domain: Driver Families / drivers/ptp.
- Implementation status: source implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.