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