18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/* Copyright 2019 NXP */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/module.h>
58c2ecf20Sopenharmony_ci#include <linux/of.h>
68c2ecf20Sopenharmony_ci#include <linux/fsl/ptp_qoriq.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "enetc.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciint enetc_phc_index = -1;
118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(enetc_phc_index);
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic struct ptp_clock_info enetc_ptp_caps = {
148c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
158c2ecf20Sopenharmony_ci	.name		= "ENETC PTP clock",
168c2ecf20Sopenharmony_ci	.max_adj	= 512000,
178c2ecf20Sopenharmony_ci	.n_alarm	= 0,
188c2ecf20Sopenharmony_ci	.n_ext_ts	= 2,
198c2ecf20Sopenharmony_ci	.n_per_out	= 0,
208c2ecf20Sopenharmony_ci	.n_pins		= 0,
218c2ecf20Sopenharmony_ci	.pps		= 1,
228c2ecf20Sopenharmony_ci	.adjfine	= ptp_qoriq_adjfine,
238c2ecf20Sopenharmony_ci	.adjtime	= ptp_qoriq_adjtime,
248c2ecf20Sopenharmony_ci	.gettime64	= ptp_qoriq_gettime,
258c2ecf20Sopenharmony_ci	.settime64	= ptp_qoriq_settime,
268c2ecf20Sopenharmony_ci	.enable		= ptp_qoriq_enable,
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int enetc_ptp_probe(struct pci_dev *pdev,
308c2ecf20Sopenharmony_ci			   const struct pci_device_id *ent)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	struct ptp_qoriq *ptp_qoriq;
338c2ecf20Sopenharmony_ci	void __iomem *base;
348c2ecf20Sopenharmony_ci	int err, len, n;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
378c2ecf20Sopenharmony_ci		dev_info(&pdev->dev, "device is disabled, skipping\n");
388c2ecf20Sopenharmony_ci		return -ENODEV;
398c2ecf20Sopenharmony_ci	}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	err = pci_enable_device_mem(pdev);
428c2ecf20Sopenharmony_ci	if (err) {
438c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "device enable failed\n");
448c2ecf20Sopenharmony_ci		return err;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* set up for high or low dma */
488c2ecf20Sopenharmony_ci	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
498c2ecf20Sopenharmony_ci	if (err) {
508c2ecf20Sopenharmony_ci		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
518c2ecf20Sopenharmony_ci		if (err) {
528c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
538c2ecf20Sopenharmony_ci				"DMA configuration failed: 0x%x\n", err);
548c2ecf20Sopenharmony_ci			goto err_dma;
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	err = pci_request_mem_regions(pdev, KBUILD_MODNAME);
598c2ecf20Sopenharmony_ci	if (err) {
608c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err);
618c2ecf20Sopenharmony_ci		goto err_pci_mem_reg;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	pci_set_master(pdev);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
678c2ecf20Sopenharmony_ci	if (!ptp_qoriq) {
688c2ecf20Sopenharmony_ci		err = -ENOMEM;
698c2ecf20Sopenharmony_ci		goto err_alloc_ptp;
708c2ecf20Sopenharmony_ci	}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	len = pci_resource_len(pdev, ENETC_BAR_REGS);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	base = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len);
758c2ecf20Sopenharmony_ci	if (!base) {
768c2ecf20Sopenharmony_ci		err = -ENXIO;
778c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "ioremap() failed\n");
788c2ecf20Sopenharmony_ci		goto err_ioremap;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	/* Allocate 1 interrupt */
828c2ecf20Sopenharmony_ci	n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
838c2ecf20Sopenharmony_ci	if (n != 1) {
848c2ecf20Sopenharmony_ci		err = -EPERM;
858c2ecf20Sopenharmony_ci		goto err_irq_vectors;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	ptp_qoriq->irq = pci_irq_vector(pdev, 0);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	err = request_irq(ptp_qoriq->irq, ptp_qoriq_isr, 0, DRIVER, ptp_qoriq);
918c2ecf20Sopenharmony_ci	if (err) {
928c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "request_irq() failed!\n");
938c2ecf20Sopenharmony_ci		goto err_irq;
948c2ecf20Sopenharmony_ci	}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	ptp_qoriq->dev = &pdev->dev;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	err = ptp_qoriq_init(ptp_qoriq, base, &enetc_ptp_caps);
998c2ecf20Sopenharmony_ci	if (err)
1008c2ecf20Sopenharmony_ci		goto err_no_clock;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	enetc_phc_index = ptp_qoriq->phc_index;
1038c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, ptp_qoriq);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cierr_no_clock:
1088c2ecf20Sopenharmony_ci	free_irq(ptp_qoriq->irq, ptp_qoriq);
1098c2ecf20Sopenharmony_cierr_irq:
1108c2ecf20Sopenharmony_ci	pci_free_irq_vectors(pdev);
1118c2ecf20Sopenharmony_cierr_irq_vectors:
1128c2ecf20Sopenharmony_ci	iounmap(base);
1138c2ecf20Sopenharmony_cierr_ioremap:
1148c2ecf20Sopenharmony_ci	kfree(ptp_qoriq);
1158c2ecf20Sopenharmony_cierr_alloc_ptp:
1168c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
1178c2ecf20Sopenharmony_cierr_pci_mem_reg:
1188c2ecf20Sopenharmony_cierr_dma:
1198c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	return err;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic void enetc_ptp_remove(struct pci_dev *pdev)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	enetc_phc_index = -1;
1298c2ecf20Sopenharmony_ci	ptp_qoriq_free(ptp_qoriq);
1308c2ecf20Sopenharmony_ci	pci_free_irq_vectors(pdev);
1318c2ecf20Sopenharmony_ci	kfree(ptp_qoriq);
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	pci_release_mem_regions(pdev);
1348c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic const struct pci_device_id enetc_ptp_id_table[] = {
1388c2ecf20Sopenharmony_ci	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PTP) },
1398c2ecf20Sopenharmony_ci	{ 0, } /* End of table. */
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, enetc_ptp_id_table);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct pci_driver enetc_ptp_driver = {
1448c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
1458c2ecf20Sopenharmony_ci	.id_table = enetc_ptp_id_table,
1468c2ecf20Sopenharmony_ci	.probe = enetc_ptp_probe,
1478c2ecf20Sopenharmony_ci	.remove = enetc_ptp_remove,
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_cimodule_pci_driver(enetc_ptp_driver);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ENETC PTP clock driver");
1528c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
153