1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright 2013-2016 Freescale Semiconductor Inc.
4 * Copyright 2016-2018 NXP
7 #include <linux/module.h>
8 #include <linux/slab.h>
9 #include <linux/ptp_clock_kernel.h>
10 #include <linux/fsl/mc.h>
14 struct ptp_dpaa2_priv {
15 struct fsl_mc_device *rtc_mc_dev;
16 struct ptp_clock *clock;
17 struct ptp_clock_info caps;
21 /* PTP clock operations */
22 static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
24 struct ptp_dpaa2_priv *ptp_dpaa2 =
25 container_of(ptp, struct ptp_dpaa2_priv, caps);
26 struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
27 struct device *dev = &mc_dev->dev;
38 tmr_add = ptp_dpaa2->freq_comp;
41 diff = div_u64(adj, 1000000000ULL);
43 tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
45 err = dprtc_set_freq_compensation(mc_dev->mc_io, 0,
46 mc_dev->mc_handle, tmr_add);
48 dev_err(dev, "dprtc_set_freq_compensation err %d\n", err);
52 static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta)
54 struct ptp_dpaa2_priv *ptp_dpaa2 =
55 container_of(ptp, struct ptp_dpaa2_priv, caps);
56 struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
57 struct device *dev = &mc_dev->dev;
61 err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now);
63 dev_err(dev, "dprtc_get_time err %d\n", err);
69 err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now);
71 dev_err(dev, "dprtc_set_time err %d\n", err);
77 static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
79 struct ptp_dpaa2_priv *ptp_dpaa2 =
80 container_of(ptp, struct ptp_dpaa2_priv, caps);
81 struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
82 struct device *dev = &mc_dev->dev;
87 err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns);
89 dev_err(dev, "dprtc_get_time err %d\n", err);
93 ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
94 ts->tv_nsec = remainder;
98 static int ptp_dpaa2_settime(struct ptp_clock_info *ptp,
99 const struct timespec64 *ts)
101 struct ptp_dpaa2_priv *ptp_dpaa2 =
102 container_of(ptp, struct ptp_dpaa2_priv, caps);
103 struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev;
104 struct device *dev = &mc_dev->dev;
108 ns = ts->tv_sec * 1000000000ULL;
111 err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns);
113 dev_err(dev, "dprtc_set_time err %d\n", err);
117 static struct ptp_clock_info ptp_dpaa2_caps = {
118 .owner = THIS_MODULE,
119 .name = "DPAA2 PTP Clock",
126 .adjfreq = ptp_dpaa2_adjfreq,
127 .adjtime = ptp_dpaa2_adjtime,
128 .gettime64 = ptp_dpaa2_gettime,
129 .settime64 = ptp_dpaa2_settime,
132 static int rtc_probe(struct fsl_mc_device *mc_dev)
134 struct device *dev = &mc_dev->dev;
135 struct ptp_dpaa2_priv *ptp_dpaa2;
139 ptp_dpaa2 = kzalloc(sizeof(*ptp_dpaa2), GFP_KERNEL);
143 err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
148 dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
152 err = dprtc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
155 dev_err(dev, "dprtc_open err %d\n", err);
159 ptp_dpaa2->rtc_mc_dev = mc_dev;
161 err = dprtc_get_freq_compensation(mc_dev->mc_io, 0,
162 mc_dev->mc_handle, &tmr_add);
164 dev_err(dev, "dprtc_get_freq_compensation err %d\n", err);
168 ptp_dpaa2->freq_comp = tmr_add;
169 ptp_dpaa2->caps = ptp_dpaa2_caps;
171 ptp_dpaa2->clock = ptp_clock_register(&ptp_dpaa2->caps, dev);
172 if (IS_ERR(ptp_dpaa2->clock)) {
173 err = PTR_ERR(ptp_dpaa2->clock);
177 dpaa2_phc_index = ptp_clock_index(ptp_dpaa2->clock);
179 dev_set_drvdata(dev, ptp_dpaa2);
184 dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
186 fsl_mc_portal_free(mc_dev->mc_io);
189 dev_set_drvdata(dev, NULL);
193 static int rtc_remove(struct fsl_mc_device *mc_dev)
195 struct ptp_dpaa2_priv *ptp_dpaa2;
196 struct device *dev = &mc_dev->dev;
198 ptp_dpaa2 = dev_get_drvdata(dev);
199 ptp_clock_unregister(ptp_dpaa2->clock);
201 dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
202 fsl_mc_portal_free(mc_dev->mc_io);
205 dev_set_drvdata(dev, NULL);
210 static const struct fsl_mc_device_id rtc_match_id_table[] = {
212 .vendor = FSL_MC_VENDOR_FREESCALE,
217 MODULE_DEVICE_TABLE(fslmc, rtc_match_id_table);
219 static struct fsl_mc_driver rtc_drv = {
221 .name = KBUILD_MODNAME,
222 .owner = THIS_MODULE,
225 .remove = rtc_remove,
226 .match_id_table = rtc_match_id_table,
229 module_fsl_mc_driver(rtc_drv);
231 MODULE_LICENSE("GPL v2");
232 MODULE_DESCRIPTION("DPAA2 PTP Clock Driver");