GNU Linux-libre 6.8.7-gnu
[releases.git] / drivers / net / ethernet / freescale / dpaa2 / dpaa2-ptp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2013-2016 Freescale Semiconductor Inc.
4  * Copyright 2016-2018 NXP
5  * Copyright 2020 NXP
6  */
7
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/fsl/mc.h>
12
13 #include "dpaa2-ptp.h"
14
15 static int dpaa2_ptp_enable(struct ptp_clock_info *ptp,
16                             struct ptp_clock_request *rq, int on)
17 {
18         struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
19         struct fsl_mc_device *mc_dev;
20         struct device *dev;
21         u32 mask = 0;
22         u32 bit;
23         int err;
24
25         dev = ptp_qoriq->dev;
26         mc_dev = to_fsl_mc_device(dev);
27
28         switch (rq->type) {
29         case PTP_CLK_REQ_EXTTS:
30                 switch (rq->extts.index) {
31                 case 0:
32                         bit = DPRTC_EVENT_ETS1;
33                         break;
34                 case 1:
35                         bit = DPRTC_EVENT_ETS2;
36                         break;
37                 default:
38                         return -EINVAL;
39                 }
40                 if (on)
41                         extts_clean_up(ptp_qoriq, rq->extts.index, false);
42                 break;
43         case PTP_CLK_REQ_PPS:
44                 bit = DPRTC_EVENT_PPS;
45                 break;
46         default:
47                 return -EOPNOTSUPP;
48         }
49
50         err = dprtc_get_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
51                                  DPRTC_IRQ_INDEX, &mask);
52         if (err < 0) {
53                 dev_err(dev, "dprtc_get_irq_mask(): %d\n", err);
54                 return err;
55         }
56
57         if (on)
58                 mask |= bit;
59         else
60                 mask &= ~bit;
61
62         err = dprtc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
63                                  DPRTC_IRQ_INDEX, mask);
64         if (err < 0) {
65                 dev_err(dev, "dprtc_set_irq_mask(): %d\n", err);
66                 return err;
67         }
68
69         return 0;
70 }
71
72 static const struct ptp_clock_info dpaa2_ptp_caps = {
73         .owner          = THIS_MODULE,
74         .name           = "DPAA2 PTP Clock",
75         .max_adj        = 512000,
76         .n_alarm        = 2,
77         .n_ext_ts       = 2,
78         .n_per_out      = 3,
79         .n_pins         = 0,
80         .pps            = 1,
81         .adjfine        = ptp_qoriq_adjfine,
82         .adjtime        = ptp_qoriq_adjtime,
83         .gettime64      = ptp_qoriq_gettime,
84         .settime64      = ptp_qoriq_settime,
85         .enable         = dpaa2_ptp_enable,
86 };
87
88 static irqreturn_t dpaa2_ptp_irq_handler_thread(int irq, void *priv)
89 {
90         struct ptp_qoriq *ptp_qoriq = priv;
91         struct ptp_clock_event event;
92         struct fsl_mc_device *mc_dev;
93         struct device *dev;
94         u32 status = 0;
95         int err;
96
97         dev = ptp_qoriq->dev;
98         mc_dev = to_fsl_mc_device(dev);
99
100         err = dprtc_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
101                                    DPRTC_IRQ_INDEX, &status);
102         if (unlikely(err)) {
103                 dev_err(dev, "dprtc_get_irq_status err %d\n", err);
104                 return IRQ_NONE;
105         }
106
107         if (status & DPRTC_EVENT_PPS) {
108                 event.type = PTP_CLOCK_PPS;
109                 ptp_clock_event(ptp_qoriq->clock, &event);
110         }
111
112         if (status & DPRTC_EVENT_ETS1)
113                 extts_clean_up(ptp_qoriq, 0, true);
114
115         if (status & DPRTC_EVENT_ETS2)
116                 extts_clean_up(ptp_qoriq, 1, true);
117
118         err = dprtc_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
119                                      DPRTC_IRQ_INDEX, status);
120         if (unlikely(err)) {
121                 dev_err(dev, "dprtc_clear_irq_status err %d\n", err);
122                 return IRQ_NONE;
123         }
124
125         return IRQ_HANDLED;
126 }
127
128 static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
129 {
130         struct device *dev = &mc_dev->dev;
131         struct ptp_qoriq *ptp_qoriq;
132         struct device_node *node;
133         void __iomem *base;
134         int err;
135
136         ptp_qoriq = devm_kzalloc(dev, sizeof(*ptp_qoriq), GFP_KERNEL);
137         if (!ptp_qoriq)
138                 return -ENOMEM;
139
140         err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
141         if (err) {
142                 if (err == -ENXIO)
143                         err = -EPROBE_DEFER;
144                 else
145                         dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
146                 goto err_exit;
147         }
148
149         err = dprtc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
150                          &mc_dev->mc_handle);
151         if (err) {
152                 dev_err(dev, "dprtc_open err %d\n", err);
153                 goto err_free_mcp;
154         }
155
156         ptp_qoriq->dev = dev;
157
158         node = of_find_compatible_node(NULL, NULL, "fsl,dpaa2-ptp");
159         if (!node) {
160                 err = -ENODEV;
161                 goto err_close;
162         }
163
164         dev->of_node = node;
165
166         base = of_iomap(node, 0);
167         if (!base) {
168                 err = -ENOMEM;
169                 goto err_put;
170         }
171
172         err = fsl_mc_allocate_irqs(mc_dev);
173         if (err) {
174                 dev_err(dev, "MC irqs allocation failed\n");
175                 goto err_unmap;
176         }
177
178         ptp_qoriq->irq = mc_dev->irqs[0]->virq;
179
180         err = request_threaded_irq(ptp_qoriq->irq, NULL,
181                                    dpaa2_ptp_irq_handler_thread,
182                                    IRQF_NO_SUSPEND | IRQF_ONESHOT,
183                                    dev_name(dev), ptp_qoriq);
184         if (err < 0) {
185                 dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
186                 goto err_free_mc_irq;
187         }
188
189         err = dprtc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
190                                    DPRTC_IRQ_INDEX, 1);
191         if (err < 0) {
192                 dev_err(dev, "dprtc_set_irq_enable(): %d\n", err);
193                 goto err_free_threaded_irq;
194         }
195
196         err = ptp_qoriq_init(ptp_qoriq, base, &dpaa2_ptp_caps);
197         if (err)
198                 goto err_free_threaded_irq;
199
200         dpaa2_phc_index = ptp_qoriq->phc_index;
201         dpaa2_ptp = ptp_qoriq;
202         dev_set_drvdata(dev, ptp_qoriq);
203
204         return 0;
205
206 err_free_threaded_irq:
207         free_irq(ptp_qoriq->irq, ptp_qoriq);
208 err_free_mc_irq:
209         fsl_mc_free_irqs(mc_dev);
210 err_unmap:
211         iounmap(base);
212 err_put:
213         of_node_put(node);
214 err_close:
215         dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
216 err_free_mcp:
217         fsl_mc_portal_free(mc_dev->mc_io);
218 err_exit:
219         return err;
220 }
221
222 static void dpaa2_ptp_remove(struct fsl_mc_device *mc_dev)
223 {
224         struct device *dev = &mc_dev->dev;
225         struct ptp_qoriq *ptp_qoriq;
226
227         ptp_qoriq = dev_get_drvdata(dev);
228
229         dpaa2_phc_index = -1;
230         ptp_qoriq_free(ptp_qoriq);
231
232         fsl_mc_free_irqs(mc_dev);
233         dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
234         fsl_mc_portal_free(mc_dev->mc_io);
235 }
236
237 static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = {
238         {
239                 .vendor = FSL_MC_VENDOR_FREESCALE,
240                 .obj_type = "dprtc",
241         },
242         {}
243 };
244 MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table);
245
246 static struct fsl_mc_driver dpaa2_ptp_drv = {
247         .driver = {
248                 .name = KBUILD_MODNAME,
249                 .owner = THIS_MODULE,
250         },
251         .probe = dpaa2_ptp_probe,
252         .remove = dpaa2_ptp_remove,
253         .match_id_table = dpaa2_ptp_match_id_table,
254 };
255
256 module_fsl_mc_driver(dpaa2_ptp_drv);
257
258 MODULE_LICENSE("GPL v2");
259 MODULE_DESCRIPTION("DPAA2 PTP Clock Driver");