@@ -1684,6 +1691,223 @@ static struct attribute *timecard_attrs[] = {
};
ATTRIBUTE_GROUPS(timecard);
+#ifdef CONFIG_DEBUG_FS
+#define gpio_map(gpio, bit, pri, sec, def) ({ \
+ char *_ans; \
+ if (gpio & (1 << bit)) \
+ _ans = pri; \
+ else if (gpio & (1 << (bit + 16))) \
+ _ans = sec; \
+ else \
+ _ans = def; \
+ _ans; \
+})
+
+#define gpio_multi_map(buf, gpio, bit, pri, sec, def) ({ \
+ char *_ans; \
+ _ans = buf; \
+ strcpy(buf, def); \
+ if (gpio & (1 << (bit + 16))) \
+ _ans += sprintf(_ans, "%s ", pri); \
+ if (gpio & (1 << bit)) \
+ _ans += sprintf(_ans, "%s ", sec); \
+})
+
+static int
+ptp_ocp_summary_show(struct seq_file *s, void *data)
+{
+ struct device *dev = s->private;
+ struct ts_reg __iomem *ts_reg;
+ u32 sma_in, sma_out, val;
+ struct timespec64 ts;
+ struct ptp_ocp *bp;
+ char *buf, *src;
+ bool on;
+
+ buf = (char *)__get_free_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ sma1_out_show(dev, NULL, buf);
+ seq_printf(s, " sma1: out from %s", buf);
+
+ sma2_out_show(dev, NULL, buf);
+ seq_printf(s, " sma2: out from %s", buf);
+
+ sma3_in_show(dev, NULL, buf);
+ seq_printf(s, " sma3: input to %s", buf);
+
+ sma4_in_show(dev, NULL, buf);
+ seq_printf(s, " sma4: input to %s", buf);
+
+ bp = dev_get_drvdata(dev);
+ sma_in = ioread32(&bp->sma->gpio1);
+ sma_out = ioread32(&bp->sma->gpio2);
+
+ if (bp->ts0) {
+ ts_reg = bp->ts0->mem;
+ on = ioread32(&ts_reg->enable);
+ src = "GNSS";
+ seq_printf(s, "%7s: %s, src: %s\n", "TS0",
+ on ? " ON" : "OFF", src);
+ }
+
+ if (bp->ts1) {
+ ts_reg = bp->ts1->mem;
+ on = ioread32(&ts_reg->enable);
+ src = gpio_map(sma_in, 2, "sma4", "sma3", "----");
+ seq_printf(s, "%7s: %s, src: %s\n", "TS1",
+ on ? " ON" : "OFF", src);
+ }
+
+ if (bp->ts2) {
+ ts_reg = bp->ts2->mem;
+ on = ioread32(&ts_reg->enable);
+ src = gpio_map(sma_in, 3, "sma4", "sma3", "----");
+ seq_printf(s, "%7s: %s, src: %s\n", "TS2",
+ on ? " ON" : "OFF", src);
+ }
+
+ if (bp->irig_out) {
+ on = ioread32(&bp->irig_out->ctrl) & IRIG_M_CTRL_ENABLE;
+ val = ioread32(&bp->irig_out->status);
+ gpio_multi_map(buf, sma_out, 4, "sma1", "sma2", "----");
+ seq_printf(s, "%7s: %s, error: %d, out: %s\n", "IRIG",
+ on ? " ON" : "OFF", val, buf);
+ }
+
+ if (bp->irig_in) {
+ on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE;
+ val = ioread32(&bp->irig_in->status);
+ src = gpio_map(sma_in, 4, "sma4", "sma3", "----");
+ seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in",
+ on ? " ON" : "OFF", val, src);
+ }
+
+ if (bp->dcf_out) {
+ on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE;
+ val = ioread32(&bp->dcf_out->status);
+ gpio_multi_map(buf, sma_out, 5, "sma1", "sma2", "----");
+ seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF",
+ on ? " ON" : "OFF", val, buf);
+ }
+
+ if (bp->dcf_in) {
+ on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE;
+ val = ioread32(&bp->dcf_in->status);
+ src = gpio_map(sma_in, 5, "sma4", "sma3", "----");
+ seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in",
+ on ? " ON" : "OFF", val, src);
+ }
+
+ src = gpio_map(sma_in, 2, "sma4", "sma3", "GNSS");
+ sprintf(buf, "%s via PPS2", src);
+ seq_printf(s, " MAC PPS src: %s\n", buf);
+
+ /* assumes automatic switchover/selection */
+ val = ioread32(&bp->reg->select);
+ switch (val >> 16) {
+ case 0:
+ sprintf(buf, "----");
+ break;
+ case 2:
+ sprintf(buf, "IRIG");
+ break;
+ case 3:
+ if (bp->pps_select) {
+ val = ioread32(&bp->pps_select->gpio1);
+ if (val & 0x01) {
+ src = gpio_map(sma_in, 1,
+ "sma4", "sma3", "----");
+ } else if (val & 0x02)
+ src = "MAC";
+ else if (val & 0x04)
+ src = "GNSS";
+ else
+ src = "----";
+ sprintf(buf, "%s via PPS1", src);
+ } else {
+ strcpy(buf, "PPS1");
+ }
+ break;
+ case 6:
+ sprintf(buf, "DCF");
+ break;
+ default:
+ strcpy(buf, "unknown");
+ break;
+ }
+ val = ioread32(&bp->reg->status);
+ seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf,
+ val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced");
+
+ if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL))
+ seq_printf(s, "%7s: %lld.%ld == %ptT\n", "PHC",
+ ts.tv_sec, ts.tv_nsec, &ts);
+
+ free_page((unsigned long)buf);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary);
+
+static struct dentry *ptp_ocp_debugfs_root;
+
+static int
+ptp_ocp_debugfs_add_device(struct ptp_ocp *bp)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir(dev_name(&bp->dev), ptp_ocp_debugfs_root);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+ bp->debug_root = d;
+
+ d = debugfs_create_file("summary", 0444, bp->debug_root,
+ &bp->dev, &ptp_ocp_summary_fops);
+ if (IS_ERR(d))
+ goto fail;
+
+ return 0;
+
+fail:
+ debugfs_remove_recursive(bp->debug_root);
+ bp->debug_root = NULL;
+
+ return PTR_ERR(d);
+}
+
+static void
+ptp_ocp_debugfs_remove_device(struct ptp_ocp *bp)
+{
+ debugfs_remove_recursive(bp->debug_root);
+}
+
+static int
+ptp_ocp_debugfs_init(void)
+{
+ struct dentry *d;
+
+ d = debugfs_create_dir("timecard", NULL);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+
+ ptp_ocp_debugfs_root = d;
+
+ return 0;
+}
+
+static void
+ptp_ocp_debugfs_fini(void)
+{
+ debugfs_remove_recursive(ptp_ocp_debugfs_root);
+}
+#else
+#define ptp_ocp_debugfs_init() 0
+#define ptp_ocp_debugfs_fini()
+#define ptp_ocp_debugfs_add_device(bp) 0
+#define ptp_ocp_debugfs_remove_device(bp)
+#endif
+
static void
ptp_ocp_dev_release(struct device *dev)
{