1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
2 | /* Copyright 2019 NXP */ |
3 | |
4 | #include <linux/module.h> |
5 | #include <linux/of.h> |
6 | #include <linux/fsl/ptp_qoriq.h> |
7 | |
8 | #include "enetc.h" |
9 | |
10 | int enetc_phc_index = -1; |
11 | EXPORT_SYMBOL_GPL(enetc_phc_index); |
12 | |
13 | static struct ptp_clock_info enetc_ptp_caps = { |
14 | .owner = THIS_MODULE, |
15 | .name = "ENETC PTP clock" , |
16 | .max_adj = 512000, |
17 | .n_alarm = 0, |
18 | .n_ext_ts = 2, |
19 | .n_per_out = 0, |
20 | .n_pins = 0, |
21 | .pps = 1, |
22 | .adjfine = ptp_qoriq_adjfine, |
23 | .adjtime = ptp_qoriq_adjtime, |
24 | .gettime64 = ptp_qoriq_gettime, |
25 | .settime64 = ptp_qoriq_settime, |
26 | .enable = ptp_qoriq_enable, |
27 | }; |
28 | |
29 | static int enetc_ptp_probe(struct pci_dev *pdev, |
30 | const struct pci_device_id *ent) |
31 | { |
32 | struct ptp_qoriq *ptp_qoriq; |
33 | void __iomem *base; |
34 | int err, len, n; |
35 | |
36 | if (pdev->dev.of_node && !of_device_is_available(device: pdev->dev.of_node)) { |
37 | dev_info(&pdev->dev, "device is disabled, skipping\n" ); |
38 | return -ENODEV; |
39 | } |
40 | |
41 | err = pci_enable_device_mem(dev: pdev); |
42 | if (err) |
43 | return dev_err_probe(dev: &pdev->dev, err, fmt: "device enable failed\n" ); |
44 | |
45 | err = dma_set_mask_and_coherent(dev: &pdev->dev, DMA_BIT_MASK(64)); |
46 | if (err) { |
47 | dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n" , err); |
48 | goto err_dma; |
49 | } |
50 | |
51 | err = pci_request_mem_regions(pdev, KBUILD_MODNAME); |
52 | if (err) { |
53 | dev_err(&pdev->dev, "pci_request_regions failed err=%d\n" , err); |
54 | goto err_pci_mem_reg; |
55 | } |
56 | |
57 | pci_set_master(dev: pdev); |
58 | |
59 | ptp_qoriq = kzalloc(size: sizeof(*ptp_qoriq), GFP_KERNEL); |
60 | if (!ptp_qoriq) { |
61 | err = -ENOMEM; |
62 | goto err_alloc_ptp; |
63 | } |
64 | |
65 | len = pci_resource_len(pdev, ENETC_BAR_REGS); |
66 | |
67 | base = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), size: len); |
68 | if (!base) { |
69 | err = -ENXIO; |
70 | dev_err(&pdev->dev, "ioremap() failed\n" ); |
71 | goto err_ioremap; |
72 | } |
73 | |
74 | /* Allocate 1 interrupt */ |
75 | n = pci_alloc_irq_vectors(dev: pdev, min_vecs: 1, max_vecs: 1, PCI_IRQ_MSIX); |
76 | if (n != 1) { |
77 | err = -EPERM; |
78 | goto err_irq_vectors; |
79 | } |
80 | |
81 | ptp_qoriq->irq = pci_irq_vector(dev: pdev, nr: 0); |
82 | |
83 | err = request_irq(irq: ptp_qoriq->irq, handler: ptp_qoriq_isr, flags: 0, DRIVER, dev: ptp_qoriq); |
84 | if (err) { |
85 | dev_err(&pdev->dev, "request_irq() failed!\n" ); |
86 | goto err_irq; |
87 | } |
88 | |
89 | ptp_qoriq->dev = &pdev->dev; |
90 | |
91 | err = ptp_qoriq_init(ptp_qoriq, base, caps: &enetc_ptp_caps); |
92 | if (err) |
93 | goto err_no_clock; |
94 | |
95 | enetc_phc_index = ptp_qoriq->phc_index; |
96 | pci_set_drvdata(pdev, data: ptp_qoriq); |
97 | |
98 | return 0; |
99 | |
100 | err_no_clock: |
101 | free_irq(ptp_qoriq->irq, ptp_qoriq); |
102 | err_irq: |
103 | pci_free_irq_vectors(dev: pdev); |
104 | err_irq_vectors: |
105 | iounmap(addr: base); |
106 | err_ioremap: |
107 | kfree(objp: ptp_qoriq); |
108 | err_alloc_ptp: |
109 | pci_release_mem_regions(pdev); |
110 | err_pci_mem_reg: |
111 | err_dma: |
112 | pci_disable_device(dev: pdev); |
113 | |
114 | return err; |
115 | } |
116 | |
117 | static void enetc_ptp_remove(struct pci_dev *pdev) |
118 | { |
119 | struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev); |
120 | |
121 | enetc_phc_index = -1; |
122 | ptp_qoriq_free(ptp_qoriq); |
123 | pci_free_irq_vectors(dev: pdev); |
124 | kfree(objp: ptp_qoriq); |
125 | |
126 | pci_release_mem_regions(pdev); |
127 | pci_disable_device(dev: pdev); |
128 | } |
129 | |
130 | static const struct pci_device_id enetc_ptp_id_table[] = { |
131 | { PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PTP) }, |
132 | { 0, } /* End of table. */ |
133 | }; |
134 | MODULE_DEVICE_TABLE(pci, enetc_ptp_id_table); |
135 | |
136 | static struct pci_driver enetc_ptp_driver = { |
137 | .name = KBUILD_MODNAME, |
138 | .id_table = enetc_ptp_id_table, |
139 | .probe = enetc_ptp_probe, |
140 | .remove = enetc_ptp_remove, |
141 | }; |
142 | module_pci_driver(enetc_ptp_driver); |
143 | |
144 | MODULE_DESCRIPTION("ENETC PTP clock driver" ); |
145 | MODULE_LICENSE("Dual BSD/GPL" ); |
146 | |