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