123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2013-2016 Freescale Semiconductor Inc.
- * Copyright 2016-2018 NXP
- * Copyright 2020 NXP
- */
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/msi.h>
- #include <linux/fsl/mc.h>
- #include "dpaa2-ptp.h"
- static int dpaa2_ptp_enable(struct ptp_clock_info *ptp,
- struct ptp_clock_request *rq, int on)
- {
- struct ptp_qoriq *ptp_qoriq = container_of(ptp, struct ptp_qoriq, caps);
- struct fsl_mc_device *mc_dev;
- struct device *dev;
- u32 mask = 0;
- u32 bit;
- int err;
- dev = ptp_qoriq->dev;
- mc_dev = to_fsl_mc_device(dev);
- switch (rq->type) {
- case PTP_CLK_REQ_EXTTS:
- switch (rq->extts.index) {
- case 0:
- bit = DPRTC_EVENT_ETS1;
- break;
- case 1:
- bit = DPRTC_EVENT_ETS2;
- break;
- default:
- return -EINVAL;
- }
- if (on)
- extts_clean_up(ptp_qoriq, rq->extts.index, false);
- break;
- case PTP_CLK_REQ_PPS:
- bit = DPRTC_EVENT_PPS;
- break;
- default:
- return -EOPNOTSUPP;
- }
- err = dprtc_get_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
- DPRTC_IRQ_INDEX, &mask);
- if (err < 0) {
- dev_err(dev, "dprtc_get_irq_mask(): %d\n", err);
- return err;
- }
- if (on)
- mask |= bit;
- else
- mask &= ~bit;
- err = dprtc_set_irq_mask(mc_dev->mc_io, 0, mc_dev->mc_handle,
- DPRTC_IRQ_INDEX, mask);
- if (err < 0) {
- dev_err(dev, "dprtc_set_irq_mask(): %d\n", err);
- return err;
- }
- return 0;
- }
- static const struct ptp_clock_info dpaa2_ptp_caps = {
- .owner = THIS_MODULE,
- .name = "DPAA2 PTP Clock",
- .max_adj = 512000,
- .n_alarm = 2,
- .n_ext_ts = 2,
- .n_per_out = 3,
- .n_pins = 0,
- .pps = 1,
- .adjfine = ptp_qoriq_adjfine,
- .adjtime = ptp_qoriq_adjtime,
- .gettime64 = ptp_qoriq_gettime,
- .settime64 = ptp_qoriq_settime,
- .enable = dpaa2_ptp_enable,
- };
- static irqreturn_t dpaa2_ptp_irq_handler_thread(int irq, void *priv)
- {
- struct ptp_qoriq *ptp_qoriq = priv;
- struct ptp_clock_event event;
- struct fsl_mc_device *mc_dev;
- struct device *dev;
- u32 status = 0;
- int err;
- dev = ptp_qoriq->dev;
- mc_dev = to_fsl_mc_device(dev);
- err = dprtc_get_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
- DPRTC_IRQ_INDEX, &status);
- if (unlikely(err)) {
- dev_err(dev, "dprtc_get_irq_status err %d\n", err);
- return IRQ_NONE;
- }
- if (status & DPRTC_EVENT_PPS) {
- event.type = PTP_CLOCK_PPS;
- ptp_clock_event(ptp_qoriq->clock, &event);
- }
- if (status & DPRTC_EVENT_ETS1)
- extts_clean_up(ptp_qoriq, 0, true);
- if (status & DPRTC_EVENT_ETS2)
- extts_clean_up(ptp_qoriq, 1, true);
- err = dprtc_clear_irq_status(mc_dev->mc_io, 0, mc_dev->mc_handle,
- DPRTC_IRQ_INDEX, status);
- if (unlikely(err)) {
- dev_err(dev, "dprtc_clear_irq_status err %d\n", err);
- return IRQ_NONE;
- }
- return IRQ_HANDLED;
- }
- static int dpaa2_ptp_probe(struct fsl_mc_device *mc_dev)
- {
- struct device *dev = &mc_dev->dev;
- struct ptp_qoriq *ptp_qoriq;
- struct device_node *node;
- void __iomem *base;
- int err;
- ptp_qoriq = devm_kzalloc(dev, sizeof(*ptp_qoriq), GFP_KERNEL);
- if (!ptp_qoriq)
- return -ENOMEM;
- err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io);
- if (err) {
- if (err == -ENXIO)
- err = -EPROBE_DEFER;
- else
- dev_err(dev, "fsl_mc_portal_allocate err %d\n", err);
- goto err_exit;
- }
- err = dprtc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
- &mc_dev->mc_handle);
- if (err) {
- dev_err(dev, "dprtc_open err %d\n", err);
- goto err_free_mcp;
- }
- ptp_qoriq->dev = dev;
- node = of_find_compatible_node(NULL, NULL, "fsl,dpaa2-ptp");
- if (!node) {
- err = -ENODEV;
- goto err_close;
- }
- dev->of_node = node;
- base = of_iomap(node, 0);
- if (!base) {
- err = -ENOMEM;
- goto err_put;
- }
- err = fsl_mc_allocate_irqs(mc_dev);
- if (err) {
- dev_err(dev, "MC irqs allocation failed\n");
- goto err_unmap;
- }
- ptp_qoriq->irq = mc_dev->irqs[0]->virq;
- err = request_threaded_irq(ptp_qoriq->irq, NULL,
- dpaa2_ptp_irq_handler_thread,
- IRQF_NO_SUSPEND | IRQF_ONESHOT,
- dev_name(dev), ptp_qoriq);
- if (err < 0) {
- dev_err(dev, "devm_request_threaded_irq(): %d\n", err);
- goto err_free_mc_irq;
- }
- err = dprtc_set_irq_enable(mc_dev->mc_io, 0, mc_dev->mc_handle,
- DPRTC_IRQ_INDEX, 1);
- if (err < 0) {
- dev_err(dev, "dprtc_set_irq_enable(): %d\n", err);
- goto err_free_threaded_irq;
- }
- err = ptp_qoriq_init(ptp_qoriq, base, &dpaa2_ptp_caps);
- if (err)
- goto err_free_threaded_irq;
- dpaa2_phc_index = ptp_qoriq->phc_index;
- dpaa2_ptp = ptp_qoriq;
- dev_set_drvdata(dev, ptp_qoriq);
- return 0;
- err_free_threaded_irq:
- free_irq(ptp_qoriq->irq, ptp_qoriq);
- err_free_mc_irq:
- fsl_mc_free_irqs(mc_dev);
- err_unmap:
- iounmap(base);
- err_put:
- of_node_put(node);
- err_close:
- dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
- err_free_mcp:
- fsl_mc_portal_free(mc_dev->mc_io);
- err_exit:
- return err;
- }
- static int dpaa2_ptp_remove(struct fsl_mc_device *mc_dev)
- {
- struct device *dev = &mc_dev->dev;
- struct ptp_qoriq *ptp_qoriq;
- ptp_qoriq = dev_get_drvdata(dev);
- dpaa2_phc_index = -1;
- ptp_qoriq_free(ptp_qoriq);
- fsl_mc_free_irqs(mc_dev);
- dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
- fsl_mc_portal_free(mc_dev->mc_io);
- return 0;
- }
- static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = {
- {
- .vendor = FSL_MC_VENDOR_FREESCALE,
- .obj_type = "dprtc",
- },
- {}
- };
- MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table);
- static struct fsl_mc_driver dpaa2_ptp_drv = {
- .driver = {
- .name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- },
- .probe = dpaa2_ptp_probe,
- .remove = dpaa2_ptp_remove,
- .match_id_table = dpaa2_ptp_match_id_table,
- };
- module_fsl_mc_driver(dpaa2_ptp_drv);
- MODULE_LICENSE("GPL v2");
- MODULE_DESCRIPTION("DPAA2 PTP Clock Driver");
|