1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18#include <linux/of_device.h>
19#include <linux/pm_domain.h>
20#include <linux/pm_runtime.h>
21
22#include <drm/drm_dp_aux_bus.h>
23#include <drm/drm_dp_helper.h>
24
25
26
27
28
29
30
31
32
33
34static int dp_aux_ep_match(struct device *dev, struct device_driver *drv)
35{
36 return !!of_match_device(drv->of_match_table, dev);
37}
38
39
40
41
42
43
44
45
46
47static int dp_aux_ep_probe(struct device *dev)
48{
49 struct dp_aux_ep_driver *aux_ep_drv = to_dp_aux_ep_drv(dev->driver);
50 struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev);
51 int ret;
52
53 ret = dev_pm_domain_attach(dev, true);
54 if (ret)
55 return dev_err_probe(dev, ret, "Failed to attach to PM Domain\n");
56
57 ret = aux_ep_drv->probe(aux_ep);
58 if (ret)
59 dev_pm_domain_detach(dev, true);
60
61 return ret;
62}
63
64
65
66
67
68
69
70
71static void dp_aux_ep_remove(struct device *dev)
72{
73 struct dp_aux_ep_driver *aux_ep_drv = to_dp_aux_ep_drv(dev->driver);
74 struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(dev);
75
76 if (aux_ep_drv->remove)
77 aux_ep_drv->remove(aux_ep);
78 dev_pm_domain_detach(dev, true);
79}
80
81
82
83
84
85
86
87static void dp_aux_ep_shutdown(struct device *dev)
88{
89 struct dp_aux_ep_driver *aux_ep_drv;
90
91 if (!dev->driver)
92 return;
93
94 aux_ep_drv = to_dp_aux_ep_drv(dev->driver);
95 if (aux_ep_drv->shutdown)
96 aux_ep_drv->shutdown(to_dp_aux_ep_dev(dev));
97}
98
99static struct bus_type dp_aux_bus_type = {
100 .name = "dp-aux",
101 .match = dp_aux_ep_match,
102 .probe = dp_aux_ep_probe,
103 .remove = dp_aux_ep_remove,
104 .shutdown = dp_aux_ep_shutdown,
105};
106
107static ssize_t modalias_show(struct device *dev,
108 struct device_attribute *attr, char *buf)
109{
110 return of_device_modalias(dev, buf, PAGE_SIZE);
111}
112static DEVICE_ATTR_RO(modalias);
113
114static struct attribute *dp_aux_ep_dev_attrs[] = {
115 &dev_attr_modalias.attr,
116 NULL,
117};
118ATTRIBUTE_GROUPS(dp_aux_ep_dev);
119
120
121
122
123
124
125
126static void dp_aux_ep_dev_release(struct device *dev)
127{
128 kfree(to_dp_aux_ep_dev(dev));
129}
130
131static struct device_type dp_aux_device_type_type = {
132 .groups = dp_aux_ep_dev_groups,
133 .uevent = of_device_uevent_modalias,
134 .release = dp_aux_ep_dev_release,
135};
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151static int of_dp_aux_ep_destroy(struct device *dev, void *data)
152{
153 struct device_node *np = dev->of_node;
154
155 if (dev->bus != &dp_aux_bus_type)
156 return 0;
157
158 if (!of_node_check_flag(np, OF_POPULATED))
159 return 0;
160
161 of_node_clear_flag(np, OF_POPULATED);
162 of_node_put(np);
163
164 device_unregister(dev);
165
166 return 0;
167}
168
169
170
171
172
173
174
175
176void of_dp_aux_depopulate_ep_devices(struct drm_dp_aux *aux)
177{
178 device_for_each_child_reverse(aux->dev, NULL, of_dp_aux_ep_destroy);
179}
180EXPORT_SYMBOL_GPL(of_dp_aux_depopulate_ep_devices);
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204int of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux)
205{
206 struct device_node *bus, *np;
207 struct dp_aux_ep_device *aux_ep;
208 int ret;
209
210
211 WARN_ON_ONCE(!aux->ddc.algo);
212
213 if (!aux->dev->of_node)
214 return 0;
215
216 bus = of_get_child_by_name(aux->dev->of_node, "aux-bus");
217 if (!bus)
218 return 0;
219
220 for_each_available_child_of_node(bus, np) {
221 if (of_node_test_and_set_flag(np, OF_POPULATED))
222 continue;
223
224 aux_ep = kzalloc(sizeof(*aux_ep), GFP_KERNEL);
225 if (!aux_ep)
226 continue;
227 aux_ep->aux = aux;
228
229 aux_ep->dev.parent = aux->dev;
230 aux_ep->dev.bus = &dp_aux_bus_type;
231 aux_ep->dev.type = &dp_aux_device_type_type;
232 aux_ep->dev.of_node = of_node_get(np);
233 dev_set_name(&aux_ep->dev, "aux-%s", dev_name(aux->dev));
234
235 ret = device_register(&aux_ep->dev);
236 if (ret) {
237 dev_err(aux->dev, "Failed to create AUX EP for %pOF: %d\n", np, ret);
238 of_node_clear_flag(np, OF_POPULATED);
239 of_node_put(np);
240
241
242
243
244
245 put_device(&aux_ep->dev);
246
247
248
249
250
251
252 }
253 }
254
255 of_node_put(bus);
256
257 return 0;
258}
259
260static void of_dp_aux_depopulate_ep_devices_void(void *data)
261{
262 of_dp_aux_depopulate_ep_devices(data);
263}
264
265
266
267
268
269
270
271
272
273int devm_of_dp_aux_populate_ep_devices(struct drm_dp_aux *aux)
274{
275 int ret;
276
277 ret = of_dp_aux_populate_ep_devices(aux);
278 if (ret)
279 return ret;
280
281 return devm_add_action_or_reset(aux->dev,
282 of_dp_aux_depopulate_ep_devices_void,
283 aux);
284}
285EXPORT_SYMBOL_GPL(devm_of_dp_aux_populate_ep_devices);
286
287int __dp_aux_dp_driver_register(struct dp_aux_ep_driver *drv, struct module *owner)
288{
289 drv->driver.owner = owner;
290 drv->driver.bus = &dp_aux_bus_type;
291
292 return driver_register(&drv->driver);
293}
294EXPORT_SYMBOL_GPL(__dp_aux_dp_driver_register);
295
296void dp_aux_dp_driver_unregister(struct dp_aux_ep_driver *drv)
297{
298 driver_unregister(&drv->driver);
299}
300EXPORT_SYMBOL_GPL(dp_aux_dp_driver_unregister);
301
302static int __init dp_aux_bus_init(void)
303{
304 int ret;
305
306 ret = bus_register(&dp_aux_bus_type);
307 if (ret)
308 return ret;
309
310 return 0;
311}
312
313static void __exit dp_aux_bus_exit(void)
314{
315 bus_unregister(&dp_aux_bus_type);
316}
317
318subsys_initcall(dp_aux_bus_init);
319module_exit(dp_aux_bus_exit);
320
321MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>");
322MODULE_DESCRIPTION("DRM DisplayPort AUX bus");
323MODULE_LICENSE("GPL v2");
324