1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2013-2016 Freescale Semiconductor Inc. 4 * Copyright 2016-2018 NXP 5 */ 6 7 #include <linux/module.h> 8 #include <linux/of.h> 9 #include <linux/of_address.h> 10 #include <linux/msi.h> 11 #include <linux/fsl/mc.h> 12 #include <linux/fsl/ptp_qoriq.h> 13 14 #include "dpaa2-ptp.h" 15 16 static 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 73 static 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 89 static 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 129 static 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 dev_set_drvdata(dev, ptp_qoriq); 205 206 return 0; 207 208 err_free_threaded_irq: 209 free_irq(ptp_qoriq->irq, ptp_qoriq); 210 err_free_mc_irq: 211 fsl_mc_free_irqs(mc_dev); 212 err_unmap: 213 iounmap(base); 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 int 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 return 0; 237 } 238 239 static const struct fsl_mc_device_id dpaa2_ptp_match_id_table[] = { 240 { 241 .vendor = FSL_MC_VENDOR_FREESCALE, 242 .obj_type = "dprtc", 243 }, 244 {} 245 }; 246 MODULE_DEVICE_TABLE(fslmc, dpaa2_ptp_match_id_table); 247 248 static struct fsl_mc_driver dpaa2_ptp_drv = { 249 .driver = { 250 .name = KBUILD_MODNAME, 251 .owner = THIS_MODULE, 252 }, 253 .probe = dpaa2_ptp_probe, 254 .remove = dpaa2_ptp_remove, 255 .match_id_table = dpaa2_ptp_match_id_table, 256 }; 257 258 module_fsl_mc_driver(dpaa2_ptp_drv); 259 260 MODULE_LICENSE("GPL v2"); 261 MODULE_DESCRIPTION("DPAA2 PTP Clock Driver"); 262