drivers/ptp/ptp_dte.c

Source file repositories/reference/linux-study-clean/drivers/ptp/ptp_dte.c

File Facts

System
Linux kernel
Corpus path
drivers/ptp/ptp_dte.c
Extension
.c
Size
7918 bytes
Lines
337
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct ptp_dte {
	void __iomem *regs;
	struct ptp_clock *ptp_clk;
	struct ptp_clock_info caps;
	struct device *dev;
	u32 ts_ovf_last;
	u32 ts_wrap_cnt;
	spinlock_t lock;
	u32 reg_val[DTE_NUM_REGS_TO_RESTORE];
};

static void dte_write_nco(void __iomem *regs, s64 ns)
{
	u32 sum2, sum3;

	sum2 = (u32)((ns >> DTE_NCO_SUM2_SHIFT) & DTE_NCO_SUM2_MASK);
	/* compensate for ignoring sum1 */
	if (sum2 != DTE_NCO_SUM2_MASK)
		sum2++;

	/* to write sum3, bits [15:8] needs to be written */
	sum3 = (u32)(((ns >> DTE_NCO_SUM3_SHIFT) & DTE_NCO_SUM3_MASK) <<
		     DTE_NCO_SUM3_WR_SHIFT);

	writel(0, (regs + DTE_NCO_LOW_TIME_REG));
	writel(sum2, (regs + DTE_NCO_TIME_REG));
	writel(sum3, (regs + DTE_NCO_OVERFLOW_REG));
}

static s64 dte_read_nco(void __iomem *regs)
{
	u32 sum2, sum3;
	s64 ns;

	/*
	 * ignoring sum1 (4 bits) gives a 16ns resolution, which
	 * works due to the async register read.
	 */
	sum3 = readl(regs + DTE_NCO_OVERFLOW_REG) & DTE_NCO_SUM3_MASK;
	sum2 = readl(regs + DTE_NCO_TIME_REG);
	ns = ((s64)sum3 << DTE_NCO_SUM3_SHIFT) |
		 ((s64)sum2 << DTE_NCO_SUM2_SHIFT);

	return ns;
}

static void dte_write_nco_delta(struct ptp_dte *ptp_dte, s64 delta)
{
	s64 ns;

	ns = dte_read_nco(ptp_dte->regs);

	/* handle wraparound conditions */
	if ((delta < 0) && (abs(delta) > ns)) {
		if (ptp_dte->ts_wrap_cnt) {
			ns += DTE_NCO_MAX_NS + delta;
			ptp_dte->ts_wrap_cnt--;
		} else {
			ns = 0;
		}
	} else {
		ns += delta;
		if (ns > DTE_NCO_MAX_NS) {
			ptp_dte->ts_wrap_cnt++;
			ns -= DTE_NCO_MAX_NS;
		}
	}

	dte_write_nco(ptp_dte->regs, ns);

	ptp_dte->ts_ovf_last = (ns >> DTE_NCO_TS_WRAP_LSHIFT) &
			DTE_NCO_TS_WRAP_MASK;
}

static s64 dte_read_nco_with_ovf(struct ptp_dte *ptp_dte)
{
	u32 ts_ovf;
	s64 ns = 0;

	ns = dte_read_nco(ptp_dte->regs);

	/*Timestamp overflow: 8 LSB bits of sum3, 4 MSB bits of sum2 */
	ts_ovf = (ns >> DTE_NCO_TS_WRAP_LSHIFT) & DTE_NCO_TS_WRAP_MASK;

	/* Check for wrap around */
	if (ts_ovf < ptp_dte->ts_ovf_last)
		ptp_dte->ts_wrap_cnt++;

	ptp_dte->ts_ovf_last = ts_ovf;

Annotation

Implementation Notes