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