This source file includes following definitions.
- get_v4l2_fwnode_bus_conv_by_fwnode_bus
- v4l2_fwnode_bus_type_to_mbus
- v4l2_fwnode_bus_type_to_string
- get_v4l2_fwnode_bus_conv_by_mbus
- v4l2_fwnode_mbus_type_to_string
- v4l2_fwnode_endpoint_parse_csi2_bus
- v4l2_fwnode_endpoint_parse_parallel_bus
- v4l2_fwnode_endpoint_parse_csi1_bus
- __v4l2_fwnode_endpoint_parse
- v4l2_fwnode_endpoint_parse
- v4l2_fwnode_endpoint_free
- v4l2_fwnode_endpoint_alloc_parse
- v4l2_fwnode_parse_link
- v4l2_fwnode_put_link
- v4l2_async_notifier_fwnode_parse_endpoint
- __v4l2_async_notifier_parse_fwnode_ep
- v4l2_async_notifier_parse_fwnode_endpoints
- v4l2_async_notifier_parse_fwnode_endpoints_by_port
- v4l2_fwnode_reference_parse
- v4l2_fwnode_reference_get_int_prop
- v4l2_fwnode_reference_parse_int_props
- v4l2_async_notifier_parse_fwnode_sensor_common
- v4l2_async_register_subdev_sensor_common
- v4l2_async_register_fwnode_subdev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 #include <linux/acpi.h>
18 #include <linux/kernel.h>
19 #include <linux/mm.h>
20 #include <linux/module.h>
21 #include <linux/of.h>
22 #include <linux/property.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/types.h>
26
27 #include <media/v4l2-async.h>
28 #include <media/v4l2-fwnode.h>
29 #include <media/v4l2-subdev.h>
30
31 enum v4l2_fwnode_bus_type {
32 V4L2_FWNODE_BUS_TYPE_GUESS = 0,
33 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
34 V4L2_FWNODE_BUS_TYPE_CSI1,
35 V4L2_FWNODE_BUS_TYPE_CCP2,
36 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
37 V4L2_FWNODE_BUS_TYPE_PARALLEL,
38 V4L2_FWNODE_BUS_TYPE_BT656,
39 NR_OF_V4L2_FWNODE_BUS_TYPE,
40 };
41
42 static const struct v4l2_fwnode_bus_conv {
43 enum v4l2_fwnode_bus_type fwnode_bus_type;
44 enum v4l2_mbus_type mbus_type;
45 const char *name;
46 } buses[] = {
47 {
48 V4L2_FWNODE_BUS_TYPE_GUESS,
49 V4L2_MBUS_UNKNOWN,
50 "not specified",
51 }, {
52 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
53 V4L2_MBUS_CSI2_CPHY,
54 "MIPI CSI-2 C-PHY",
55 }, {
56 V4L2_FWNODE_BUS_TYPE_CSI1,
57 V4L2_MBUS_CSI1,
58 "MIPI CSI-1",
59 }, {
60 V4L2_FWNODE_BUS_TYPE_CCP2,
61 V4L2_MBUS_CCP2,
62 "compact camera port 2",
63 }, {
64 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
65 V4L2_MBUS_CSI2_DPHY,
66 "MIPI CSI-2 D-PHY",
67 }, {
68 V4L2_FWNODE_BUS_TYPE_PARALLEL,
69 V4L2_MBUS_PARALLEL,
70 "parallel",
71 }, {
72 V4L2_FWNODE_BUS_TYPE_BT656,
73 V4L2_MBUS_BT656,
74 "Bt.656",
75 }
76 };
77
78 static const struct v4l2_fwnode_bus_conv *
79 get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
80 {
81 unsigned int i;
82
83 for (i = 0; i < ARRAY_SIZE(buses); i++)
84 if (buses[i].fwnode_bus_type == type)
85 return &buses[i];
86
87 return NULL;
88 }
89
90 static enum v4l2_mbus_type
91 v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
92 {
93 const struct v4l2_fwnode_bus_conv *conv =
94 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
95
96 return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
97 }
98
99 static const char *
100 v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
101 {
102 const struct v4l2_fwnode_bus_conv *conv =
103 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
104
105 return conv ? conv->name : "not found";
106 }
107
108 static const struct v4l2_fwnode_bus_conv *
109 get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
110 {
111 unsigned int i;
112
113 for (i = 0; i < ARRAY_SIZE(buses); i++)
114 if (buses[i].mbus_type == type)
115 return &buses[i];
116
117 return NULL;
118 }
119
120 static const char *
121 v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
122 {
123 const struct v4l2_fwnode_bus_conv *conv =
124 get_v4l2_fwnode_bus_conv_by_mbus(type);
125
126 return conv ? conv->name : "not found";
127 }
128
129 static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
130 struct v4l2_fwnode_endpoint *vep,
131 enum v4l2_mbus_type bus_type)
132 {
133 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
134 bool have_clk_lane = false, have_data_lanes = false,
135 have_lane_polarities = false;
136 unsigned int flags = 0, lanes_used = 0;
137 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
138 u32 clock_lane = 0;
139 unsigned int num_data_lanes = 0;
140 bool use_default_lane_mapping = false;
141 unsigned int i;
142 u32 v;
143 int rval;
144
145 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
146 bus_type == V4L2_MBUS_CSI2_CPHY) {
147 use_default_lane_mapping = true;
148
149 num_data_lanes = min_t(u32, bus->num_data_lanes,
150 V4L2_FWNODE_CSI2_MAX_DATA_LANES);
151
152 clock_lane = bus->clock_lane;
153 if (clock_lane)
154 use_default_lane_mapping = false;
155
156 for (i = 0; i < num_data_lanes; i++) {
157 array[i] = bus->data_lanes[i];
158 if (array[i])
159 use_default_lane_mapping = false;
160 }
161
162 if (use_default_lane_mapping)
163 pr_debug("no lane mapping given, using defaults\n");
164 }
165
166 rval = fwnode_property_count_u32(fwnode, "data-lanes");
167 if (rval > 0) {
168 num_data_lanes =
169 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
170
171 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
172 num_data_lanes);
173
174 have_data_lanes = true;
175 if (use_default_lane_mapping) {
176 pr_debug("data-lanes property exists; disabling default mapping\n");
177 use_default_lane_mapping = false;
178 }
179 }
180
181 for (i = 0; i < num_data_lanes; i++) {
182 if (lanes_used & BIT(array[i])) {
183 if (have_data_lanes || !use_default_lane_mapping)
184 pr_warn("duplicated lane %u in data-lanes, using defaults\n",
185 array[i]);
186 use_default_lane_mapping = true;
187 }
188 lanes_used |= BIT(array[i]);
189
190 if (have_data_lanes)
191 pr_debug("lane %u position %u\n", i, array[i]);
192 }
193
194 rval = fwnode_property_count_u32(fwnode, "lane-polarities");
195 if (rval > 0) {
196 if (rval != 1 + num_data_lanes ) {
197 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
198 1 + num_data_lanes, rval);
199 return -EINVAL;
200 }
201
202 have_lane_polarities = true;
203 }
204
205 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
206 clock_lane = v;
207 pr_debug("clock lane position %u\n", v);
208 have_clk_lane = true;
209 }
210
211 if (have_clk_lane && lanes_used & BIT(clock_lane) &&
212 !use_default_lane_mapping) {
213 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
214 v);
215 use_default_lane_mapping = true;
216 }
217
218 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
219 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
220 pr_debug("non-continuous clock\n");
221 } else {
222 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
223 }
224
225 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
226 bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
227 have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
228
229 unsigned int dfl_data_lane_index =
230 bus_type == V4L2_MBUS_CSI2_DPHY;
231
232 bus->flags = flags;
233 if (bus_type == V4L2_MBUS_UNKNOWN)
234 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
235 bus->num_data_lanes = num_data_lanes;
236
237 if (use_default_lane_mapping) {
238 bus->clock_lane = 0;
239 for (i = 0; i < num_data_lanes; i++)
240 bus->data_lanes[i] = dfl_data_lane_index + i;
241 } else {
242 bus->clock_lane = clock_lane;
243 for (i = 0; i < num_data_lanes; i++)
244 bus->data_lanes[i] = array[i];
245 }
246
247 if (have_lane_polarities) {
248 fwnode_property_read_u32_array(fwnode,
249 "lane-polarities", array,
250 1 + num_data_lanes);
251
252 for (i = 0; i < 1 + num_data_lanes; i++) {
253 bus->lane_polarities[i] = array[i];
254 pr_debug("lane %u polarity %sinverted",
255 i, array[i] ? "" : "not ");
256 }
257 } else {
258 pr_debug("no lane polarities defined, assuming not inverted\n");
259 }
260 }
261
262 return 0;
263 }
264
265 #define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
266 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
267 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
268 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
269 V4L2_MBUS_FIELD_EVEN_HIGH | \
270 V4L2_MBUS_FIELD_EVEN_LOW)
271
272 static void
273 v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
274 struct v4l2_fwnode_endpoint *vep,
275 enum v4l2_mbus_type bus_type)
276 {
277 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
278 unsigned int flags = 0;
279 u32 v;
280
281 if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
282 flags = bus->flags;
283
284 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
285 flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
286 V4L2_MBUS_HSYNC_ACTIVE_LOW);
287 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
288 V4L2_MBUS_HSYNC_ACTIVE_LOW;
289 pr_debug("hsync-active %s\n", v ? "high" : "low");
290 }
291
292 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
293 flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
294 V4L2_MBUS_VSYNC_ACTIVE_LOW);
295 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
296 V4L2_MBUS_VSYNC_ACTIVE_LOW;
297 pr_debug("vsync-active %s\n", v ? "high" : "low");
298 }
299
300 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
301 flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
302 V4L2_MBUS_FIELD_EVEN_LOW);
303 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
304 V4L2_MBUS_FIELD_EVEN_LOW;
305 pr_debug("field-even-active %s\n", v ? "high" : "low");
306 }
307
308 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
309 flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
310 V4L2_MBUS_PCLK_SAMPLE_FALLING);
311 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
312 V4L2_MBUS_PCLK_SAMPLE_FALLING;
313 pr_debug("pclk-sample %s\n", v ? "high" : "low");
314 }
315
316 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
317 flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
318 V4L2_MBUS_DATA_ACTIVE_LOW);
319 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
320 V4L2_MBUS_DATA_ACTIVE_LOW;
321 pr_debug("data-active %s\n", v ? "high" : "low");
322 }
323
324 if (fwnode_property_present(fwnode, "slave-mode")) {
325 pr_debug("slave mode\n");
326 flags &= ~V4L2_MBUS_MASTER;
327 flags |= V4L2_MBUS_SLAVE;
328 } else {
329 flags &= ~V4L2_MBUS_SLAVE;
330 flags |= V4L2_MBUS_MASTER;
331 }
332
333 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
334 bus->bus_width = v;
335 pr_debug("bus-width %u\n", v);
336 }
337
338 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
339 bus->data_shift = v;
340 pr_debug("data-shift %u\n", v);
341 }
342
343 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
344 flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
345 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
346 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
347 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
348 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
349 }
350
351 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
352 flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
353 V4L2_MBUS_DATA_ENABLE_LOW);
354 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
355 V4L2_MBUS_DATA_ENABLE_LOW;
356 pr_debug("data-enable-active %s\n", v ? "high" : "low");
357 }
358
359 switch (bus_type) {
360 default:
361 bus->flags = flags;
362 if (flags & PARALLEL_MBUS_FLAGS)
363 vep->bus_type = V4L2_MBUS_PARALLEL;
364 else
365 vep->bus_type = V4L2_MBUS_BT656;
366 break;
367 case V4L2_MBUS_PARALLEL:
368 vep->bus_type = V4L2_MBUS_PARALLEL;
369 bus->flags = flags;
370 break;
371 case V4L2_MBUS_BT656:
372 vep->bus_type = V4L2_MBUS_BT656;
373 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
374 break;
375 }
376 }
377
378 static void
379 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
380 struct v4l2_fwnode_endpoint *vep,
381 enum v4l2_mbus_type bus_type)
382 {
383 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
384 u32 v;
385
386 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
387 bus->clock_inv = v;
388 pr_debug("clock-inv %u\n", v);
389 }
390
391 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
392 bus->strobe = v;
393 pr_debug("strobe %u\n", v);
394 }
395
396 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
397 bus->data_lane = v;
398 pr_debug("data-lanes %u\n", v);
399 }
400
401 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
402 bus->clock_lane = v;
403 pr_debug("clock-lanes %u\n", v);
404 }
405
406 if (bus_type == V4L2_MBUS_CCP2)
407 vep->bus_type = V4L2_MBUS_CCP2;
408 else
409 vep->bus_type = V4L2_MBUS_CSI1;
410 }
411
412 static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
413 struct v4l2_fwnode_endpoint *vep)
414 {
415 u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
416 enum v4l2_mbus_type mbus_type;
417 int rval;
418
419 if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
420
421 memset(&vep->bus, 0,
422 sizeof(*vep) - offsetof(typeof(*vep), bus));
423 }
424
425 pr_debug("===== begin V4L2 endpoint properties\n");
426
427
428
429
430
431 memset(&vep->base, 0, sizeof(vep->base));
432
433 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
434 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
435 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
436 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
437 vep->bus_type);
438 mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
439
440 if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
441 if (mbus_type != V4L2_MBUS_UNKNOWN &&
442 vep->bus_type != mbus_type) {
443 pr_debug("expecting bus type %s\n",
444 v4l2_fwnode_mbus_type_to_string(vep->bus_type));
445 return -ENXIO;
446 }
447 } else {
448 vep->bus_type = mbus_type;
449 }
450
451 switch (vep->bus_type) {
452 case V4L2_MBUS_UNKNOWN:
453 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
454 V4L2_MBUS_UNKNOWN);
455 if (rval)
456 return rval;
457
458 if (vep->bus_type == V4L2_MBUS_UNKNOWN)
459 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
460 V4L2_MBUS_UNKNOWN);
461
462 pr_debug("assuming media bus type %s (%u)\n",
463 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
464 vep->bus_type);
465
466 break;
467 case V4L2_MBUS_CCP2:
468 case V4L2_MBUS_CSI1:
469 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
470
471 break;
472 case V4L2_MBUS_CSI2_DPHY:
473 case V4L2_MBUS_CSI2_CPHY:
474 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
475 vep->bus_type);
476 if (rval)
477 return rval;
478
479 break;
480 case V4L2_MBUS_PARALLEL:
481 case V4L2_MBUS_BT656:
482 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
483 vep->bus_type);
484
485 break;
486 default:
487 pr_warn("unsupported bus type %u\n", mbus_type);
488 return -EINVAL;
489 }
490
491 fwnode_graph_parse_endpoint(fwnode, &vep->base);
492
493 return 0;
494 }
495
496 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
497 struct v4l2_fwnode_endpoint *vep)
498 {
499 int ret;
500
501 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
502
503 pr_debug("===== end V4L2 endpoint properties\n");
504
505 return ret;
506 }
507 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
508
509 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
510 {
511 if (IS_ERR_OR_NULL(vep))
512 return;
513
514 kfree(vep->link_frequencies);
515 }
516 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
517
518 int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
519 struct v4l2_fwnode_endpoint *vep)
520 {
521 int rval;
522
523 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
524 if (rval < 0)
525 return rval;
526
527 rval = fwnode_property_count_u64(fwnode, "link-frequencies");
528 if (rval > 0) {
529 unsigned int i;
530
531 vep->link_frequencies =
532 kmalloc_array(rval, sizeof(*vep->link_frequencies),
533 GFP_KERNEL);
534 if (!vep->link_frequencies)
535 return -ENOMEM;
536
537 vep->nr_of_link_frequencies = rval;
538
539 rval = fwnode_property_read_u64_array(fwnode,
540 "link-frequencies",
541 vep->link_frequencies,
542 vep->nr_of_link_frequencies);
543 if (rval < 0) {
544 v4l2_fwnode_endpoint_free(vep);
545 return rval;
546 }
547
548 for (i = 0; i < vep->nr_of_link_frequencies; i++)
549 pr_info("link-frequencies %u value %llu\n", i,
550 vep->link_frequencies[i]);
551 }
552
553 pr_debug("===== end V4L2 endpoint properties\n");
554
555 return 0;
556 }
557 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
558
559 int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
560 struct v4l2_fwnode_link *link)
561 {
562 const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
563 struct fwnode_handle *fwnode;
564
565 memset(link, 0, sizeof(*link));
566
567 fwnode = fwnode_get_parent(__fwnode);
568 fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
569 fwnode = fwnode_get_next_parent(fwnode);
570 if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
571 fwnode = fwnode_get_next_parent(fwnode);
572 link->local_node = fwnode;
573
574 fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
575 if (!fwnode) {
576 fwnode_handle_put(fwnode);
577 return -ENOLINK;
578 }
579
580 fwnode = fwnode_get_parent(fwnode);
581 fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
582 fwnode = fwnode_get_next_parent(fwnode);
583 if (is_of_node(fwnode) && of_node_name_eq(to_of_node(fwnode), "ports"))
584 fwnode = fwnode_get_next_parent(fwnode);
585 link->remote_node = fwnode;
586
587 return 0;
588 }
589 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
590
591 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
592 {
593 fwnode_handle_put(link->local_node);
594 fwnode_handle_put(link->remote_node);
595 }
596 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
597
598 static int
599 v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
600 struct v4l2_async_notifier *notifier,
601 struct fwnode_handle *endpoint,
602 unsigned int asd_struct_size,
603 parse_endpoint_func parse_endpoint)
604 {
605 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
606 struct v4l2_async_subdev *asd;
607 int ret;
608
609 asd = kzalloc(asd_struct_size, GFP_KERNEL);
610 if (!asd)
611 return -ENOMEM;
612
613 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
614 asd->match.fwnode =
615 fwnode_graph_get_remote_port_parent(endpoint);
616 if (!asd->match.fwnode) {
617 dev_dbg(dev, "no remote endpoint found\n");
618 ret = -ENOTCONN;
619 goto out_err;
620 }
621
622 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
623 if (ret) {
624 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
625 ret);
626 goto out_err;
627 }
628
629 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
630 if (ret == -ENOTCONN)
631 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
632 vep.base.id);
633 else if (ret < 0)
634 dev_warn(dev,
635 "driver could not parse port@%u/endpoint@%u (%d)\n",
636 vep.base.port, vep.base.id, ret);
637 v4l2_fwnode_endpoint_free(&vep);
638 if (ret < 0)
639 goto out_err;
640
641 ret = v4l2_async_notifier_add_subdev(notifier, asd);
642 if (ret < 0) {
643
644 if (ret == -EEXIST)
645 ret = 0;
646 goto out_err;
647 }
648
649 return 0;
650
651 out_err:
652 fwnode_handle_put(asd->match.fwnode);
653 kfree(asd);
654
655 return ret == -ENOTCONN ? 0 : ret;
656 }
657
658 static int
659 __v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
660 struct v4l2_async_notifier *notifier,
661 size_t asd_struct_size,
662 unsigned int port,
663 bool has_port,
664 parse_endpoint_func parse_endpoint)
665 {
666 struct fwnode_handle *fwnode;
667 int ret = 0;
668
669 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
670 return -EINVAL;
671
672 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
673 struct fwnode_handle *dev_fwnode;
674 bool is_available;
675
676 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
677 is_available = fwnode_device_is_available(dev_fwnode);
678 fwnode_handle_put(dev_fwnode);
679 if (!is_available)
680 continue;
681
682 if (has_port) {
683 struct fwnode_endpoint ep;
684
685 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
686 if (ret)
687 break;
688
689 if (ep.port != port)
690 continue;
691 }
692
693 ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
694 notifier,
695 fwnode,
696 asd_struct_size,
697 parse_endpoint);
698 if (ret < 0)
699 break;
700 }
701
702 fwnode_handle_put(fwnode);
703
704 return ret;
705 }
706
707 int
708 v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
709 struct v4l2_async_notifier *notifier,
710 size_t asd_struct_size,
711 parse_endpoint_func parse_endpoint)
712 {
713 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
714 asd_struct_size, 0,
715 false, parse_endpoint);
716 }
717 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
718
719 int
720 v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
721 struct v4l2_async_notifier *notifier,
722 size_t asd_struct_size,
723 unsigned int port,
724 parse_endpoint_func parse_endpoint)
725 {
726 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
727 asd_struct_size,
728 port, true,
729 parse_endpoint);
730 }
731 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
732
733
734
735
736
737
738
739
740
741
742
743
744 static int v4l2_fwnode_reference_parse(struct device *dev,
745 struct v4l2_async_notifier *notifier,
746 const char *prop)
747 {
748 struct fwnode_reference_args args;
749 unsigned int index;
750 int ret;
751
752 for (index = 0;
753 !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
754 prop, NULL, 0,
755 index, &args));
756 index++)
757 fwnode_handle_put(args.fwnode);
758
759 if (!index)
760 return -ENOENT;
761
762
763
764
765
766 if (ret != -ENOENT && ret != -ENODATA)
767 return ret;
768
769 for (index = 0;
770 !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
771 0, index, &args);
772 index++) {
773 struct v4l2_async_subdev *asd;
774
775 asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
776 args.fwnode,
777 sizeof(*asd));
778 fwnode_handle_put(args.fwnode);
779 if (IS_ERR(asd)) {
780
781 if (PTR_ERR(asd) == -EEXIST)
782 continue;
783
784 return PTR_ERR(asd);
785 }
786 }
787
788 return 0;
789 }
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950 static struct fwnode_handle *
951 v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
952 const char *prop,
953 unsigned int index,
954 const char * const *props,
955 unsigned int nprops)
956 {
957 struct fwnode_reference_args fwnode_args;
958 u64 *args = fwnode_args.args;
959 struct fwnode_handle *child;
960 int ret;
961
962
963
964
965
966
967
968 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
969 index, &fwnode_args);
970 if (ret)
971 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
972
973
974
975
976
977 fwnode = fwnode_args.fwnode;
978 while (nprops--) {
979 u32 val;
980
981
982 fwnode_for_each_child_node(fwnode, child) {
983 if (fwnode_property_read_u32(child, *props, &val))
984 continue;
985
986
987 if (val == *args)
988 break;
989 }
990
991 fwnode_handle_put(fwnode);
992
993
994 if (!child) {
995 fwnode = ERR_PTR(-ENOENT);
996 break;
997 }
998
999 props++;
1000 args++;
1001 fwnode = child;
1002 }
1003
1004 return fwnode;
1005 }
1006
1007 struct v4l2_fwnode_int_props {
1008 const char *name;
1009 const char * const *props;
1010 unsigned int nprops;
1011 };
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036 static int
1037 v4l2_fwnode_reference_parse_int_props(struct device *dev,
1038 struct v4l2_async_notifier *notifier,
1039 const struct v4l2_fwnode_int_props *p)
1040 {
1041 struct fwnode_handle *fwnode;
1042 unsigned int index;
1043 int ret;
1044 const char *prop = p->name;
1045 const char * const *props = p->props;
1046 unsigned int nprops = p->nprops;
1047
1048 index = 0;
1049 do {
1050 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1051 prop, index,
1052 props, nprops);
1053 if (IS_ERR(fwnode)) {
1054
1055
1056
1057
1058
1059 if (PTR_ERR(fwnode) != -ENOENT &&
1060 PTR_ERR(fwnode) != -ENODATA)
1061 return PTR_ERR(fwnode);
1062 break;
1063 }
1064 fwnode_handle_put(fwnode);
1065 index++;
1066 } while (1);
1067
1068 for (index = 0;
1069 !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1070 prop, index,
1071 props,
1072 nprops)));
1073 index++) {
1074 struct v4l2_async_subdev *asd;
1075
1076 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1077 sizeof(*asd));
1078 fwnode_handle_put(fwnode);
1079 if (IS_ERR(asd)) {
1080 ret = PTR_ERR(asd);
1081
1082 if (ret == -EEXIST)
1083 continue;
1084
1085 return PTR_ERR(asd);
1086 }
1087 }
1088
1089 return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1090 }
1091
1092 int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev,
1093 struct v4l2_async_notifier *notifier)
1094 {
1095 static const char * const led_props[] = { "led" };
1096 static const struct v4l2_fwnode_int_props props[] = {
1097 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
1098 { "lens-focus", NULL, 0 },
1099 };
1100 unsigned int i;
1101
1102 for (i = 0; i < ARRAY_SIZE(props); i++) {
1103 int ret;
1104
1105 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1106 ret = v4l2_fwnode_reference_parse_int_props(dev,
1107 notifier,
1108 &props[i]);
1109 else
1110 ret = v4l2_fwnode_reference_parse(dev, notifier,
1111 props[i].name);
1112 if (ret && ret != -ENOENT) {
1113 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1114 props[i].name, ret);
1115 return ret;
1116 }
1117 }
1118
1119 return 0;
1120 }
1121 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
1122
1123 int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
1124 {
1125 struct v4l2_async_notifier *notifier;
1126 int ret;
1127
1128 if (WARN_ON(!sd->dev))
1129 return -ENODEV;
1130
1131 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1132 if (!notifier)
1133 return -ENOMEM;
1134
1135 v4l2_async_notifier_init(notifier);
1136
1137 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
1138 notifier);
1139 if (ret < 0)
1140 goto out_cleanup;
1141
1142 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1143 if (ret < 0)
1144 goto out_cleanup;
1145
1146 ret = v4l2_async_register_subdev(sd);
1147 if (ret < 0)
1148 goto out_unregister;
1149
1150 sd->subdev_notifier = notifier;
1151
1152 return 0;
1153
1154 out_unregister:
1155 v4l2_async_notifier_unregister(notifier);
1156
1157 out_cleanup:
1158 v4l2_async_notifier_cleanup(notifier);
1159 kfree(notifier);
1160
1161 return ret;
1162 }
1163 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
1164
1165 int v4l2_async_register_fwnode_subdev(struct v4l2_subdev *sd,
1166 size_t asd_struct_size,
1167 unsigned int *ports,
1168 unsigned int num_ports,
1169 parse_endpoint_func parse_endpoint)
1170 {
1171 struct v4l2_async_notifier *notifier;
1172 struct device *dev = sd->dev;
1173 struct fwnode_handle *fwnode;
1174 int ret;
1175
1176 if (WARN_ON(!dev))
1177 return -ENODEV;
1178
1179 fwnode = dev_fwnode(dev);
1180 if (!fwnode_device_is_available(fwnode))
1181 return -ENODEV;
1182
1183 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1184 if (!notifier)
1185 return -ENOMEM;
1186
1187 v4l2_async_notifier_init(notifier);
1188
1189 if (!ports) {
1190 ret = v4l2_async_notifier_parse_fwnode_endpoints(dev, notifier,
1191 asd_struct_size,
1192 parse_endpoint);
1193 if (ret < 0)
1194 goto out_cleanup;
1195 } else {
1196 unsigned int i;
1197
1198 for (i = 0; i < num_ports; i++) {
1199 ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev, notifier, asd_struct_size, ports[i], parse_endpoint);
1200 if (ret < 0)
1201 goto out_cleanup;
1202 }
1203 }
1204
1205 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1206 if (ret < 0)
1207 goto out_cleanup;
1208
1209 ret = v4l2_async_register_subdev(sd);
1210 if (ret < 0)
1211 goto out_unregister;
1212
1213 sd->subdev_notifier = notifier;
1214
1215 return 0;
1216
1217 out_unregister:
1218 v4l2_async_notifier_unregister(notifier);
1219 out_cleanup:
1220 v4l2_async_notifier_cleanup(notifier);
1221 kfree(notifier);
1222
1223 return ret;
1224 }
1225 EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev);
1226
1227 MODULE_LICENSE("GPL");
1228 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1229 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1230 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");