xref: /linux/drivers/hwtracing/coresight/coresight-dummy.c (revision e70140ba0d2b1a30467d4af6bcfe761327b9ec95)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <linux/coresight.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/platform_device.h>
11 #include <linux/pm_runtime.h>
12 
13 #include "coresight-priv.h"
14 
15 struct dummy_drvdata {
16 	struct device			*dev;
17 	struct coresight_device		*csdev;
18 };
19 
20 DEFINE_CORESIGHT_DEVLIST(source_devs, "dummy_source");
21 DEFINE_CORESIGHT_DEVLIST(sink_devs, "dummy_sink");
22 
dummy_source_enable(struct coresight_device * csdev,struct perf_event * event,enum cs_mode mode,__maybe_unused struct coresight_trace_id_map * id_map)23 static int dummy_source_enable(struct coresight_device *csdev,
24 			       struct perf_event *event, enum cs_mode mode,
25 			       __maybe_unused struct coresight_trace_id_map *id_map)
26 {
27 	if (!coresight_take_mode(csdev, mode))
28 		return -EBUSY;
29 
30 	dev_dbg(csdev->dev.parent, "Dummy source enabled\n");
31 
32 	return 0;
33 }
34 
dummy_source_disable(struct coresight_device * csdev,struct perf_event * event)35 static void dummy_source_disable(struct coresight_device *csdev,
36 				 struct perf_event *event)
37 {
38 	coresight_set_mode(csdev, CS_MODE_DISABLED);
39 	dev_dbg(csdev->dev.parent, "Dummy source disabled\n");
40 }
41 
dummy_sink_enable(struct coresight_device * csdev,enum cs_mode mode,void * data)42 static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
43 				void *data)
44 {
45 	dev_dbg(csdev->dev.parent, "Dummy sink enabled\n");
46 
47 	return 0;
48 }
49 
dummy_sink_disable(struct coresight_device * csdev)50 static int dummy_sink_disable(struct coresight_device *csdev)
51 {
52 	dev_dbg(csdev->dev.parent, "Dummy sink disabled\n");
53 
54 	return 0;
55 }
56 
57 static const struct coresight_ops_source dummy_source_ops = {
58 	.enable	= dummy_source_enable,
59 	.disable = dummy_source_disable,
60 };
61 
62 static const struct coresight_ops dummy_source_cs_ops = {
63 	.source_ops = &dummy_source_ops,
64 };
65 
66 static const struct coresight_ops_sink dummy_sink_ops = {
67 	.enable	= dummy_sink_enable,
68 	.disable = dummy_sink_disable,
69 };
70 
71 static const struct coresight_ops dummy_sink_cs_ops = {
72 	.sink_ops = &dummy_sink_ops,
73 };
74 
dummy_probe(struct platform_device * pdev)75 static int dummy_probe(struct platform_device *pdev)
76 {
77 	struct device *dev = &pdev->dev;
78 	struct device_node *node = dev->of_node;
79 	struct coresight_platform_data *pdata;
80 	struct dummy_drvdata *drvdata;
81 	struct coresight_desc desc = { 0 };
82 
83 	if (of_device_is_compatible(node, "arm,coresight-dummy-source")) {
84 
85 		desc.name = coresight_alloc_device_name(&source_devs, dev);
86 		if (!desc.name)
87 			return -ENOMEM;
88 
89 		desc.type = CORESIGHT_DEV_TYPE_SOURCE;
90 		desc.subtype.source_subtype =
91 					CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
92 		desc.ops = &dummy_source_cs_ops;
93 	} else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
94 		desc.name = coresight_alloc_device_name(&sink_devs, dev);
95 		if (!desc.name)
96 			return -ENOMEM;
97 
98 		desc.type = CORESIGHT_DEV_TYPE_SINK;
99 		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_DUMMY;
100 		desc.ops = &dummy_sink_cs_ops;
101 	} else {
102 		dev_err(dev, "Device type not set\n");
103 		return -EINVAL;
104 	}
105 
106 	pdata = coresight_get_platform_data(dev);
107 	if (IS_ERR(pdata))
108 		return PTR_ERR(pdata);
109 	pdev->dev.platform_data = pdata;
110 
111 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
112 	if (!drvdata)
113 		return -ENOMEM;
114 
115 	drvdata->dev = &pdev->dev;
116 	platform_set_drvdata(pdev, drvdata);
117 
118 	desc.pdata = pdev->dev.platform_data;
119 	desc.dev = &pdev->dev;
120 	drvdata->csdev = coresight_register(&desc);
121 	if (IS_ERR(drvdata->csdev))
122 		return PTR_ERR(drvdata->csdev);
123 
124 	pm_runtime_enable(dev);
125 	dev_dbg(dev, "Dummy device initialized\n");
126 
127 	return 0;
128 }
129 
dummy_remove(struct platform_device * pdev)130 static void dummy_remove(struct platform_device *pdev)
131 {
132 	struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
133 	struct device *dev = &pdev->dev;
134 
135 	pm_runtime_disable(dev);
136 	coresight_unregister(drvdata->csdev);
137 }
138 
139 static const struct of_device_id dummy_match[] = {
140 	{.compatible = "arm,coresight-dummy-source"},
141 	{.compatible = "arm,coresight-dummy-sink"},
142 	{},
143 };
144 
145 static struct platform_driver dummy_driver = {
146 	.probe	= dummy_probe,
147 	.remove = dummy_remove,
148 	.driver	= {
149 		.name   = "coresight-dummy",
150 		.of_match_table = dummy_match,
151 	},
152 };
153 
154 module_platform_driver(dummy_driver);
155 
156 MODULE_LICENSE("GPL");
157 MODULE_DESCRIPTION("CoreSight dummy driver");
158