xref: /openbmc/linux/drivers/net/ethernet/cavium/common/cavium_ptp.c (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
18c56df37SRadoslaw Biernacki // SPDX-License-Identifier: GPL-2.0
28c56df37SRadoslaw Biernacki /* cavium_ptp.c - PTP 1588 clock on Cavium hardware
38c56df37SRadoslaw Biernacki  * Copyright (c) 2003-2015, 2017 Cavium, Inc.
48c56df37SRadoslaw Biernacki  */
58c56df37SRadoslaw Biernacki 
68c56df37SRadoslaw Biernacki #include <linux/device.h>
78c56df37SRadoslaw Biernacki #include <linux/module.h>
88c56df37SRadoslaw Biernacki #include <linux/timecounter.h>
98c56df37SRadoslaw Biernacki #include <linux/pci.h>
108c56df37SRadoslaw Biernacki 
118c56df37SRadoslaw Biernacki #include "cavium_ptp.h"
128c56df37SRadoslaw Biernacki 
1334343410SStephen Hemminger #define DRV_NAME "cavium_ptp"
148c56df37SRadoslaw Biernacki 
158c56df37SRadoslaw Biernacki #define PCI_DEVICE_ID_CAVIUM_PTP	0xA00C
16aa3afcccSPrakash Brahmajyosyula #define PCI_SUBSYS_DEVID_88XX_PTP	0xA10C
17aa3afcccSPrakash Brahmajyosyula #define PCI_SUBSYS_DEVID_81XX_PTP	0XA20C
18aa3afcccSPrakash Brahmajyosyula #define PCI_SUBSYS_DEVID_83XX_PTP	0xA30C
198c56df37SRadoslaw Biernacki #define PCI_DEVICE_ID_CAVIUM_RST	0xA00E
208c56df37SRadoslaw Biernacki 
218c56df37SRadoslaw Biernacki #define PCI_PTP_BAR_NO	0
228c56df37SRadoslaw Biernacki #define PCI_RST_BAR_NO	0
238c56df37SRadoslaw Biernacki 
248c56df37SRadoslaw Biernacki #define PTP_CLOCK_CFG		0xF00ULL
258c56df37SRadoslaw Biernacki #define  PTP_CLOCK_CFG_PTP_EN	BIT(0)
268c56df37SRadoslaw Biernacki #define PTP_CLOCK_LO		0xF08ULL
278c56df37SRadoslaw Biernacki #define PTP_CLOCK_HI		0xF10ULL
288c56df37SRadoslaw Biernacki #define PTP_CLOCK_COMP		0xF18ULL
298c56df37SRadoslaw Biernacki 
308c56df37SRadoslaw Biernacki #define RST_BOOT	0x1600ULL
318c56df37SRadoslaw Biernacki #define CLOCK_BASE_RATE	50000000ULL
328c56df37SRadoslaw Biernacki 
ptp_cavium_clock_get(void)338c56df37SRadoslaw Biernacki static u64 ptp_cavium_clock_get(void)
348c56df37SRadoslaw Biernacki {
358c56df37SRadoslaw Biernacki 	struct pci_dev *pdev;
368c56df37SRadoslaw Biernacki 	void __iomem *base;
378c56df37SRadoslaw Biernacki 	u64 ret = CLOCK_BASE_RATE * 16;
388c56df37SRadoslaw Biernacki 
398c56df37SRadoslaw Biernacki 	pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
408c56df37SRadoslaw Biernacki 			      PCI_DEVICE_ID_CAVIUM_RST, NULL);
418c56df37SRadoslaw Biernacki 	if (!pdev)
428c56df37SRadoslaw Biernacki 		goto error;
438c56df37SRadoslaw Biernacki 
448c56df37SRadoslaw Biernacki 	base = pci_ioremap_bar(pdev, PCI_RST_BAR_NO);
458c56df37SRadoslaw Biernacki 	if (!base)
468c56df37SRadoslaw Biernacki 		goto error_put_pdev;
478c56df37SRadoslaw Biernacki 
488c56df37SRadoslaw Biernacki 	ret = CLOCK_BASE_RATE * ((readq(base + RST_BOOT) >> 33) & 0x3f);
498c56df37SRadoslaw Biernacki 
508c56df37SRadoslaw Biernacki 	iounmap(base);
518c56df37SRadoslaw Biernacki 
528c56df37SRadoslaw Biernacki error_put_pdev:
538c56df37SRadoslaw Biernacki 	pci_dev_put(pdev);
548c56df37SRadoslaw Biernacki 
558c56df37SRadoslaw Biernacki error:
568c56df37SRadoslaw Biernacki 	return ret;
578c56df37SRadoslaw Biernacki }
588c56df37SRadoslaw Biernacki 
cavium_ptp_get(void)598c56df37SRadoslaw Biernacki struct cavium_ptp *cavium_ptp_get(void)
608c56df37SRadoslaw Biernacki {
618c56df37SRadoslaw Biernacki 	struct cavium_ptp *ptp;
628c56df37SRadoslaw Biernacki 	struct pci_dev *pdev;
638c56df37SRadoslaw Biernacki 
648c56df37SRadoslaw Biernacki 	pdev = pci_get_device(PCI_VENDOR_ID_CAVIUM,
658c56df37SRadoslaw Biernacki 			      PCI_DEVICE_ID_CAVIUM_PTP, NULL);
668c56df37SRadoslaw Biernacki 	if (!pdev)
678c56df37SRadoslaw Biernacki 		return ERR_PTR(-ENODEV);
688c56df37SRadoslaw Biernacki 
698c56df37SRadoslaw Biernacki 	ptp = pci_get_drvdata(pdev);
708c56df37SRadoslaw Biernacki 	if (!ptp)
718c56df37SRadoslaw Biernacki 		ptp = ERR_PTR(-EPROBE_DEFER);
728c56df37SRadoslaw Biernacki 	if (IS_ERR(ptp))
738c56df37SRadoslaw Biernacki 		pci_dev_put(pdev);
748c56df37SRadoslaw Biernacki 
758c56df37SRadoslaw Biernacki 	return ptp;
768c56df37SRadoslaw Biernacki }
778c56df37SRadoslaw Biernacki EXPORT_SYMBOL(cavium_ptp_get);
788c56df37SRadoslaw Biernacki 
cavium_ptp_put(struct cavium_ptp * ptp)798c56df37SRadoslaw Biernacki void cavium_ptp_put(struct cavium_ptp *ptp)
808c56df37SRadoslaw Biernacki {
8107a2e1cfSJan Glauber 	if (!ptp)
8207a2e1cfSJan Glauber 		return;
838c56df37SRadoslaw Biernacki 	pci_dev_put(ptp->pdev);
848c56df37SRadoslaw Biernacki }
858c56df37SRadoslaw Biernacki EXPORT_SYMBOL(cavium_ptp_put);
868c56df37SRadoslaw Biernacki 
878c56df37SRadoslaw Biernacki /**
888c56df37SRadoslaw Biernacki  * cavium_ptp_adjfine() - Adjust ptp frequency
89*74c654a8SWang Hai  * @ptp_info: PTP clock info
908c56df37SRadoslaw Biernacki  * @scaled_ppm: how much to adjust by, in parts per million, but with a
918c56df37SRadoslaw Biernacki  *              16 bit binary fractional field
928c56df37SRadoslaw Biernacki  */
cavium_ptp_adjfine(struct ptp_clock_info * ptp_info,long scaled_ppm)938c56df37SRadoslaw Biernacki static int cavium_ptp_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm)
948c56df37SRadoslaw Biernacki {
958c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock =
968c56df37SRadoslaw Biernacki 		container_of(ptp_info, struct cavium_ptp, ptp_info);
978c56df37SRadoslaw Biernacki 	unsigned long flags;
988c56df37SRadoslaw Biernacki 	u64 comp;
998c56df37SRadoslaw Biernacki 	u64 adj;
1008c56df37SRadoslaw Biernacki 	bool neg_adj = false;
1018c56df37SRadoslaw Biernacki 
1028c56df37SRadoslaw Biernacki 	if (scaled_ppm < 0) {
1038c56df37SRadoslaw Biernacki 		neg_adj = true;
1048c56df37SRadoslaw Biernacki 		scaled_ppm = -scaled_ppm;
1058c56df37SRadoslaw Biernacki 	}
1068c56df37SRadoslaw Biernacki 
1078c56df37SRadoslaw Biernacki 	/* The hardware adds the clock compensation value to the PTP clock
1088c56df37SRadoslaw Biernacki 	 * on every coprocessor clock cycle. Typical convention is that it
1098c56df37SRadoslaw Biernacki 	 * represent number of nanosecond betwen each cycle. In this
1108c56df37SRadoslaw Biernacki 	 * convention compensation value is in 64 bit fixed-point
1118c56df37SRadoslaw Biernacki 	 * representation where upper 32 bits are number of nanoseconds
1128c56df37SRadoslaw Biernacki 	 * and lower is fractions of nanosecond.
1138c56df37SRadoslaw Biernacki 	 * The scaled_ppm represent the ratio in "parts per bilion" by which the
1148c56df37SRadoslaw Biernacki 	 * compensation value should be corrected.
1158c56df37SRadoslaw Biernacki 	 * To calculate new compenstation value we use 64bit fixed point
1168c56df37SRadoslaw Biernacki 	 * arithmetic on following formula
1178c56df37SRadoslaw Biernacki 	 * comp = tbase + tbase * scaled_ppm / (1M * 2^16)
1188c56df37SRadoslaw Biernacki 	 * where tbase is the basic compensation value calculated initialy
1198c56df37SRadoslaw Biernacki 	 * in cavium_ptp_init() -> tbase = 1/Hz. Then we use endian
1208c56df37SRadoslaw Biernacki 	 * independent structure definition to write data to PTP register.
1218c56df37SRadoslaw Biernacki 	 */
1228c56df37SRadoslaw Biernacki 	comp = ((u64)1000000000ull << 32) / clock->clock_rate;
1238c56df37SRadoslaw Biernacki 	adj = comp * scaled_ppm;
1248c56df37SRadoslaw Biernacki 	adj >>= 16;
1258c56df37SRadoslaw Biernacki 	adj = div_u64(adj, 1000000ull);
1268c56df37SRadoslaw Biernacki 	comp = neg_adj ? comp - adj : comp + adj;
1278c56df37SRadoslaw Biernacki 
1288c56df37SRadoslaw Biernacki 	spin_lock_irqsave(&clock->spin_lock, flags);
1298c56df37SRadoslaw Biernacki 	writeq(comp, clock->reg_base + PTP_CLOCK_COMP);
1308c56df37SRadoslaw Biernacki 	spin_unlock_irqrestore(&clock->spin_lock, flags);
1318c56df37SRadoslaw Biernacki 
1328c56df37SRadoslaw Biernacki 	return 0;
1338c56df37SRadoslaw Biernacki }
1348c56df37SRadoslaw Biernacki 
1358c56df37SRadoslaw Biernacki /**
1368c56df37SRadoslaw Biernacki  * cavium_ptp_adjtime() - Adjust ptp time
137*74c654a8SWang Hai  * @ptp_info:   PTP clock info
1388c56df37SRadoslaw Biernacki  * @delta: how much to adjust by, in nanosecs
1398c56df37SRadoslaw Biernacki  */
cavium_ptp_adjtime(struct ptp_clock_info * ptp_info,s64 delta)1408c56df37SRadoslaw Biernacki static int cavium_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
1418c56df37SRadoslaw Biernacki {
1428c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock =
1438c56df37SRadoslaw Biernacki 		container_of(ptp_info, struct cavium_ptp, ptp_info);
1448c56df37SRadoslaw Biernacki 	unsigned long flags;
1458c56df37SRadoslaw Biernacki 
1468c56df37SRadoslaw Biernacki 	spin_lock_irqsave(&clock->spin_lock, flags);
1478c56df37SRadoslaw Biernacki 	timecounter_adjtime(&clock->time_counter, delta);
1488c56df37SRadoslaw Biernacki 	spin_unlock_irqrestore(&clock->spin_lock, flags);
1498c56df37SRadoslaw Biernacki 
1508c56df37SRadoslaw Biernacki 	/* Sync, for network driver to get latest value */
1518c56df37SRadoslaw Biernacki 	smp_mb();
1528c56df37SRadoslaw Biernacki 
1538c56df37SRadoslaw Biernacki 	return 0;
1548c56df37SRadoslaw Biernacki }
1558c56df37SRadoslaw Biernacki 
1568c56df37SRadoslaw Biernacki /**
1578c56df37SRadoslaw Biernacki  * cavium_ptp_gettime() - Get hardware clock time with adjustment
158*74c654a8SWang Hai  * @ptp_info: PTP clock info
1598c56df37SRadoslaw Biernacki  * @ts:  timespec
1608c56df37SRadoslaw Biernacki  */
cavium_ptp_gettime(struct ptp_clock_info * ptp_info,struct timespec64 * ts)1618c56df37SRadoslaw Biernacki static int cavium_ptp_gettime(struct ptp_clock_info *ptp_info,
1628c56df37SRadoslaw Biernacki 			      struct timespec64 *ts)
1638c56df37SRadoslaw Biernacki {
1648c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock =
1658c56df37SRadoslaw Biernacki 		container_of(ptp_info, struct cavium_ptp, ptp_info);
1668c56df37SRadoslaw Biernacki 	unsigned long flags;
1678c56df37SRadoslaw Biernacki 	u64 nsec;
1688c56df37SRadoslaw Biernacki 
1698c56df37SRadoslaw Biernacki 	spin_lock_irqsave(&clock->spin_lock, flags);
1708c56df37SRadoslaw Biernacki 	nsec = timecounter_read(&clock->time_counter);
1718c56df37SRadoslaw Biernacki 	spin_unlock_irqrestore(&clock->spin_lock, flags);
1728c56df37SRadoslaw Biernacki 
1738c56df37SRadoslaw Biernacki 	*ts = ns_to_timespec64(nsec);
1748c56df37SRadoslaw Biernacki 
1758c56df37SRadoslaw Biernacki 	return 0;
1768c56df37SRadoslaw Biernacki }
1778c56df37SRadoslaw Biernacki 
1788c56df37SRadoslaw Biernacki /**
1798c56df37SRadoslaw Biernacki  * cavium_ptp_settime() - Set hardware clock time. Reset adjustment
180*74c654a8SWang Hai  * @ptp_info: PTP clock info
1818c56df37SRadoslaw Biernacki  * @ts:  timespec
1828c56df37SRadoslaw Biernacki  */
cavium_ptp_settime(struct ptp_clock_info * ptp_info,const struct timespec64 * ts)1838c56df37SRadoslaw Biernacki static int cavium_ptp_settime(struct ptp_clock_info *ptp_info,
1848c56df37SRadoslaw Biernacki 			      const struct timespec64 *ts)
1858c56df37SRadoslaw Biernacki {
1868c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock =
1878c56df37SRadoslaw Biernacki 		container_of(ptp_info, struct cavium_ptp, ptp_info);
1888c56df37SRadoslaw Biernacki 	unsigned long flags;
1898c56df37SRadoslaw Biernacki 	u64 nsec;
1908c56df37SRadoslaw Biernacki 
1918c56df37SRadoslaw Biernacki 	nsec = timespec64_to_ns(ts);
1928c56df37SRadoslaw Biernacki 
1938c56df37SRadoslaw Biernacki 	spin_lock_irqsave(&clock->spin_lock, flags);
1948c56df37SRadoslaw Biernacki 	timecounter_init(&clock->time_counter, &clock->cycle_counter, nsec);
1958c56df37SRadoslaw Biernacki 	spin_unlock_irqrestore(&clock->spin_lock, flags);
1968c56df37SRadoslaw Biernacki 
1978c56df37SRadoslaw Biernacki 	return 0;
1988c56df37SRadoslaw Biernacki }
1998c56df37SRadoslaw Biernacki 
2008c56df37SRadoslaw Biernacki /**
2018c56df37SRadoslaw Biernacki  * cavium_ptp_enable() - Request to enable or disable an ancillary feature.
202*74c654a8SWang Hai  * @ptp_info: PTP clock info
2038c56df37SRadoslaw Biernacki  * @rq:  request
2048c56df37SRadoslaw Biernacki  * @on:  is it on
2058c56df37SRadoslaw Biernacki  */
cavium_ptp_enable(struct ptp_clock_info * ptp_info,struct ptp_clock_request * rq,int on)2068c56df37SRadoslaw Biernacki static int cavium_ptp_enable(struct ptp_clock_info *ptp_info,
2078c56df37SRadoslaw Biernacki 			     struct ptp_clock_request *rq, int on)
2088c56df37SRadoslaw Biernacki {
2098c56df37SRadoslaw Biernacki 	return -EOPNOTSUPP;
2108c56df37SRadoslaw Biernacki }
2118c56df37SRadoslaw Biernacki 
cavium_ptp_cc_read(const struct cyclecounter * cc)2128c56df37SRadoslaw Biernacki static u64 cavium_ptp_cc_read(const struct cyclecounter *cc)
2138c56df37SRadoslaw Biernacki {
2148c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock =
2158c56df37SRadoslaw Biernacki 		container_of(cc, struct cavium_ptp, cycle_counter);
2168c56df37SRadoslaw Biernacki 
2178c56df37SRadoslaw Biernacki 	return readq(clock->reg_base + PTP_CLOCK_HI);
2188c56df37SRadoslaw Biernacki }
2198c56df37SRadoslaw Biernacki 
cavium_ptp_probe(struct pci_dev * pdev,const struct pci_device_id * ent)2208c56df37SRadoslaw Biernacki static int cavium_ptp_probe(struct pci_dev *pdev,
2218c56df37SRadoslaw Biernacki 			    const struct pci_device_id *ent)
2228c56df37SRadoslaw Biernacki {
2238c56df37SRadoslaw Biernacki 	struct device *dev = &pdev->dev;
2248c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock;
2258c56df37SRadoslaw Biernacki 	struct cyclecounter *cc;
2268c56df37SRadoslaw Biernacki 	u64 clock_cfg;
2278c56df37SRadoslaw Biernacki 	u64 clock_comp;
2288c56df37SRadoslaw Biernacki 	int err;
2298c56df37SRadoslaw Biernacki 
2308c56df37SRadoslaw Biernacki 	clock = devm_kzalloc(dev, sizeof(*clock), GFP_KERNEL);
2318c56df37SRadoslaw Biernacki 	if (!clock) {
2328c56df37SRadoslaw Biernacki 		err = -ENOMEM;
2338c56df37SRadoslaw Biernacki 		goto error;
2348c56df37SRadoslaw Biernacki 	}
2358c56df37SRadoslaw Biernacki 
2368c56df37SRadoslaw Biernacki 	clock->pdev = pdev;
2378c56df37SRadoslaw Biernacki 
2388c56df37SRadoslaw Biernacki 	err = pcim_enable_device(pdev);
2398c56df37SRadoslaw Biernacki 	if (err)
2408c56df37SRadoslaw Biernacki 		goto error_free;
2418c56df37SRadoslaw Biernacki 
2428c56df37SRadoslaw Biernacki 	err = pcim_iomap_regions(pdev, 1 << PCI_PTP_BAR_NO, pci_name(pdev));
2438c56df37SRadoslaw Biernacki 	if (err)
2448c56df37SRadoslaw Biernacki 		goto error_free;
2458c56df37SRadoslaw Biernacki 
2468c56df37SRadoslaw Biernacki 	clock->reg_base = pcim_iomap_table(pdev)[PCI_PTP_BAR_NO];
2478c56df37SRadoslaw Biernacki 
2488c56df37SRadoslaw Biernacki 	spin_lock_init(&clock->spin_lock);
2498c56df37SRadoslaw Biernacki 
2508c56df37SRadoslaw Biernacki 	cc = &clock->cycle_counter;
2518c56df37SRadoslaw Biernacki 	cc->read = cavium_ptp_cc_read;
2528c56df37SRadoslaw Biernacki 	cc->mask = CYCLECOUNTER_MASK(64);
2538c56df37SRadoslaw Biernacki 	cc->mult = 1;
2548c56df37SRadoslaw Biernacki 	cc->shift = 0;
2558c56df37SRadoslaw Biernacki 
2568c56df37SRadoslaw Biernacki 	timecounter_init(&clock->time_counter, &clock->cycle_counter,
2578c56df37SRadoslaw Biernacki 			 ktime_to_ns(ktime_get_real()));
2588c56df37SRadoslaw Biernacki 
2598c56df37SRadoslaw Biernacki 	clock->clock_rate = ptp_cavium_clock_get();
2608c56df37SRadoslaw Biernacki 
2618c56df37SRadoslaw Biernacki 	clock->ptp_info = (struct ptp_clock_info) {
2628c56df37SRadoslaw Biernacki 		.owner		= THIS_MODULE,
2638c56df37SRadoslaw Biernacki 		.name		= "ThunderX PTP",
2648c56df37SRadoslaw Biernacki 		.max_adj	= 1000000000ull,
2658c56df37SRadoslaw Biernacki 		.n_ext_ts	= 0,
2668c56df37SRadoslaw Biernacki 		.n_pins		= 0,
2678c56df37SRadoslaw Biernacki 		.pps		= 0,
2688c56df37SRadoslaw Biernacki 		.adjfine	= cavium_ptp_adjfine,
2698c56df37SRadoslaw Biernacki 		.adjtime	= cavium_ptp_adjtime,
2708c56df37SRadoslaw Biernacki 		.gettime64	= cavium_ptp_gettime,
2718c56df37SRadoslaw Biernacki 		.settime64	= cavium_ptp_settime,
2728c56df37SRadoslaw Biernacki 		.enable		= cavium_ptp_enable,
2738c56df37SRadoslaw Biernacki 	};
2748c56df37SRadoslaw Biernacki 
2758c56df37SRadoslaw Biernacki 	clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
2768c56df37SRadoslaw Biernacki 	clock_cfg |= PTP_CLOCK_CFG_PTP_EN;
2778c56df37SRadoslaw Biernacki 	writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
2788c56df37SRadoslaw Biernacki 
2798c56df37SRadoslaw Biernacki 	clock_comp = ((u64)1000000000ull << 32) / clock->clock_rate;
2808c56df37SRadoslaw Biernacki 	writeq(clock_comp, clock->reg_base + PTP_CLOCK_COMP);
2818c56df37SRadoslaw Biernacki 
2828c56df37SRadoslaw Biernacki 	clock->ptp_clock = ptp_clock_register(&clock->ptp_info, dev);
2838c56df37SRadoslaw Biernacki 	if (IS_ERR(clock->ptp_clock)) {
2848c56df37SRadoslaw Biernacki 		err = PTR_ERR(clock->ptp_clock);
2858c56df37SRadoslaw Biernacki 		goto error_stop;
2868c56df37SRadoslaw Biernacki 	}
2878c56df37SRadoslaw Biernacki 
2888c56df37SRadoslaw Biernacki 	pci_set_drvdata(pdev, clock);
2898c56df37SRadoslaw Biernacki 	return 0;
2908c56df37SRadoslaw Biernacki 
2918c56df37SRadoslaw Biernacki error_stop:
2928c56df37SRadoslaw Biernacki 	clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
2938c56df37SRadoslaw Biernacki 	clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
2948c56df37SRadoslaw Biernacki 	writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
2958c56df37SRadoslaw Biernacki 	pcim_iounmap_regions(pdev, 1 << PCI_PTP_BAR_NO);
2968c56df37SRadoslaw Biernacki 
2978c56df37SRadoslaw Biernacki error_free:
2988c56df37SRadoslaw Biernacki 	devm_kfree(dev, clock);
2998c56df37SRadoslaw Biernacki 
3008c56df37SRadoslaw Biernacki error:
3018c56df37SRadoslaw Biernacki 	/* For `cavium_ptp_get()` we need to differentiate between the case
3028c56df37SRadoslaw Biernacki 	 * when the core has not tried to probe this device and the case when
3038c56df37SRadoslaw Biernacki 	 * the probe failed.  In the later case we pretend that the
3048c56df37SRadoslaw Biernacki 	 * initialization was successful and keep the error in
3058c56df37SRadoslaw Biernacki 	 * `dev->driver_data`.
3068c56df37SRadoslaw Biernacki 	 */
3078c56df37SRadoslaw Biernacki 	pci_set_drvdata(pdev, ERR_PTR(err));
3088c56df37SRadoslaw Biernacki 	return 0;
3098c56df37SRadoslaw Biernacki }
3108c56df37SRadoslaw Biernacki 
cavium_ptp_remove(struct pci_dev * pdev)3118c56df37SRadoslaw Biernacki static void cavium_ptp_remove(struct pci_dev *pdev)
3128c56df37SRadoslaw Biernacki {
3138c56df37SRadoslaw Biernacki 	struct cavium_ptp *clock = pci_get_drvdata(pdev);
3148c56df37SRadoslaw Biernacki 	u64 clock_cfg;
3158c56df37SRadoslaw Biernacki 
3168c56df37SRadoslaw Biernacki 	if (IS_ERR_OR_NULL(clock))
3178c56df37SRadoslaw Biernacki 		return;
3188c56df37SRadoslaw Biernacki 
3198c56df37SRadoslaw Biernacki 	ptp_clock_unregister(clock->ptp_clock);
3208c56df37SRadoslaw Biernacki 
3218c56df37SRadoslaw Biernacki 	clock_cfg = readq(clock->reg_base + PTP_CLOCK_CFG);
3228c56df37SRadoslaw Biernacki 	clock_cfg &= ~PTP_CLOCK_CFG_PTP_EN;
3238c56df37SRadoslaw Biernacki 	writeq(clock_cfg, clock->reg_base + PTP_CLOCK_CFG);
3248c56df37SRadoslaw Biernacki }
3258c56df37SRadoslaw Biernacki 
3268c56df37SRadoslaw Biernacki static const struct pci_device_id cavium_ptp_id_table[] = {
327aa3afcccSPrakash Brahmajyosyula 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_PTP,
328aa3afcccSPrakash Brahmajyosyula 			PCI_VENDOR_ID_CAVIUM, PCI_SUBSYS_DEVID_88XX_PTP) },
329aa3afcccSPrakash Brahmajyosyula 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_PTP,
330aa3afcccSPrakash Brahmajyosyula 			PCI_VENDOR_ID_CAVIUM, PCI_SUBSYS_DEVID_81XX_PTP) },
331aa3afcccSPrakash Brahmajyosyula 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_CAVIUM_PTP,
332aa3afcccSPrakash Brahmajyosyula 			PCI_VENDOR_ID_CAVIUM, PCI_SUBSYS_DEVID_83XX_PTP) },
3338c56df37SRadoslaw Biernacki 	{ 0, }
3348c56df37SRadoslaw Biernacki };
3358c56df37SRadoslaw Biernacki 
3368c56df37SRadoslaw Biernacki static struct pci_driver cavium_ptp_driver = {
3378c56df37SRadoslaw Biernacki 	.name = DRV_NAME,
3388c56df37SRadoslaw Biernacki 	.id_table = cavium_ptp_id_table,
3398c56df37SRadoslaw Biernacki 	.probe = cavium_ptp_probe,
3408c56df37SRadoslaw Biernacki 	.remove = cavium_ptp_remove,
3418c56df37SRadoslaw Biernacki };
3428c56df37SRadoslaw Biernacki 
34375498aa1SWei Yongjun module_pci_driver(cavium_ptp_driver);
3448c56df37SRadoslaw Biernacki 
3458c56df37SRadoslaw Biernacki MODULE_DESCRIPTION(DRV_NAME);
3468c56df37SRadoslaw Biernacki MODULE_AUTHOR("Cavium Networks <support@cavium.com>");
3478c56df37SRadoslaw Biernacki MODULE_LICENSE("GPL v2");
3488c56df37SRadoslaw Biernacki MODULE_DEVICE_TABLE(pci, cavium_ptp_id_table);
349