0001
0002
0003
0004
0005
0006
0007 #include <linux/device.h>
0008 #include <linux/module.h>
0009 #include <linux/mod_devicetable.h>
0010 #include <linux/err.h>
0011 #include <linux/init.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/io.h>
0014 #include <linux/irq.h>
0015 #include <linux/kernel.h>
0016 #include <linux/ptp_clock_kernel.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/soc/ixp4xx/cpu.h>
0019
0020 #include "ixp46x_ts.h"
0021
0022 #define DRIVER "ptp_ixp46x"
0023 #define N_EXT_TS 2
0024
0025 struct ixp_clock {
0026 struct ixp46x_ts_regs *regs;
0027 struct ptp_clock *ptp_clock;
0028 struct ptp_clock_info caps;
0029 int exts0_enabled;
0030 int exts1_enabled;
0031 int slave_irq;
0032 int master_irq;
0033 };
0034
0035 static DEFINE_SPINLOCK(register_lock);
0036
0037
0038
0039
0040
0041 static u64 ixp_systime_read(struct ixp46x_ts_regs *regs)
0042 {
0043 u64 ns;
0044 u32 lo, hi;
0045
0046 lo = __raw_readl(®s->systime_lo);
0047 hi = __raw_readl(®s->systime_hi);
0048
0049 ns = ((u64) hi) << 32;
0050 ns |= lo;
0051 ns <<= TICKS_NS_SHIFT;
0052
0053 return ns;
0054 }
0055
0056 static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns)
0057 {
0058 u32 hi, lo;
0059
0060 ns >>= TICKS_NS_SHIFT;
0061 hi = ns >> 32;
0062 lo = ns & 0xffffffff;
0063
0064 __raw_writel(lo, ®s->systime_lo);
0065 __raw_writel(hi, ®s->systime_hi);
0066 }
0067
0068
0069
0070
0071
0072 static irqreturn_t isr(int irq, void *priv)
0073 {
0074 struct ixp_clock *ixp_clock = priv;
0075 struct ixp46x_ts_regs *regs = ixp_clock->regs;
0076 struct ptp_clock_event event;
0077 u32 ack = 0, lo, hi, val;
0078
0079 val = __raw_readl(®s->event);
0080
0081 if (val & TSER_SNS) {
0082 ack |= TSER_SNS;
0083 if (ixp_clock->exts0_enabled) {
0084 hi = __raw_readl(®s->asms_hi);
0085 lo = __raw_readl(®s->asms_lo);
0086 event.type = PTP_CLOCK_EXTTS;
0087 event.index = 0;
0088 event.timestamp = ((u64) hi) << 32;
0089 event.timestamp |= lo;
0090 event.timestamp <<= TICKS_NS_SHIFT;
0091 ptp_clock_event(ixp_clock->ptp_clock, &event);
0092 }
0093 }
0094
0095 if (val & TSER_SNM) {
0096 ack |= TSER_SNM;
0097 if (ixp_clock->exts1_enabled) {
0098 hi = __raw_readl(®s->amms_hi);
0099 lo = __raw_readl(®s->amms_lo);
0100 event.type = PTP_CLOCK_EXTTS;
0101 event.index = 1;
0102 event.timestamp = ((u64) hi) << 32;
0103 event.timestamp |= lo;
0104 event.timestamp <<= TICKS_NS_SHIFT;
0105 ptp_clock_event(ixp_clock->ptp_clock, &event);
0106 }
0107 }
0108
0109 if (val & TTIPEND)
0110 ack |= TTIPEND;
0111
0112 if (ack) {
0113 __raw_writel(ack, ®s->event);
0114 return IRQ_HANDLED;
0115 } else
0116 return IRQ_NONE;
0117 }
0118
0119
0120
0121
0122
0123 static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
0124 {
0125 u64 adj;
0126 u32 diff, addend;
0127 int neg_adj = 0;
0128 struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
0129 struct ixp46x_ts_regs *regs = ixp_clock->regs;
0130
0131 if (ppb < 0) {
0132 neg_adj = 1;
0133 ppb = -ppb;
0134 }
0135 addend = DEFAULT_ADDEND;
0136 adj = addend;
0137 adj *= ppb;
0138 diff = div_u64(adj, 1000000000ULL);
0139
0140 addend = neg_adj ? addend - diff : addend + diff;
0141
0142 __raw_writel(addend, ®s->addend);
0143
0144 return 0;
0145 }
0146
0147 static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta)
0148 {
0149 s64 now;
0150 unsigned long flags;
0151 struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
0152 struct ixp46x_ts_regs *regs = ixp_clock->regs;
0153
0154 spin_lock_irqsave(®ister_lock, flags);
0155
0156 now = ixp_systime_read(regs);
0157 now += delta;
0158 ixp_systime_write(regs, now);
0159
0160 spin_unlock_irqrestore(®ister_lock, flags);
0161
0162 return 0;
0163 }
0164
0165 static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts)
0166 {
0167 u64 ns;
0168 unsigned long flags;
0169 struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
0170 struct ixp46x_ts_regs *regs = ixp_clock->regs;
0171
0172 spin_lock_irqsave(®ister_lock, flags);
0173
0174 ns = ixp_systime_read(regs);
0175
0176 spin_unlock_irqrestore(®ister_lock, flags);
0177
0178 *ts = ns_to_timespec64(ns);
0179 return 0;
0180 }
0181
0182 static int ptp_ixp_settime(struct ptp_clock_info *ptp,
0183 const struct timespec64 *ts)
0184 {
0185 u64 ns;
0186 unsigned long flags;
0187 struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
0188 struct ixp46x_ts_regs *regs = ixp_clock->regs;
0189
0190 ns = timespec64_to_ns(ts);
0191
0192 spin_lock_irqsave(®ister_lock, flags);
0193
0194 ixp_systime_write(regs, ns);
0195
0196 spin_unlock_irqrestore(®ister_lock, flags);
0197
0198 return 0;
0199 }
0200
0201 static int ptp_ixp_enable(struct ptp_clock_info *ptp,
0202 struct ptp_clock_request *rq, int on)
0203 {
0204 struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
0205
0206 switch (rq->type) {
0207 case PTP_CLK_REQ_EXTTS:
0208 switch (rq->extts.index) {
0209 case 0:
0210 ixp_clock->exts0_enabled = on ? 1 : 0;
0211 break;
0212 case 1:
0213 ixp_clock->exts1_enabled = on ? 1 : 0;
0214 break;
0215 default:
0216 return -EINVAL;
0217 }
0218 return 0;
0219 default:
0220 break;
0221 }
0222
0223 return -EOPNOTSUPP;
0224 }
0225
0226 static const struct ptp_clock_info ptp_ixp_caps = {
0227 .owner = THIS_MODULE,
0228 .name = "IXP46X timer",
0229 .max_adj = 66666655,
0230 .n_ext_ts = N_EXT_TS,
0231 .n_pins = 0,
0232 .pps = 0,
0233 .adjfreq = ptp_ixp_adjfreq,
0234 .adjtime = ptp_ixp_adjtime,
0235 .gettime64 = ptp_ixp_gettime,
0236 .settime64 = ptp_ixp_settime,
0237 .enable = ptp_ixp_enable,
0238 };
0239
0240
0241
0242 static struct ixp_clock ixp_clock;
0243
0244 int ixp46x_ptp_find(struct ixp46x_ts_regs *__iomem *regs, int *phc_index)
0245 {
0246 *regs = ixp_clock.regs;
0247 *phc_index = ptp_clock_index(ixp_clock.ptp_clock);
0248
0249 if (!ixp_clock.ptp_clock)
0250 return -EPROBE_DEFER;
0251
0252 return 0;
0253 }
0254 EXPORT_SYMBOL_GPL(ixp46x_ptp_find);
0255
0256
0257 static void ptp_ixp_unregister_action(void *d)
0258 {
0259 struct ptp_clock *ptp_clock = d;
0260
0261 ptp_clock_unregister(ptp_clock);
0262 ixp_clock.ptp_clock = NULL;
0263 }
0264
0265 static int ptp_ixp_probe(struct platform_device *pdev)
0266 {
0267 struct device *dev = &pdev->dev;
0268 int ret;
0269
0270 ixp_clock.regs = devm_platform_ioremap_resource(pdev, 0);
0271 ixp_clock.master_irq = platform_get_irq(pdev, 0);
0272 ixp_clock.slave_irq = platform_get_irq(pdev, 1);
0273 if (IS_ERR(ixp_clock.regs) ||
0274 ixp_clock.master_irq < 0 || ixp_clock.slave_irq < 0)
0275 return -ENXIO;
0276
0277 ixp_clock.caps = ptp_ixp_caps;
0278
0279 ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps, NULL);
0280
0281 if (IS_ERR(ixp_clock.ptp_clock))
0282 return PTR_ERR(ixp_clock.ptp_clock);
0283
0284 ret = devm_add_action_or_reset(dev, ptp_ixp_unregister_action,
0285 ixp_clock.ptp_clock);
0286 if (ret) {
0287 dev_err(dev, "failed to install clock removal handler\n");
0288 return ret;
0289 }
0290
0291 __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend);
0292 __raw_writel(1, &ixp_clock.regs->trgt_lo);
0293 __raw_writel(0, &ixp_clock.regs->trgt_hi);
0294 __raw_writel(TTIPEND, &ixp_clock.regs->event);
0295
0296 ret = devm_request_irq(dev, ixp_clock.master_irq, isr,
0297 0, DRIVER, &ixp_clock);
0298 if (ret)
0299 return dev_err_probe(dev, ret,
0300 "request_irq failed for irq %d\n",
0301 ixp_clock.master_irq);
0302
0303 ret = devm_request_irq(dev, ixp_clock.slave_irq, isr,
0304 0, DRIVER, &ixp_clock);
0305 if (ret)
0306 return dev_err_probe(dev, ret,
0307 "request_irq failed for irq %d\n",
0308 ixp_clock.slave_irq);
0309
0310 return 0;
0311 }
0312
0313 static const struct of_device_id ptp_ixp_match[] = {
0314 {
0315 .compatible = "intel,ixp46x-ptp-timer",
0316 },
0317 { },
0318 };
0319
0320 static struct platform_driver ptp_ixp_driver = {
0321 .driver = {
0322 .name = "ptp-ixp46x",
0323 .of_match_table = ptp_ixp_match,
0324 .suppress_bind_attrs = true,
0325 },
0326 .probe = ptp_ixp_probe,
0327 };
0328 module_platform_driver(ptp_ixp_driver);
0329
0330 MODULE_AUTHOR("Richard Cochran <richardcochran@gmail.com>");
0331 MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
0332 MODULE_LICENSE("GPL");