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