drivers/net/ethernet/wangxun/libwx/wx_ptp.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/wangxun/libwx/wx_ptp.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/wangxun/libwx/wx_ptp.c
Extension
.c
Size
25336 bytes
Lines
906
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

if (wx->pps_enabled) {
			wx->pps_enabled = false;
			wx_set_pps(wx, false, 0, 0);
		}
		return 0;
	}

	wx->pps_enabled = true;
	nsec = wx_ptp_trigger_calc(wx);
	wx_set_pps(wx, wx->pps_enabled, nsec, wx->pps_edge_start);

	tsauxc = WX_TSC_1588_AUX_CTL_PLSG | WX_TSC_1588_AUX_CTL_EN_TT0 |
		WX_TSC_1588_AUX_CTL_EN_TT1 | WX_TSC_1588_AUX_CTL_EN_TS0;
	wr32ptp(wx, WX_TSC_1588_TRGT_L(0), (u32)wx->pps_edge_start);
	wr32ptp(wx, WX_TSC_1588_TRGT_H(0), (u32)(wx->pps_edge_start >> 32));
	wr32ptp(wx, WX_TSC_1588_TRGT_L(1), (u32)wx->pps_edge_end);
	wr32ptp(wx, WX_TSC_1588_TRGT_H(1), (u32)(wx->pps_edge_end >> 32));
	wr32ptp(wx, WX_TSC_1588_SDP(0),
		WX_TSC_1588_SDP_FUN_SEL_TT0 | WX_TSC_1588_SDP_OUT_LEVEL_H);
	wr32ptp(wx, WX_TSC_1588_SDP(1), WX_TSC_1588_SDP_FUN_SEL_TS0);
	wr32ptp(wx, WX_TSC_1588_AUX_CTL, tsauxc);
	wr32ptp(wx, WX_TSC_1588_INT_EN, WX_TSC_1588_INT_EN_TT1);
	WX_WRITE_FLUSH(wx);

	/* Adjust the clock edge to align with the next full second. */
	wx->sec_to_cc = div_u64(((u64)WX_NS_PER_SEC << cc->shift), cc->mult);

	return 0;
}

static int wx_ptp_feature_enable(struct ptp_clock_info *ptp,
				 struct ptp_clock_request *rq, int on)
{
	struct wx *wx = container_of(ptp, struct wx, ptp_caps);

	/**
	 * When PPS is enabled, unmask the interrupt for the ClockOut
	 * feature, so that the interrupt handler can send the PPS
	 * event when the clock SDP triggers. Clear mask when PPS is
	 * disabled
	 */
	if (rq->type != PTP_CLK_REQ_PEROUT || !wx->ptp_setup_sdp)
		return -EOPNOTSUPP;

	/* Reject requests with unsupported flags */
	if (rq->perout.flags & ~(PTP_PEROUT_DUTY_CYCLE |
				 PTP_PEROUT_PHASE))
		return -EOPNOTSUPP;

	if (rq->perout.phase.sec || rq->perout.phase.nsec) {
		wx_err(wx, "Absolute start time not supported.\n");
		return -EINVAL;
	}

	if (rq->perout.period.sec != 1 || rq->perout.period.nsec) {
		wx_err(wx, "Only 1pps is supported.\n");
		return -EINVAL;
	}

	if (rq->perout.flags & PTP_PEROUT_DUTY_CYCLE) {
		struct timespec64 ts_on;

		ts_on.tv_sec = rq->perout.on.sec;
		ts_on.tv_nsec = rq->perout.on.nsec;
		wx->pps_width = timespec64_to_ns(&ts_on);
	} else {
		wx->pps_width = 120000000;
	}

	if (on)
		set_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags);
	else
		clear_bit(WX_FLAG_PTP_PPS_ENABLED, wx->flags);

	return wx->ptp_setup_sdp(wx);
}

void wx_ptp_check_pps_event(struct wx *wx)
{
	u32 tsauxc, int_status;

	/* this check is necessary in case the interrupt was enabled via some
	 * alternative means (ex. debug_fs). Better to check here than
	 * everywhere that calls this function.
	 */
	if (!wx->ptp_clock)
		return;

	int_status = rd32ptp(wx, WX_TSC_1588_INT_ST);
	if (int_status & WX_TSC_1588_INT_ST_TT1) {

Annotation

Implementation Notes