Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PTP 1588 clock using the IXP46X
0004  *
0005  * Copyright (C) 2010 OMICRON electronics GmbH
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  * Register access functions
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(&regs->systime_lo);
0047     hi = __raw_readl(&regs->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, &regs->systime_lo);
0065     __raw_writel(hi, &regs->systime_hi);
0066 }
0067 
0068 /*
0069  * Interrupt service routine
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(&regs->event);
0080 
0081     if (val & TSER_SNS) {
0082         ack |= TSER_SNS;
0083         if (ixp_clock->exts0_enabled) {
0084             hi = __raw_readl(&regs->asms_hi);
0085             lo = __raw_readl(&regs->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(&regs->amms_hi);
0099             lo = __raw_readl(&regs->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; /* this bit seems to be always set */
0111 
0112     if (ack) {
0113         __raw_writel(ack, &regs->event);
0114         return IRQ_HANDLED;
0115     } else
0116         return IRQ_NONE;
0117 }
0118 
0119 /*
0120  * PTP clock operations
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, &regs->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(&register_lock, flags);
0155 
0156     now = ixp_systime_read(regs);
0157     now += delta;
0158     ixp_systime_write(regs, now);
0159 
0160     spin_unlock_irqrestore(&register_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(&register_lock, flags);
0173 
0174     ns = ixp_systime_read(regs);
0175 
0176     spin_unlock_irqrestore(&register_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(&register_lock, flags);
0193 
0194     ixp_systime_write(regs, ns);
0195 
0196     spin_unlock_irqrestore(&register_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 /* module operations */
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 /* Called from the registered devm action */
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");