162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
262306a36Sopenharmony_ci/* Copyright 2019 NXP */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/of.h>
662306a36Sopenharmony_ci#include <linux/fsl/ptp_qoriq.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "enetc.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciint enetc_phc_index = -1;
1162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(enetc_phc_index);
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic struct ptp_clock_info enetc_ptp_caps = {
1462306a36Sopenharmony_ci	.owner		= THIS_MODULE,
1562306a36Sopenharmony_ci	.name		= "ENETC PTP clock",
1662306a36Sopenharmony_ci	.max_adj	= 512000,
1762306a36Sopenharmony_ci	.n_alarm	= 0,
1862306a36Sopenharmony_ci	.n_ext_ts	= 2,
1962306a36Sopenharmony_ci	.n_per_out	= 0,
2062306a36Sopenharmony_ci	.n_pins		= 0,
2162306a36Sopenharmony_ci	.pps		= 1,
2262306a36Sopenharmony_ci	.adjfine	= ptp_qoriq_adjfine,
2362306a36Sopenharmony_ci	.adjtime	= ptp_qoriq_adjtime,
2462306a36Sopenharmony_ci	.gettime64	= ptp_qoriq_gettime,
2562306a36Sopenharmony_ci	.settime64	= ptp_qoriq_settime,
2662306a36Sopenharmony_ci	.enable		= ptp_qoriq_enable,
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int enetc_ptp_probe(struct pci_dev *pdev,
3062306a36Sopenharmony_ci			   const struct pci_device_id *ent)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct ptp_qoriq *ptp_qoriq;
3362306a36Sopenharmony_ci	void __iomem *base;
3462306a36Sopenharmony_ci	int err, len, n;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
3762306a36Sopenharmony_ci		dev_info(&pdev->dev, "device is disabled, skipping\n");
3862306a36Sopenharmony_ci		return -ENODEV;
3962306a36Sopenharmony_ci	}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	err = pci_enable_device_mem(pdev);
4262306a36Sopenharmony_ci	if (err)
4362306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, err, "device enable failed\n");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
4662306a36Sopenharmony_ci	if (err) {
4762306a36Sopenharmony_ci		dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err);
4862306a36Sopenharmony_ci		goto err_dma;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	err = pci_request_mem_regions(pdev, KBUILD_MODNAME);
5262306a36Sopenharmony_ci	if (err) {
5362306a36Sopenharmony_ci		dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err);
5462306a36Sopenharmony_ci		goto err_pci_mem_reg;
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	pci_set_master(pdev);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
6062306a36Sopenharmony_ci	if (!ptp_qoriq) {
6162306a36Sopenharmony_ci		err = -ENOMEM;
6262306a36Sopenharmony_ci		goto err_alloc_ptp;
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	len = pci_resource_len(pdev, ENETC_BAR_REGS);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	base = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len);
6862306a36Sopenharmony_ci	if (!base) {
6962306a36Sopenharmony_ci		err = -ENXIO;
7062306a36Sopenharmony_ci		dev_err(&pdev->dev, "ioremap() failed\n");
7162306a36Sopenharmony_ci		goto err_ioremap;
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Allocate 1 interrupt */
7562306a36Sopenharmony_ci	n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
7662306a36Sopenharmony_ci	if (n != 1) {
7762306a36Sopenharmony_ci		err = -EPERM;
7862306a36Sopenharmony_ci		goto err_irq_vectors;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	ptp_qoriq->irq = pci_irq_vector(pdev, 0);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	err = request_irq(ptp_qoriq->irq, ptp_qoriq_isr, 0, DRIVER, ptp_qoriq);
8462306a36Sopenharmony_ci	if (err) {
8562306a36Sopenharmony_ci		dev_err(&pdev->dev, "request_irq() failed!\n");
8662306a36Sopenharmony_ci		goto err_irq;
8762306a36Sopenharmony_ci	}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	ptp_qoriq->dev = &pdev->dev;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	err = ptp_qoriq_init(ptp_qoriq, base, &enetc_ptp_caps);
9262306a36Sopenharmony_ci	if (err)
9362306a36Sopenharmony_ci		goto err_no_clock;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	enetc_phc_index = ptp_qoriq->phc_index;
9662306a36Sopenharmony_ci	pci_set_drvdata(pdev, ptp_qoriq);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return 0;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cierr_no_clock:
10162306a36Sopenharmony_ci	free_irq(ptp_qoriq->irq, ptp_qoriq);
10262306a36Sopenharmony_cierr_irq:
10362306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
10462306a36Sopenharmony_cierr_irq_vectors:
10562306a36Sopenharmony_ci	iounmap(base);
10662306a36Sopenharmony_cierr_ioremap:
10762306a36Sopenharmony_ci	kfree(ptp_qoriq);
10862306a36Sopenharmony_cierr_alloc_ptp:
10962306a36Sopenharmony_ci	pci_release_mem_regions(pdev);
11062306a36Sopenharmony_cierr_pci_mem_reg:
11162306a36Sopenharmony_cierr_dma:
11262306a36Sopenharmony_ci	pci_disable_device(pdev);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return err;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void enetc_ptp_remove(struct pci_dev *pdev)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	enetc_phc_index = -1;
12262306a36Sopenharmony_ci	ptp_qoriq_free(ptp_qoriq);
12362306a36Sopenharmony_ci	pci_free_irq_vectors(pdev);
12462306a36Sopenharmony_ci	kfree(ptp_qoriq);
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	pci_release_mem_regions(pdev);
12762306a36Sopenharmony_ci	pci_disable_device(pdev);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const struct pci_device_id enetc_ptp_id_table[] = {
13162306a36Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PTP) },
13262306a36Sopenharmony_ci	{ 0, } /* End of table. */
13362306a36Sopenharmony_ci};
13462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, enetc_ptp_id_table);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic struct pci_driver enetc_ptp_driver = {
13762306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
13862306a36Sopenharmony_ci	.id_table = enetc_ptp_id_table,
13962306a36Sopenharmony_ci	.probe = enetc_ptp_probe,
14062306a36Sopenharmony_ci	.remove = enetc_ptp_remove,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_cimodule_pci_driver(enetc_ptp_driver);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ciMODULE_DESCRIPTION("ENETC PTP clock driver");
14562306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
146