]> Git Repo - J-linux.git/blob - drivers/net/ethernet/renesas/rcar_gen4_ptp.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / ethernet / renesas / rcar_gen4_ptp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Renesas R-Car Gen4 gPTP device driver
3  *
4  * Copyright (C) 2022 Renesas Electronics Corporation
5  */
6
7 #include <linux/err.h>
8 #include <linux/etherdevice.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
13
14 #include "rcar_gen4_ptp.h"
15 #define ptp_to_priv(ptp)        container_of(ptp, struct rcar_gen4_ptp_private, info)
16
17 static const struct rcar_gen4_ptp_reg_offset gen4_offs = {
18         .enable = PTPTMEC,
19         .disable = PTPTMDC,
20         .increment = PTPTIVC0,
21         .config_t0 = PTPTOVC00,
22         .config_t1 = PTPTOVC10,
23         .config_t2 = PTPTOVC20,
24         .monitor_t0 = PTPGPTPTM00,
25         .monitor_t1 = PTPGPTPTM10,
26         .monitor_t2 = PTPGPTPTM20,
27 };
28
29 static int rcar_gen4_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
30 {
31         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
32         bool neg_adj = scaled_ppm < 0 ? true : false;
33         s64 addend = ptp_priv->default_addend;
34         s64 diff;
35
36         if (neg_adj)
37                 scaled_ppm = -scaled_ppm;
38         diff = div_s64(addend * scaled_ppm_to_ppb(scaled_ppm), NSEC_PER_SEC);
39         addend = neg_adj ? addend - diff : addend + diff;
40
41         iowrite32(addend, ptp_priv->addr + ptp_priv->offs->increment);
42
43         return 0;
44 }
45
46 /* Caller must hold the lock */
47 static void _rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
48                                    struct timespec64 *ts)
49 {
50         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
51
52         ts->tv_nsec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t0);
53         ts->tv_sec = ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t1) |
54                      ((s64)ioread32(ptp_priv->addr + ptp_priv->offs->monitor_t2) << 32);
55 }
56
57 static int rcar_gen4_ptp_gettime(struct ptp_clock_info *ptp,
58                                  struct timespec64 *ts)
59 {
60         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
61         unsigned long flags;
62
63         spin_lock_irqsave(&ptp_priv->lock, flags);
64         _rcar_gen4_ptp_gettime(ptp, ts);
65         spin_unlock_irqrestore(&ptp_priv->lock, flags);
66
67         return 0;
68 }
69
70 /* Caller must hold the lock */
71 static void _rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
72                                    const struct timespec64 *ts)
73 {
74         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
75
76         iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
77         iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t2);
78         iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t1);
79         iowrite32(0, ptp_priv->addr + ptp_priv->offs->config_t0);
80         iowrite32(1, ptp_priv->addr + ptp_priv->offs->enable);
81         iowrite32(ts->tv_sec >> 32, ptp_priv->addr + ptp_priv->offs->config_t2);
82         iowrite32(ts->tv_sec, ptp_priv->addr + ptp_priv->offs->config_t1);
83         iowrite32(ts->tv_nsec, ptp_priv->addr + ptp_priv->offs->config_t0);
84 }
85
86 static int rcar_gen4_ptp_settime(struct ptp_clock_info *ptp,
87                                  const struct timespec64 *ts)
88 {
89         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
90         unsigned long flags;
91
92         spin_lock_irqsave(&ptp_priv->lock, flags);
93         _rcar_gen4_ptp_settime(ptp, ts);
94         spin_unlock_irqrestore(&ptp_priv->lock, flags);
95
96         return 0;
97 }
98
99 static int rcar_gen4_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
100 {
101         struct rcar_gen4_ptp_private *ptp_priv = ptp_to_priv(ptp);
102         struct timespec64 ts;
103         unsigned long flags;
104         s64 now;
105
106         spin_lock_irqsave(&ptp_priv->lock, flags);
107         _rcar_gen4_ptp_gettime(ptp, &ts);
108         now = ktime_to_ns(timespec64_to_ktime(ts));
109         ts = ns_to_timespec64(now + delta);
110         _rcar_gen4_ptp_settime(ptp, &ts);
111         spin_unlock_irqrestore(&ptp_priv->lock, flags);
112
113         return 0;
114 }
115
116 static int rcar_gen4_ptp_enable(struct ptp_clock_info *ptp,
117                                 struct ptp_clock_request *rq, int on)
118 {
119         return -EOPNOTSUPP;
120 }
121
122 static struct ptp_clock_info rcar_gen4_ptp_info = {
123         .owner = THIS_MODULE,
124         .name = "rcar_gen4_ptp",
125         .max_adj = 50000000,
126         .adjfine = rcar_gen4_ptp_adjfine,
127         .adjtime = rcar_gen4_ptp_adjtime,
128         .gettime64 = rcar_gen4_ptp_gettime,
129         .settime64 = rcar_gen4_ptp_settime,
130         .enable = rcar_gen4_ptp_enable,
131 };
132
133 static int rcar_gen4_ptp_set_offs(struct rcar_gen4_ptp_private *ptp_priv,
134                                   enum rcar_gen4_ptp_reg_layout layout)
135 {
136         if (layout != RCAR_GEN4_PTP_REG_LAYOUT)
137                 return -EINVAL;
138
139         ptp_priv->offs = &gen4_offs;
140
141         return 0;
142 }
143
144 static s64 rcar_gen4_ptp_rate_to_increment(u32 rate)
145 {
146         /* Timer increment in ns.
147          * bit[31:27] - integer
148          * bit[26:0]  - decimal
149          * increment[ns] = perid[ns] * 2^27 => (1ns * 2^27) / rate[hz]
150          */
151         return div_s64(1000000000LL << 27, rate);
152 }
153
154 int rcar_gen4_ptp_register(struct rcar_gen4_ptp_private *ptp_priv,
155                            enum rcar_gen4_ptp_reg_layout layout, u32 rate)
156 {
157         int ret;
158
159         if (ptp_priv->initialized)
160                 return 0;
161
162         spin_lock_init(&ptp_priv->lock);
163
164         ret = rcar_gen4_ptp_set_offs(ptp_priv, layout);
165         if (ret)
166                 return ret;
167
168         ptp_priv->default_addend = rcar_gen4_ptp_rate_to_increment(rate);
169         iowrite32(ptp_priv->default_addend, ptp_priv->addr + ptp_priv->offs->increment);
170         ptp_priv->clock = ptp_clock_register(&ptp_priv->info, NULL);
171         if (IS_ERR(ptp_priv->clock))
172                 return PTR_ERR(ptp_priv->clock);
173
174         iowrite32(0x01, ptp_priv->addr + ptp_priv->offs->enable);
175         ptp_priv->initialized = true;
176
177         return 0;
178 }
179 EXPORT_SYMBOL_GPL(rcar_gen4_ptp_register);
180
181 int rcar_gen4_ptp_unregister(struct rcar_gen4_ptp_private *ptp_priv)
182 {
183         iowrite32(1, ptp_priv->addr + ptp_priv->offs->disable);
184
185         return ptp_clock_unregister(ptp_priv->clock);
186 }
187 EXPORT_SYMBOL_GPL(rcar_gen4_ptp_unregister);
188
189 struct rcar_gen4_ptp_private *rcar_gen4_ptp_alloc(struct platform_device *pdev)
190 {
191         struct rcar_gen4_ptp_private *ptp;
192
193         ptp = devm_kzalloc(&pdev->dev, sizeof(*ptp), GFP_KERNEL);
194         if (!ptp)
195                 return NULL;
196
197         ptp->info = rcar_gen4_ptp_info;
198
199         return ptp;
200 }
201 EXPORT_SYMBOL_GPL(rcar_gen4_ptp_alloc);
202
203 MODULE_AUTHOR("Yoshihiro Shimoda");
204 MODULE_DESCRIPTION("Renesas R-Car Gen4 gPTP driver");
205 MODULE_LICENSE("GPL");
This page took 0.036066 seconds and 4 git commands to generate.