xref: /openbmc/linux/drivers/ptp/ptp_ocp.c (revision a7e1abad13f3f0366ee625831fecda2b603cdc17)
1*a7e1abadSJonathan Lemon // SPDX-License-Identifier: GPL-2.0-only
2*a7e1abadSJonathan Lemon /* Copyright (c) 2020 Facebook */
3*a7e1abadSJonathan Lemon 
4*a7e1abadSJonathan Lemon #include <linux/err.h>
5*a7e1abadSJonathan Lemon #include <linux/kernel.h>
6*a7e1abadSJonathan Lemon #include <linux/module.h>
7*a7e1abadSJonathan Lemon #include <linux/init.h>
8*a7e1abadSJonathan Lemon #include <linux/pci.h>
9*a7e1abadSJonathan Lemon #include <linux/ptp_clock_kernel.h>
10*a7e1abadSJonathan Lemon 
11*a7e1abadSJonathan Lemon static const struct pci_device_id ptp_ocp_pcidev_id[] = {
12*a7e1abadSJonathan Lemon 	{ PCI_DEVICE(0x1d9b, 0x0400) },
13*a7e1abadSJonathan Lemon 	{ 0 }
14*a7e1abadSJonathan Lemon };
15*a7e1abadSJonathan Lemon MODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id);
16*a7e1abadSJonathan Lemon 
17*a7e1abadSJonathan Lemon #define OCP_REGISTER_OFFSET	0x01000000
18*a7e1abadSJonathan Lemon 
19*a7e1abadSJonathan Lemon struct ocp_reg {
20*a7e1abadSJonathan Lemon 	u32	ctrl;
21*a7e1abadSJonathan Lemon 	u32	status;
22*a7e1abadSJonathan Lemon 	u32	select;
23*a7e1abadSJonathan Lemon 	u32	version;
24*a7e1abadSJonathan Lemon 	u32	time_ns;
25*a7e1abadSJonathan Lemon 	u32	time_sec;
26*a7e1abadSJonathan Lemon 	u32	__pad0[2];
27*a7e1abadSJonathan Lemon 	u32	adjust_ns;
28*a7e1abadSJonathan Lemon 	u32	adjust_sec;
29*a7e1abadSJonathan Lemon 	u32	__pad1[2];
30*a7e1abadSJonathan Lemon 	u32	offset_ns;
31*a7e1abadSJonathan Lemon 	u32	offset_window_ns;
32*a7e1abadSJonathan Lemon };
33*a7e1abadSJonathan Lemon 
34*a7e1abadSJonathan Lemon #define OCP_CTRL_ENABLE		BIT(0)
35*a7e1abadSJonathan Lemon #define OCP_CTRL_ADJUST_TIME	BIT(1)
36*a7e1abadSJonathan Lemon #define OCP_CTRL_ADJUST_OFFSET	BIT(2)
37*a7e1abadSJonathan Lemon #define OCP_CTRL_READ_TIME_REQ	BIT(30)
38*a7e1abadSJonathan Lemon #define OCP_CTRL_READ_TIME_DONE	BIT(31)
39*a7e1abadSJonathan Lemon 
40*a7e1abadSJonathan Lemon #define OCP_STATUS_IN_SYNC	BIT(0)
41*a7e1abadSJonathan Lemon 
42*a7e1abadSJonathan Lemon #define OCP_SELECT_CLK_NONE	0
43*a7e1abadSJonathan Lemon #define OCP_SELECT_CLK_REG	6
44*a7e1abadSJonathan Lemon 
45*a7e1abadSJonathan Lemon struct tod_reg {
46*a7e1abadSJonathan Lemon 	u32	ctrl;
47*a7e1abadSJonathan Lemon 	u32	status;
48*a7e1abadSJonathan Lemon 	u32	uart_polarity;
49*a7e1abadSJonathan Lemon 	u32	version;
50*a7e1abadSJonathan Lemon 	u32	correction_sec;
51*a7e1abadSJonathan Lemon 	u32	__pad0[3];
52*a7e1abadSJonathan Lemon 	u32	uart_baud;
53*a7e1abadSJonathan Lemon 	u32	__pad1[3];
54*a7e1abadSJonathan Lemon 	u32	utc_status;
55*a7e1abadSJonathan Lemon 	u32	leap;
56*a7e1abadSJonathan Lemon };
57*a7e1abadSJonathan Lemon 
58*a7e1abadSJonathan Lemon #define TOD_REGISTER_OFFSET	0x01050000
59*a7e1abadSJonathan Lemon 
60*a7e1abadSJonathan Lemon #define TOD_CTRL_PROTOCOL	BIT(28)
61*a7e1abadSJonathan Lemon #define TOD_CTRL_DISABLE_FMT_A	BIT(17)
62*a7e1abadSJonathan Lemon #define TOD_CTRL_DISABLE_FMT_B	BIT(16)
63*a7e1abadSJonathan Lemon #define TOD_CTRL_ENABLE		BIT(0)
64*a7e1abadSJonathan Lemon #define TOD_CTRL_GNSS_MASK	((1U << 4) - 1)
65*a7e1abadSJonathan Lemon #define TOD_CTRL_GNSS_SHIFT	24
66*a7e1abadSJonathan Lemon 
67*a7e1abadSJonathan Lemon #define TOD_STATUS_UTC_MASK	0xff
68*a7e1abadSJonathan Lemon #define TOD_STATUS_UTC_VALID	BIT(8)
69*a7e1abadSJonathan Lemon #define TOD_STATUS_LEAP_VALID	BIT(16)
70*a7e1abadSJonathan Lemon 
71*a7e1abadSJonathan Lemon struct ptp_ocp {
72*a7e1abadSJonathan Lemon 	struct pci_dev		*pdev;
73*a7e1abadSJonathan Lemon 	spinlock_t		lock;
74*a7e1abadSJonathan Lemon 	void __iomem		*base;
75*a7e1abadSJonathan Lemon 	struct ocp_reg __iomem	*reg;
76*a7e1abadSJonathan Lemon 	struct tod_reg __iomem	*tod;
77*a7e1abadSJonathan Lemon 	struct ptp_clock	*ptp;
78*a7e1abadSJonathan Lemon 	struct ptp_clock_info	ptp_info;
79*a7e1abadSJonathan Lemon };
80*a7e1abadSJonathan Lemon 
81*a7e1abadSJonathan Lemon static int
82*a7e1abadSJonathan Lemon __ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts,
83*a7e1abadSJonathan Lemon 			 struct ptp_system_timestamp *sts)
84*a7e1abadSJonathan Lemon {
85*a7e1abadSJonathan Lemon 	u32 ctrl, time_sec, time_ns;
86*a7e1abadSJonathan Lemon 	int i;
87*a7e1abadSJonathan Lemon 
88*a7e1abadSJonathan Lemon 	ctrl = ioread32(&bp->reg->ctrl);
89*a7e1abadSJonathan Lemon 	ctrl |= OCP_CTRL_READ_TIME_REQ;
90*a7e1abadSJonathan Lemon 
91*a7e1abadSJonathan Lemon 	ptp_read_system_prets(sts);
92*a7e1abadSJonathan Lemon 	iowrite32(ctrl, &bp->reg->ctrl);
93*a7e1abadSJonathan Lemon 
94*a7e1abadSJonathan Lemon 	for (i = 0; i < 100; i++) {
95*a7e1abadSJonathan Lemon 		ctrl = ioread32(&bp->reg->ctrl);
96*a7e1abadSJonathan Lemon 		if (ctrl & OCP_CTRL_READ_TIME_DONE)
97*a7e1abadSJonathan Lemon 			break;
98*a7e1abadSJonathan Lemon 	}
99*a7e1abadSJonathan Lemon 	ptp_read_system_postts(sts);
100*a7e1abadSJonathan Lemon 
101*a7e1abadSJonathan Lemon 	time_ns = ioread32(&bp->reg->time_ns);
102*a7e1abadSJonathan Lemon 	time_sec = ioread32(&bp->reg->time_sec);
103*a7e1abadSJonathan Lemon 
104*a7e1abadSJonathan Lemon 	ts->tv_sec = time_sec;
105*a7e1abadSJonathan Lemon 	ts->tv_nsec = time_ns;
106*a7e1abadSJonathan Lemon 
107*a7e1abadSJonathan Lemon 	return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT;
108*a7e1abadSJonathan Lemon }
109*a7e1abadSJonathan Lemon 
110*a7e1abadSJonathan Lemon static int
111*a7e1abadSJonathan Lemon ptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts,
112*a7e1abadSJonathan Lemon 		 struct ptp_system_timestamp *sts)
113*a7e1abadSJonathan Lemon {
114*a7e1abadSJonathan Lemon 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
115*a7e1abadSJonathan Lemon 	unsigned long flags;
116*a7e1abadSJonathan Lemon 	int err;
117*a7e1abadSJonathan Lemon 
118*a7e1abadSJonathan Lemon 	spin_lock_irqsave(&bp->lock, flags);
119*a7e1abadSJonathan Lemon 	err = __ptp_ocp_gettime_locked(bp, ts, sts);
120*a7e1abadSJonathan Lemon 	spin_unlock_irqrestore(&bp->lock, flags);
121*a7e1abadSJonathan Lemon 
122*a7e1abadSJonathan Lemon 	return err;
123*a7e1abadSJonathan Lemon }
124*a7e1abadSJonathan Lemon 
125*a7e1abadSJonathan Lemon static void
126*a7e1abadSJonathan Lemon __ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts)
127*a7e1abadSJonathan Lemon {
128*a7e1abadSJonathan Lemon 	u32 ctrl, time_sec, time_ns;
129*a7e1abadSJonathan Lemon 	u32 select;
130*a7e1abadSJonathan Lemon 
131*a7e1abadSJonathan Lemon 	time_ns = ts->tv_nsec;
132*a7e1abadSJonathan Lemon 	time_sec = ts->tv_sec;
133*a7e1abadSJonathan Lemon 
134*a7e1abadSJonathan Lemon 	select = ioread32(&bp->reg->select);
135*a7e1abadSJonathan Lemon 	iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
136*a7e1abadSJonathan Lemon 
137*a7e1abadSJonathan Lemon 	iowrite32(time_ns, &bp->reg->adjust_ns);
138*a7e1abadSJonathan Lemon 	iowrite32(time_sec, &bp->reg->adjust_sec);
139*a7e1abadSJonathan Lemon 
140*a7e1abadSJonathan Lemon 	ctrl = ioread32(&bp->reg->ctrl);
141*a7e1abadSJonathan Lemon 	ctrl |= OCP_CTRL_ADJUST_TIME;
142*a7e1abadSJonathan Lemon 	iowrite32(ctrl, &bp->reg->ctrl);
143*a7e1abadSJonathan Lemon 
144*a7e1abadSJonathan Lemon 	/* restore clock selection */
145*a7e1abadSJonathan Lemon 	iowrite32(select >> 16, &bp->reg->select);
146*a7e1abadSJonathan Lemon }
147*a7e1abadSJonathan Lemon 
148*a7e1abadSJonathan Lemon static int
149*a7e1abadSJonathan Lemon ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
150*a7e1abadSJonathan Lemon {
151*a7e1abadSJonathan Lemon 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
152*a7e1abadSJonathan Lemon 	unsigned long flags;
153*a7e1abadSJonathan Lemon 
154*a7e1abadSJonathan Lemon 	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
155*a7e1abadSJonathan Lemon 		return 0;
156*a7e1abadSJonathan Lemon 
157*a7e1abadSJonathan Lemon 	spin_lock_irqsave(&bp->lock, flags);
158*a7e1abadSJonathan Lemon 	__ptp_ocp_settime_locked(bp, ts);
159*a7e1abadSJonathan Lemon 	spin_unlock_irqrestore(&bp->lock, flags);
160*a7e1abadSJonathan Lemon 
161*a7e1abadSJonathan Lemon 	return 0;
162*a7e1abadSJonathan Lemon }
163*a7e1abadSJonathan Lemon 
164*a7e1abadSJonathan Lemon static int
165*a7e1abadSJonathan Lemon ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
166*a7e1abadSJonathan Lemon {
167*a7e1abadSJonathan Lemon 	struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info);
168*a7e1abadSJonathan Lemon 	struct timespec64 ts;
169*a7e1abadSJonathan Lemon 	unsigned long flags;
170*a7e1abadSJonathan Lemon 	int err;
171*a7e1abadSJonathan Lemon 
172*a7e1abadSJonathan Lemon 	if (ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC)
173*a7e1abadSJonathan Lemon 		return 0;
174*a7e1abadSJonathan Lemon 
175*a7e1abadSJonathan Lemon 	spin_lock_irqsave(&bp->lock, flags);
176*a7e1abadSJonathan Lemon 	err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
177*a7e1abadSJonathan Lemon 	if (likely(!err)) {
178*a7e1abadSJonathan Lemon 		timespec64_add_ns(&ts, delta_ns);
179*a7e1abadSJonathan Lemon 		__ptp_ocp_settime_locked(bp, &ts);
180*a7e1abadSJonathan Lemon 	}
181*a7e1abadSJonathan Lemon 	spin_unlock_irqrestore(&bp->lock, flags);
182*a7e1abadSJonathan Lemon 
183*a7e1abadSJonathan Lemon 	return err;
184*a7e1abadSJonathan Lemon }
185*a7e1abadSJonathan Lemon 
186*a7e1abadSJonathan Lemon static int
187*a7e1abadSJonathan Lemon ptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
188*a7e1abadSJonathan Lemon {
189*a7e1abadSJonathan Lemon 	if (scaled_ppm == 0)
190*a7e1abadSJonathan Lemon 		return 0;
191*a7e1abadSJonathan Lemon 
192*a7e1abadSJonathan Lemon 	return -EOPNOTSUPP;
193*a7e1abadSJonathan Lemon }
194*a7e1abadSJonathan Lemon 
195*a7e1abadSJonathan Lemon static const struct ptp_clock_info ptp_ocp_clock_info = {
196*a7e1abadSJonathan Lemon 	.owner		= THIS_MODULE,
197*a7e1abadSJonathan Lemon 	.name		= KBUILD_MODNAME,
198*a7e1abadSJonathan Lemon 	.max_adj	= 100000000,
199*a7e1abadSJonathan Lemon 	.gettimex64	= ptp_ocp_gettimex,
200*a7e1abadSJonathan Lemon 	.settime64	= ptp_ocp_settime,
201*a7e1abadSJonathan Lemon 	.adjtime	= ptp_ocp_adjtime,
202*a7e1abadSJonathan Lemon 	.adjfine	= ptp_ocp_null_adjfine,
203*a7e1abadSJonathan Lemon };
204*a7e1abadSJonathan Lemon 
205*a7e1abadSJonathan Lemon static int
206*a7e1abadSJonathan Lemon ptp_ocp_check_clock(struct ptp_ocp *bp)
207*a7e1abadSJonathan Lemon {
208*a7e1abadSJonathan Lemon 	struct timespec64 ts;
209*a7e1abadSJonathan Lemon 	bool sync;
210*a7e1abadSJonathan Lemon 	u32 ctrl;
211*a7e1abadSJonathan Lemon 
212*a7e1abadSJonathan Lemon 	/* make sure clock is enabled */
213*a7e1abadSJonathan Lemon 	ctrl = ioread32(&bp->reg->ctrl);
214*a7e1abadSJonathan Lemon 	ctrl |= OCP_CTRL_ENABLE;
215*a7e1abadSJonathan Lemon 	iowrite32(ctrl, &bp->reg->ctrl);
216*a7e1abadSJonathan Lemon 
217*a7e1abadSJonathan Lemon 	if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) {
218*a7e1abadSJonathan Lemon 		dev_err(&bp->pdev->dev, "clock not enabled\n");
219*a7e1abadSJonathan Lemon 		return -ENODEV;
220*a7e1abadSJonathan Lemon 	}
221*a7e1abadSJonathan Lemon 
222*a7e1abadSJonathan Lemon 	sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC;
223*a7e1abadSJonathan Lemon 	if (!sync) {
224*a7e1abadSJonathan Lemon 		ktime_get_real_ts64(&ts);
225*a7e1abadSJonathan Lemon 		ptp_ocp_settime(&bp->ptp_info, &ts);
226*a7e1abadSJonathan Lemon 	}
227*a7e1abadSJonathan Lemon 	if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
228*a7e1abadSJonathan Lemon 		dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n",
229*a7e1abadSJonathan Lemon 			 ts.tv_sec, ts.tv_nsec,
230*a7e1abadSJonathan Lemon 			 sync ? "in-sync" : "UNSYNCED");
231*a7e1abadSJonathan Lemon 
232*a7e1abadSJonathan Lemon 	return 0;
233*a7e1abadSJonathan Lemon }
234*a7e1abadSJonathan Lemon 
235*a7e1abadSJonathan Lemon static void
236*a7e1abadSJonathan Lemon ptp_ocp_tod_info(struct ptp_ocp *bp)
237*a7e1abadSJonathan Lemon {
238*a7e1abadSJonathan Lemon 	static const char * const proto_name[] = {
239*a7e1abadSJonathan Lemon 		"NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none",
240*a7e1abadSJonathan Lemon 		"UBX", "UBX_UTC", "UBX_LS", "UBX_none"
241*a7e1abadSJonathan Lemon 	};
242*a7e1abadSJonathan Lemon 	static const char * const gnss_name[] = {
243*a7e1abadSJonathan Lemon 		"ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU",
244*a7e1abadSJonathan Lemon 	};
245*a7e1abadSJonathan Lemon 	u32 version, ctrl, reg;
246*a7e1abadSJonathan Lemon 	int idx;
247*a7e1abadSJonathan Lemon 
248*a7e1abadSJonathan Lemon 	version = ioread32(&bp->tod->version);
249*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "TOD Version %d.%d.%d\n",
250*a7e1abadSJonathan Lemon 		 version >> 24, (version >> 16) & 0xff, version & 0xffff);
251*a7e1abadSJonathan Lemon 
252*a7e1abadSJonathan Lemon 	ctrl = ioread32(&bp->tod->ctrl);
253*a7e1abadSJonathan Lemon 	ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE;
254*a7e1abadSJonathan Lemon 	ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B);
255*a7e1abadSJonathan Lemon 	iowrite32(ctrl, &bp->tod->ctrl);
256*a7e1abadSJonathan Lemon 
257*a7e1abadSJonathan Lemon 	ctrl = ioread32(&bp->tod->ctrl);
258*a7e1abadSJonathan Lemon 	idx = ctrl & TOD_CTRL_PROTOCOL ? 4 : 0;
259*a7e1abadSJonathan Lemon 	idx += (ctrl >> 16) & 3;
260*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "control: %x\n", ctrl);
261*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "TOD Protocol %s %s\n", proto_name[idx],
262*a7e1abadSJonathan Lemon 		 ctrl & TOD_CTRL_ENABLE ? "enabled" : "");
263*a7e1abadSJonathan Lemon 
264*a7e1abadSJonathan Lemon 	idx = (ctrl >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK;
265*a7e1abadSJonathan Lemon 	if (idx < ARRAY_SIZE(gnss_name))
266*a7e1abadSJonathan Lemon 		dev_info(&bp->pdev->dev, "GNSS %s\n", gnss_name[idx]);
267*a7e1abadSJonathan Lemon 
268*a7e1abadSJonathan Lemon 	reg = ioread32(&bp->tod->status);
269*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "status: %x\n", reg);
270*a7e1abadSJonathan Lemon 
271*a7e1abadSJonathan Lemon 	reg = ioread32(&bp->tod->correction_sec);
272*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "correction: %d\n", reg);
273*a7e1abadSJonathan Lemon 
274*a7e1abadSJonathan Lemon 	reg = ioread32(&bp->tod->utc_status);
275*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "utc_status: %x\n", reg);
276*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "utc_offset: %d  valid:%d  leap_valid:%d\n",
277*a7e1abadSJonathan Lemon 		 reg & TOD_STATUS_UTC_MASK, reg & TOD_STATUS_UTC_VALID ? 1 : 0,
278*a7e1abadSJonathan Lemon 		 reg & TOD_STATUS_LEAP_VALID ? 1 : 0);
279*a7e1abadSJonathan Lemon }
280*a7e1abadSJonathan Lemon 
281*a7e1abadSJonathan Lemon static void
282*a7e1abadSJonathan Lemon ptp_ocp_info(struct ptp_ocp *bp)
283*a7e1abadSJonathan Lemon {
284*a7e1abadSJonathan Lemon 	static const char * const clock_name[] = {
285*a7e1abadSJonathan Lemon 		"NO", "TOD", "IRIG", "PPS", "PTP", "RTC", "REGS", "EXT"
286*a7e1abadSJonathan Lemon 	};
287*a7e1abadSJonathan Lemon 	u32 version, select;
288*a7e1abadSJonathan Lemon 
289*a7e1abadSJonathan Lemon 	version = ioread32(&bp->reg->version);
290*a7e1abadSJonathan Lemon 	select = ioread32(&bp->reg->select);
291*a7e1abadSJonathan Lemon 	dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n",
292*a7e1abadSJonathan Lemon 		 version >> 24, (version >> 16) & 0xff, version & 0xffff,
293*a7e1abadSJonathan Lemon 		 clock_name[select & 7],
294*a7e1abadSJonathan Lemon 		 ptp_clock_index(bp->ptp));
295*a7e1abadSJonathan Lemon 
296*a7e1abadSJonathan Lemon 	ptp_ocp_tod_info(bp);
297*a7e1abadSJonathan Lemon }
298*a7e1abadSJonathan Lemon 
299*a7e1abadSJonathan Lemon static int
300*a7e1abadSJonathan Lemon ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id)
301*a7e1abadSJonathan Lemon {
302*a7e1abadSJonathan Lemon 	struct ptp_ocp *bp;
303*a7e1abadSJonathan Lemon 	int err;
304*a7e1abadSJonathan Lemon 
305*a7e1abadSJonathan Lemon 	bp = kzalloc(sizeof(*bp), GFP_KERNEL);
306*a7e1abadSJonathan Lemon 	if (!bp)
307*a7e1abadSJonathan Lemon 		return -ENOMEM;
308*a7e1abadSJonathan Lemon 	bp->pdev = pdev;
309*a7e1abadSJonathan Lemon 	pci_set_drvdata(pdev, bp);
310*a7e1abadSJonathan Lemon 
311*a7e1abadSJonathan Lemon 	err = pci_enable_device(pdev);
312*a7e1abadSJonathan Lemon 	if (err) {
313*a7e1abadSJonathan Lemon 		dev_err(&pdev->dev, "pci_enable_device\n");
314*a7e1abadSJonathan Lemon 		goto out_free;
315*a7e1abadSJonathan Lemon 	}
316*a7e1abadSJonathan Lemon 
317*a7e1abadSJonathan Lemon 	err = pci_request_regions(pdev, KBUILD_MODNAME);
318*a7e1abadSJonathan Lemon 	if (err) {
319*a7e1abadSJonathan Lemon 		dev_err(&pdev->dev, "pci_request_region\n");
320*a7e1abadSJonathan Lemon 		goto out_disable;
321*a7e1abadSJonathan Lemon 	}
322*a7e1abadSJonathan Lemon 
323*a7e1abadSJonathan Lemon 	bp->base = pci_ioremap_bar(pdev, 0);
324*a7e1abadSJonathan Lemon 	if (!bp->base) {
325*a7e1abadSJonathan Lemon 		dev_err(&pdev->dev, "io_remap bar0\n");
326*a7e1abadSJonathan Lemon 		err = -ENOMEM;
327*a7e1abadSJonathan Lemon 		goto out;
328*a7e1abadSJonathan Lemon 	}
329*a7e1abadSJonathan Lemon 	bp->reg = bp->base + OCP_REGISTER_OFFSET;
330*a7e1abadSJonathan Lemon 	bp->tod = bp->base + TOD_REGISTER_OFFSET;
331*a7e1abadSJonathan Lemon 	bp->ptp_info = ptp_ocp_clock_info;
332*a7e1abadSJonathan Lemon 	spin_lock_init(&bp->lock);
333*a7e1abadSJonathan Lemon 
334*a7e1abadSJonathan Lemon 	err = ptp_ocp_check_clock(bp);
335*a7e1abadSJonathan Lemon 	if (err)
336*a7e1abadSJonathan Lemon 		goto out;
337*a7e1abadSJonathan Lemon 
338*a7e1abadSJonathan Lemon 	bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev);
339*a7e1abadSJonathan Lemon 	if (IS_ERR(bp->ptp)) {
340*a7e1abadSJonathan Lemon 		dev_err(&pdev->dev, "ptp_clock_register\n");
341*a7e1abadSJonathan Lemon 		err = PTR_ERR(bp->ptp);
342*a7e1abadSJonathan Lemon 		goto out;
343*a7e1abadSJonathan Lemon 	}
344*a7e1abadSJonathan Lemon 
345*a7e1abadSJonathan Lemon 	ptp_ocp_info(bp);
346*a7e1abadSJonathan Lemon 
347*a7e1abadSJonathan Lemon 	return 0;
348*a7e1abadSJonathan Lemon 
349*a7e1abadSJonathan Lemon out:
350*a7e1abadSJonathan Lemon 	pci_release_regions(pdev);
351*a7e1abadSJonathan Lemon out_disable:
352*a7e1abadSJonathan Lemon 	pci_disable_device(pdev);
353*a7e1abadSJonathan Lemon out_free:
354*a7e1abadSJonathan Lemon 	kfree(bp);
355*a7e1abadSJonathan Lemon 
356*a7e1abadSJonathan Lemon 	return err;
357*a7e1abadSJonathan Lemon }
358*a7e1abadSJonathan Lemon 
359*a7e1abadSJonathan Lemon static void
360*a7e1abadSJonathan Lemon ptp_ocp_remove(struct pci_dev *pdev)
361*a7e1abadSJonathan Lemon {
362*a7e1abadSJonathan Lemon 	struct ptp_ocp *bp = pci_get_drvdata(pdev);
363*a7e1abadSJonathan Lemon 
364*a7e1abadSJonathan Lemon 	ptp_clock_unregister(bp->ptp);
365*a7e1abadSJonathan Lemon 	pci_iounmap(pdev, bp->base);
366*a7e1abadSJonathan Lemon 	pci_release_regions(pdev);
367*a7e1abadSJonathan Lemon 	pci_disable_device(pdev);
368*a7e1abadSJonathan Lemon 	pci_set_drvdata(pdev, NULL);
369*a7e1abadSJonathan Lemon 	kfree(bp);
370*a7e1abadSJonathan Lemon }
371*a7e1abadSJonathan Lemon 
372*a7e1abadSJonathan Lemon static struct pci_driver ptp_ocp_driver = {
373*a7e1abadSJonathan Lemon 	.name		= KBUILD_MODNAME,
374*a7e1abadSJonathan Lemon 	.id_table	= ptp_ocp_pcidev_id,
375*a7e1abadSJonathan Lemon 	.probe		= ptp_ocp_probe,
376*a7e1abadSJonathan Lemon 	.remove		= ptp_ocp_remove,
377*a7e1abadSJonathan Lemon };
378*a7e1abadSJonathan Lemon 
379*a7e1abadSJonathan Lemon static int __init
380*a7e1abadSJonathan Lemon ptp_ocp_init(void)
381*a7e1abadSJonathan Lemon {
382*a7e1abadSJonathan Lemon 	int err;
383*a7e1abadSJonathan Lemon 
384*a7e1abadSJonathan Lemon 	err = pci_register_driver(&ptp_ocp_driver);
385*a7e1abadSJonathan Lemon 	return err;
386*a7e1abadSJonathan Lemon }
387*a7e1abadSJonathan Lemon 
388*a7e1abadSJonathan Lemon static void __exit
389*a7e1abadSJonathan Lemon ptp_ocp_fini(void)
390*a7e1abadSJonathan Lemon {
391*a7e1abadSJonathan Lemon 	pci_unregister_driver(&ptp_ocp_driver);
392*a7e1abadSJonathan Lemon }
393*a7e1abadSJonathan Lemon 
394*a7e1abadSJonathan Lemon module_init(ptp_ocp_init);
395*a7e1abadSJonathan Lemon module_exit(ptp_ocp_fini);
396*a7e1abadSJonathan Lemon 
397*a7e1abadSJonathan Lemon MODULE_DESCRIPTION("OpenCompute TimeCard driver");
398*a7e1abadSJonathan Lemon MODULE_LICENSE("GPL v2");
399