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 
23 static int dummy_source_enable(struct coresight_device *csdev,
24 			       struct perf_event *event, enum cs_mode mode)
25 {
26 	dev_dbg(csdev->dev.parent, "Dummy source enabled\n");
27 
28 	return 0;
29 }
30 
31 static void dummy_source_disable(struct coresight_device *csdev,
32 				 struct perf_event *event)
33 {
34 	dev_dbg(csdev->dev.parent, "Dummy source disabled\n");
35 }
36 
37 static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
38 				void *data)
39 {
40 	dev_dbg(csdev->dev.parent, "Dummy sink enabled\n");
41 
42 	return 0;
43 }
44 
45 static int dummy_sink_disable(struct coresight_device *csdev)
46 {
47 	dev_dbg(csdev->dev.parent, "Dummy sink disabled\n");
48 
49 	return 0;
50 }
51 
52 static const struct coresight_ops_source dummy_source_ops = {
53 	.enable	= dummy_source_enable,
54 	.disable = dummy_source_disable,
55 };
56 
57 static const struct coresight_ops dummy_source_cs_ops = {
58 	.source_ops = &dummy_source_ops,
59 };
60 
61 static const struct coresight_ops_sink dummy_sink_ops = {
62 	.enable	= dummy_sink_enable,
63 	.disable = dummy_sink_disable,
64 };
65 
66 static const struct coresight_ops dummy_sink_cs_ops = {
67 	.sink_ops = &dummy_sink_ops,
68 };
69 
70 static int dummy_probe(struct platform_device *pdev)
71 {
72 	struct device *dev = &pdev->dev;
73 	struct device_node *node = dev->of_node;
74 	struct coresight_platform_data *pdata;
75 	struct dummy_drvdata *drvdata;
76 	struct coresight_desc desc = { 0 };
77 
78 	if (of_device_is_compatible(node, "arm,coresight-dummy-source")) {
79 
80 		desc.name = coresight_alloc_device_name(&source_devs, dev);
81 		if (!desc.name)
82 			return -ENOMEM;
83 
84 		desc.type = CORESIGHT_DEV_TYPE_SOURCE;
85 		desc.subtype.source_subtype =
86 					CORESIGHT_DEV_SUBTYPE_SOURCE_OTHERS;
87 		desc.ops = &dummy_source_cs_ops;
88 	} else if (of_device_is_compatible(node, "arm,coresight-dummy-sink")) {
89 		desc.name = coresight_alloc_device_name(&sink_devs, dev);
90 		if (!desc.name)
91 			return -ENOMEM;
92 
93 		desc.type = CORESIGHT_DEV_TYPE_SINK;
94 		desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_DUMMY;
95 		desc.ops = &dummy_sink_cs_ops;
96 	} else {
97 		dev_err(dev, "Device type not set\n");
98 		return -EINVAL;
99 	}
100 
101 	pdata = coresight_get_platform_data(dev);
102 	if (IS_ERR(pdata))
103 		return PTR_ERR(pdata);
104 	pdev->dev.platform_data = pdata;
105 
106 	drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
107 	if (!drvdata)
108 		return -ENOMEM;
109 
110 	drvdata->dev = &pdev->dev;
111 	platform_set_drvdata(pdev, drvdata);
112 
113 	desc.pdata = pdev->dev.platform_data;
114 	desc.dev = &pdev->dev;
115 	drvdata->csdev = coresight_register(&desc);
116 	if (IS_ERR(drvdata->csdev))
117 		return PTR_ERR(drvdata->csdev);
118 
119 	pm_runtime_enable(dev);
120 	dev_dbg(dev, "Dummy device initialized\n");
121 
122 	return 0;
123 }
124 
125 static int dummy_remove(struct platform_device *pdev)
126 {
127 	struct dummy_drvdata *drvdata = platform_get_drvdata(pdev);
128 	struct device *dev = &pdev->dev;
129 
130 	pm_runtime_disable(dev);
131 	coresight_unregister(drvdata->csdev);
132 	return 0;
133 }
134 
135 static const struct of_device_id dummy_match[] = {
136 	{.compatible = "arm,coresight-dummy-source"},
137 	{.compatible = "arm,coresight-dummy-sink"},
138 	{},
139 };
140 
141 static struct platform_driver dummy_driver = {
142 	.probe	= dummy_probe,
143 	.remove	= dummy_remove,
144 	.driver	= {
145 		.name   = "coresight-dummy",
146 		.of_match_table = dummy_match,
147 	},
148 };
149 
150 static int __init dummy_init(void)
151 {
152 	return platform_driver_register(&dummy_driver);
153 }
154 module_init(dummy_init);
155 
156 static void __exit dummy_exit(void)
157 {
158 	platform_driver_unregister(&dummy_driver);
159 }
160 module_exit(dummy_exit);
161 
162 MODULE_LICENSE("GPL");
163 MODULE_DESCRIPTION("CoreSight dummy driver");
164