1 // SPDX-License-Identifier: GPL-2.0-only
3 * V4L2 fwnode binding parsing library
5 * The origins of the V4L2 fwnode library are in V4L2 OF library that
6 * formerly was located in v4l2-of.c.
8 * Copyright (c) 2016 Intel Corporation.
9 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
11 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
12 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
14 * Copyright (C) 2012 Renesas Electronics Corp.
15 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
17 #include <linux/acpi.h>
18 #include <linux/kernel.h>
20 #include <linux/module.h>
22 #include <linux/property.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/types.h>
27 #include <media/v4l2-async.h>
28 #include <media/v4l2-fwnode.h>
29 #include <media/v4l2-subdev.h>
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
,
42 static const struct v4l2_fwnode_bus_conv
{
43 enum v4l2_fwnode_bus_type fwnode_bus_type
;
44 enum v4l2_mbus_type mbus_type
;
48 V4L2_FWNODE_BUS_TYPE_GUESS
,
52 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY
,
56 V4L2_FWNODE_BUS_TYPE_CSI1
,
60 V4L2_FWNODE_BUS_TYPE_CCP2
,
62 "compact camera port 2",
64 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY
,
68 V4L2_FWNODE_BUS_TYPE_PARALLEL
,
72 V4L2_FWNODE_BUS_TYPE_BT656
,
78 static const struct v4l2_fwnode_bus_conv
*
79 get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type
)
83 for (i
= 0; i
< ARRAY_SIZE(buses
); i
++)
84 if (buses
[i
].fwnode_bus_type
== type
)
90 static enum v4l2_mbus_type
91 v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type
)
93 const struct v4l2_fwnode_bus_conv
*conv
=
94 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type
);
96 return conv
? conv
->mbus_type
: V4L2_MBUS_UNKNOWN
;
100 v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type
)
102 const struct v4l2_fwnode_bus_conv
*conv
=
103 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type
);
105 return conv
? conv
->name
: "not found";
108 static const struct v4l2_fwnode_bus_conv
*
109 get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type
)
113 for (i
= 0; i
< ARRAY_SIZE(buses
); i
++)
114 if (buses
[i
].mbus_type
== type
)
121 v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type
)
123 const struct v4l2_fwnode_bus_conv
*conv
=
124 get_v4l2_fwnode_bus_conv_by_mbus(type
);
126 return conv
? conv
->name
: "not found";
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
)
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
];
139 unsigned int num_data_lanes
= 0;
140 bool use_default_lane_mapping
= false;
145 if (bus_type
== V4L2_MBUS_CSI2_DPHY
||
146 bus_type
== V4L2_MBUS_CSI2_CPHY
) {
147 use_default_lane_mapping
= true;
149 num_data_lanes
= min_t(u32
, bus
->num_data_lanes
,
150 V4L2_FWNODE_CSI2_MAX_DATA_LANES
);
152 clock_lane
= bus
->clock_lane
;
154 use_default_lane_mapping
= false;
156 for (i
= 0; i
< num_data_lanes
; i
++) {
157 array
[i
] = bus
->data_lanes
[i
];
159 use_default_lane_mapping
= false;
162 if (use_default_lane_mapping
)
163 pr_debug("no lane mapping given, using defaults\n");
166 rval
= fwnode_property_read_u32_array(fwnode
, "data-lanes", NULL
, 0);
169 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES
, rval
);
171 fwnode_property_read_u32_array(fwnode
, "data-lanes", array
,
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;
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",
186 use_default_lane_mapping
= true;
188 lanes_used
|= BIT(array
[i
]);
191 pr_debug("lane %u position %u\n", i
, array
[i
]);
194 rval
= fwnode_property_read_u32_array(fwnode
, "lane-polarities", NULL
,
197 if (rval
!= 1 + num_data_lanes
/* clock+data */) {
198 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
199 1 + num_data_lanes
, rval
);
203 have_lane_polarities
= true;
206 if (!fwnode_property_read_u32(fwnode
, "clock-lanes", &v
)) {
208 pr_debug("clock lane position %u\n", v
);
209 have_clk_lane
= true;
212 if (have_clk_lane
&& lanes_used
& BIT(clock_lane
) &&
213 !use_default_lane_mapping
) {
214 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
216 use_default_lane_mapping
= true;
219 if (fwnode_property_present(fwnode
, "clock-noncontinuous")) {
220 flags
|= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK
;
221 pr_debug("non-continuous clock\n");
223 flags
|= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK
;
226 if (bus_type
== V4L2_MBUS_CSI2_DPHY
||
227 bus_type
== V4L2_MBUS_CSI2_CPHY
|| lanes_used
||
228 have_clk_lane
|| (flags
& ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK
)) {
229 /* Only D-PHY has a clock lane. */
230 unsigned int dfl_data_lane_index
=
231 bus_type
== V4L2_MBUS_CSI2_DPHY
;
234 if (bus_type
== V4L2_MBUS_UNKNOWN
)
235 vep
->bus_type
= V4L2_MBUS_CSI2_DPHY
;
236 bus
->num_data_lanes
= num_data_lanes
;
238 if (use_default_lane_mapping
) {
240 for (i
= 0; i
< num_data_lanes
; i
++)
241 bus
->data_lanes
[i
] = dfl_data_lane_index
+ i
;
243 bus
->clock_lane
= clock_lane
;
244 for (i
= 0; i
< num_data_lanes
; i
++)
245 bus
->data_lanes
[i
] = array
[i
];
248 if (have_lane_polarities
) {
249 fwnode_property_read_u32_array(fwnode
,
250 "lane-polarities", array
,
253 for (i
= 0; i
< 1 + num_data_lanes
; i
++) {
254 bus
->lane_polarities
[i
] = array
[i
];
255 pr_debug("lane %u polarity %sinverted",
256 i
, array
[i
] ? "" : "not ");
259 pr_debug("no lane polarities defined, assuming not inverted\n");
266 #define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
267 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
268 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
269 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
270 V4L2_MBUS_FIELD_EVEN_HIGH | \
271 V4L2_MBUS_FIELD_EVEN_LOW)
274 v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle
*fwnode
,
275 struct v4l2_fwnode_endpoint
*vep
,
276 enum v4l2_mbus_type bus_type
)
278 struct v4l2_fwnode_bus_parallel
*bus
= &vep
->bus
.parallel
;
279 unsigned int flags
= 0;
282 if (bus_type
== V4L2_MBUS_PARALLEL
|| bus_type
== V4L2_MBUS_BT656
)
285 if (!fwnode_property_read_u32(fwnode
, "hsync-active", &v
)) {
286 flags
&= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH
|
287 V4L2_MBUS_HSYNC_ACTIVE_LOW
);
288 flags
|= v
? V4L2_MBUS_HSYNC_ACTIVE_HIGH
:
289 V4L2_MBUS_HSYNC_ACTIVE_LOW
;
290 pr_debug("hsync-active %s\n", v
? "high" : "low");
293 if (!fwnode_property_read_u32(fwnode
, "vsync-active", &v
)) {
294 flags
&= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH
|
295 V4L2_MBUS_VSYNC_ACTIVE_LOW
);
296 flags
|= v
? V4L2_MBUS_VSYNC_ACTIVE_HIGH
:
297 V4L2_MBUS_VSYNC_ACTIVE_LOW
;
298 pr_debug("vsync-active %s\n", v
? "high" : "low");
301 if (!fwnode_property_read_u32(fwnode
, "field-even-active", &v
)) {
302 flags
&= ~(V4L2_MBUS_FIELD_EVEN_HIGH
|
303 V4L2_MBUS_FIELD_EVEN_LOW
);
304 flags
|= v
? V4L2_MBUS_FIELD_EVEN_HIGH
:
305 V4L2_MBUS_FIELD_EVEN_LOW
;
306 pr_debug("field-even-active %s\n", v
? "high" : "low");
309 if (!fwnode_property_read_u32(fwnode
, "pclk-sample", &v
)) {
310 flags
&= ~(V4L2_MBUS_PCLK_SAMPLE_RISING
|
311 V4L2_MBUS_PCLK_SAMPLE_FALLING
);
312 flags
|= v
? V4L2_MBUS_PCLK_SAMPLE_RISING
:
313 V4L2_MBUS_PCLK_SAMPLE_FALLING
;
314 pr_debug("pclk-sample %s\n", v
? "high" : "low");
317 if (!fwnode_property_read_u32(fwnode
, "data-active", &v
)) {
318 flags
&= ~(V4L2_MBUS_DATA_ACTIVE_HIGH
|
319 V4L2_MBUS_DATA_ACTIVE_LOW
);
320 flags
|= v
? V4L2_MBUS_DATA_ACTIVE_HIGH
:
321 V4L2_MBUS_DATA_ACTIVE_LOW
;
322 pr_debug("data-active %s\n", v
? "high" : "low");
325 if (fwnode_property_present(fwnode
, "slave-mode")) {
326 pr_debug("slave mode\n");
327 flags
&= ~V4L2_MBUS_MASTER
;
328 flags
|= V4L2_MBUS_SLAVE
;
330 flags
&= ~V4L2_MBUS_SLAVE
;
331 flags
|= V4L2_MBUS_MASTER
;
334 if (!fwnode_property_read_u32(fwnode
, "bus-width", &v
)) {
336 pr_debug("bus-width %u\n", v
);
339 if (!fwnode_property_read_u32(fwnode
, "data-shift", &v
)) {
341 pr_debug("data-shift %u\n", v
);
344 if (!fwnode_property_read_u32(fwnode
, "sync-on-green-active", &v
)) {
345 flags
&= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH
|
346 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW
);
347 flags
|= v
? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH
:
348 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW
;
349 pr_debug("sync-on-green-active %s\n", v
? "high" : "low");
352 if (!fwnode_property_read_u32(fwnode
, "data-enable-active", &v
)) {
353 flags
&= ~(V4L2_MBUS_DATA_ENABLE_HIGH
|
354 V4L2_MBUS_DATA_ENABLE_LOW
);
355 flags
|= v
? V4L2_MBUS_DATA_ENABLE_HIGH
:
356 V4L2_MBUS_DATA_ENABLE_LOW
;
357 pr_debug("data-enable-active %s\n", v
? "high" : "low");
363 if (flags
& PARALLEL_MBUS_FLAGS
)
364 vep
->bus_type
= V4L2_MBUS_PARALLEL
;
366 vep
->bus_type
= V4L2_MBUS_BT656
;
368 case V4L2_MBUS_PARALLEL
:
369 vep
->bus_type
= V4L2_MBUS_PARALLEL
;
372 case V4L2_MBUS_BT656
:
373 vep
->bus_type
= V4L2_MBUS_BT656
;
374 bus
->flags
= flags
& ~PARALLEL_MBUS_FLAGS
;
380 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle
*fwnode
,
381 struct v4l2_fwnode_endpoint
*vep
,
382 enum v4l2_mbus_type bus_type
)
384 struct v4l2_fwnode_bus_mipi_csi1
*bus
= &vep
->bus
.mipi_csi1
;
387 if (!fwnode_property_read_u32(fwnode
, "clock-inv", &v
)) {
389 pr_debug("clock-inv %u\n", v
);
392 if (!fwnode_property_read_u32(fwnode
, "strobe", &v
)) {
394 pr_debug("strobe %u\n", v
);
397 if (!fwnode_property_read_u32(fwnode
, "data-lanes", &v
)) {
399 pr_debug("data-lanes %u\n", v
);
402 if (!fwnode_property_read_u32(fwnode
, "clock-lanes", &v
)) {
404 pr_debug("clock-lanes %u\n", v
);
407 if (bus_type
== V4L2_MBUS_CCP2
)
408 vep
->bus_type
= V4L2_MBUS_CCP2
;
410 vep
->bus_type
= V4L2_MBUS_CSI1
;
413 static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle
*fwnode
,
414 struct v4l2_fwnode_endpoint
*vep
)
416 u32 bus_type
= V4L2_FWNODE_BUS_TYPE_GUESS
;
417 enum v4l2_mbus_type mbus_type
;
420 if (vep
->bus_type
== V4L2_MBUS_UNKNOWN
) {
421 /* Zero fields from bus union to until the end */
423 sizeof(*vep
) - offsetof(typeof(*vep
), bus
));
426 pr_debug("===== begin V4L2 endpoint properties\n");
429 * Zero the fwnode graph endpoint memory in case we don't end up parsing
432 memset(&vep
->base
, 0, sizeof(vep
->base
));
434 fwnode_property_read_u32(fwnode
, "bus-type", &bus_type
);
435 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
436 v4l2_fwnode_bus_type_to_string(bus_type
), bus_type
,
437 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
),
439 mbus_type
= v4l2_fwnode_bus_type_to_mbus(bus_type
);
441 if (vep
->bus_type
!= V4L2_MBUS_UNKNOWN
) {
442 if (mbus_type
!= V4L2_MBUS_UNKNOWN
&&
443 vep
->bus_type
!= mbus_type
) {
444 pr_debug("expecting bus type %s\n",
445 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
));
449 vep
->bus_type
= mbus_type
;
452 switch (vep
->bus_type
) {
453 case V4L2_MBUS_UNKNOWN
:
454 rval
= v4l2_fwnode_endpoint_parse_csi2_bus(fwnode
, vep
,
459 if (vep
->bus_type
== V4L2_MBUS_UNKNOWN
)
460 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode
, vep
,
463 pr_debug("assuming media bus type %s (%u)\n",
464 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
),
470 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode
, vep
, vep
->bus_type
);
473 case V4L2_MBUS_CSI2_DPHY
:
474 case V4L2_MBUS_CSI2_CPHY
:
475 rval
= v4l2_fwnode_endpoint_parse_csi2_bus(fwnode
, vep
,
481 case V4L2_MBUS_PARALLEL
:
482 case V4L2_MBUS_BT656
:
483 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode
, vep
,
488 pr_warn("unsupported bus type %u\n", mbus_type
);
492 fwnode_graph_parse_endpoint(fwnode
, &vep
->base
);
497 int v4l2_fwnode_endpoint_parse(struct fwnode_handle
*fwnode
,
498 struct v4l2_fwnode_endpoint
*vep
)
502 ret
= __v4l2_fwnode_endpoint_parse(fwnode
, vep
);
504 pr_debug("===== end V4L2 endpoint properties\n");
508 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse
);
510 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint
*vep
)
512 if (IS_ERR_OR_NULL(vep
))
515 kfree(vep
->link_frequencies
);
517 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free
);
519 int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle
*fwnode
,
520 struct v4l2_fwnode_endpoint
*vep
)
524 rval
= __v4l2_fwnode_endpoint_parse(fwnode
, vep
);
528 rval
= fwnode_property_read_u64_array(fwnode
, "link-frequencies",
533 vep
->link_frequencies
=
534 kmalloc_array(rval
, sizeof(*vep
->link_frequencies
),
536 if (!vep
->link_frequencies
)
539 vep
->nr_of_link_frequencies
= rval
;
541 rval
= fwnode_property_read_u64_array(fwnode
,
543 vep
->link_frequencies
,
544 vep
->nr_of_link_frequencies
);
546 v4l2_fwnode_endpoint_free(vep
);
550 for (i
= 0; i
< vep
->nr_of_link_frequencies
; i
++)
551 pr_info("link-frequencies %u value %llu\n", i
,
552 vep
->link_frequencies
[i
]);
555 pr_debug("===== end V4L2 endpoint properties\n");
559 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse
);
561 int v4l2_fwnode_parse_link(struct fwnode_handle
*__fwnode
,
562 struct v4l2_fwnode_link
*link
)
564 const char *port_prop
= is_of_node(__fwnode
) ? "reg" : "port";
565 struct fwnode_handle
*fwnode
;
567 memset(link
, 0, sizeof(*link
));
569 fwnode
= fwnode_get_parent(__fwnode
);
570 fwnode_property_read_u32(fwnode
, port_prop
, &link
->local_port
);
571 fwnode
= fwnode_get_next_parent(fwnode
);
572 if (is_of_node(fwnode
) && of_node_name_eq(to_of_node(fwnode
), "ports"))
573 fwnode
= fwnode_get_next_parent(fwnode
);
574 link
->local_node
= fwnode
;
576 fwnode
= fwnode_graph_get_remote_endpoint(__fwnode
);
578 fwnode_handle_put(fwnode
);
582 fwnode
= fwnode_get_parent(fwnode
);
583 fwnode_property_read_u32(fwnode
, port_prop
, &link
->remote_port
);
584 fwnode
= fwnode_get_next_parent(fwnode
);
585 if (is_of_node(fwnode
) && of_node_name_eq(to_of_node(fwnode
), "ports"))
586 fwnode
= fwnode_get_next_parent(fwnode
);
587 link
->remote_node
= fwnode
;
591 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link
);
593 void v4l2_fwnode_put_link(struct v4l2_fwnode_link
*link
)
595 fwnode_handle_put(link
->local_node
);
596 fwnode_handle_put(link
->remote_node
);
598 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link
);
601 v4l2_async_notifier_fwnode_parse_endpoint(struct device
*dev
,
602 struct v4l2_async_notifier
*notifier
,
603 struct fwnode_handle
*endpoint
,
604 unsigned int asd_struct_size
,
605 parse_endpoint_func parse_endpoint
)
607 struct v4l2_fwnode_endpoint vep
= { .bus_type
= 0 };
608 struct v4l2_async_subdev
*asd
;
611 asd
= kzalloc(asd_struct_size
, GFP_KERNEL
);
615 asd
->match_type
= V4L2_ASYNC_MATCH_FWNODE
;
617 fwnode_graph_get_remote_port_parent(endpoint
);
618 if (!asd
->match
.fwnode
) {
619 dev_dbg(dev
, "no remote endpoint found\n");
624 ret
= v4l2_fwnode_endpoint_alloc_parse(endpoint
, &vep
);
626 dev_warn(dev
, "unable to parse V4L2 fwnode endpoint (%d)\n",
631 ret
= parse_endpoint
? parse_endpoint(dev
, &vep
, asd
) : 0;
632 if (ret
== -ENOTCONN
)
633 dev_dbg(dev
, "ignoring port@%u/endpoint@%u\n", vep
.base
.port
,
637 "driver could not parse port@%u/endpoint@%u (%d)\n",
638 vep
.base
.port
, vep
.base
.id
, ret
);
639 v4l2_fwnode_endpoint_free(&vep
);
643 ret
= v4l2_async_notifier_add_subdev(notifier
, asd
);
645 /* not an error if asd already exists */
654 fwnode_handle_put(asd
->match
.fwnode
);
657 return ret
== -ENOTCONN
? 0 : ret
;
661 __v4l2_async_notifier_parse_fwnode_ep(struct device
*dev
,
662 struct v4l2_async_notifier
*notifier
,
663 size_t asd_struct_size
,
666 parse_endpoint_func parse_endpoint
)
668 struct fwnode_handle
*fwnode
;
671 if (WARN_ON(asd_struct_size
< sizeof(struct v4l2_async_subdev
)))
674 fwnode_graph_for_each_endpoint(dev_fwnode(dev
), fwnode
) {
675 struct fwnode_handle
*dev_fwnode
;
678 dev_fwnode
= fwnode_graph_get_port_parent(fwnode
);
679 is_available
= fwnode_device_is_available(dev_fwnode
);
680 fwnode_handle_put(dev_fwnode
);
685 struct fwnode_endpoint ep
;
687 ret
= fwnode_graph_parse_endpoint(fwnode
, &ep
);
695 ret
= v4l2_async_notifier_fwnode_parse_endpoint(dev
,
704 fwnode_handle_put(fwnode
);
710 v4l2_async_notifier_parse_fwnode_endpoints(struct device
*dev
,
711 struct v4l2_async_notifier
*notifier
,
712 size_t asd_struct_size
,
713 parse_endpoint_func parse_endpoint
)
715 return __v4l2_async_notifier_parse_fwnode_ep(dev
, notifier
,
717 false, parse_endpoint
);
719 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints
);
722 v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device
*dev
,
723 struct v4l2_async_notifier
*notifier
,
724 size_t asd_struct_size
,
726 parse_endpoint_func parse_endpoint
)
728 return __v4l2_async_notifier_parse_fwnode_ep(dev
, notifier
,
733 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port
);
736 * v4l2_fwnode_reference_parse - parse references for async sub-devices
737 * @dev: the device node the properties of which are parsed for references
738 * @notifier: the async notifier where the async subdevs will be added
739 * @prop: the name of the property
741 * Return: 0 on success
742 * -ENOENT if no entries were found
743 * -ENOMEM if memory allocation failed
744 * -EINVAL if property parsing failed
746 static int v4l2_fwnode_reference_parse(struct device
*dev
,
747 struct v4l2_async_notifier
*notifier
,
750 struct fwnode_reference_args args
;
755 !(ret
= fwnode_property_get_reference_args(dev_fwnode(dev
),
759 fwnode_handle_put(args
.fwnode
);
765 * Note that right now both -ENODATA and -ENOENT may signal
766 * out-of-bounds access. Return the error in cases other than that.
768 if (ret
!= -ENOENT
&& ret
!= -ENODATA
)
772 !fwnode_property_get_reference_args(dev_fwnode(dev
), prop
, NULL
,
775 struct v4l2_async_subdev
*asd
;
777 asd
= v4l2_async_notifier_add_fwnode_subdev(notifier
,
782 /* not an error if asd already exists */
783 if (ret
== -EEXIST
) {
784 fwnode_handle_put(args
.fwnode
);
795 fwnode_handle_put(args
.fwnode
);
800 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
802 * @fwnode: fwnode to read @prop from
803 * @notifier: notifier for @dev
804 * @prop: the name of the property
805 * @index: the index of the reference to get
806 * @props: the array of integer property names
807 * @nprops: the number of integer property names in @nprops
809 * First find an fwnode referred to by the reference at @index in @prop.
811 * Then under that fwnode, @nprops times, for each property in @props,
812 * iteratively follow child nodes starting from fwnode such that they have the
813 * property in @props array at the index of the child node distance from the
814 * root node and the value of that property matching with the integer argument
815 * of the reference, at the same index.
817 * The child fwnode reached at the end of the iteration is then returned to the
820 * The core reason for this is that you cannot refer to just any node in ACPI.
821 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
822 * provide a list of (property name, property value) tuples where each tuple
823 * uniquely identifies a child node. The first tuple identifies a child directly
824 * underneath the device fwnode, the next tuple identifies a child node
825 * underneath the fwnode identified by the previous tuple, etc. until you
826 * reached the fwnode you need.
828 * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A
829 * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under
830 * Documentation/acpi/dsd instead and especially graph.txt,
831 * data-node-references.txt and leds.txt .
833 * Scope (\_SB.PCI0.I2C2)
837 * Name (_DSD, Package () {
838 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
842 * Package () { "nokia,smia" }
845 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
847 * Package () { "port0", "PRT0" },
850 * Name (PRT0, Package() {
851 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
853 * Package () { "port", 0 },
855 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
857 * Package () { "endpoint0", "EP00" },
860 * Name (EP00, Package() {
861 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
863 * Package () { "endpoint", 0 },
867 * \_SB.PCI0.ISP, 4, 0
879 * Name (_DSD, Package () {
880 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
882 * Package () { "port4", "PRT4" },
886 * Name (PRT4, Package() {
887 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
889 * Package () { "port", 4 },
891 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
893 * Package () { "endpoint0", "EP40" },
897 * Name (EP40, Package() {
898 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
900 * Package () { "endpoint", 0 },
904 * \_SB.PCI0.I2C2.CAM0,
913 * From the EP40 node under ISP device, you could parse the graph remote
914 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
916 * @fwnode: fwnode referring to EP40 under ISP.
917 * @prop: "remote-endpoint"
919 * @props: "port", "endpoint"
922 * And you'd get back fwnode referring to EP00 under CAM0.
924 * The same works the other way around: if you use EP00 under CAM0 as the
925 * fwnode, you'll get fwnode referring to EP40 under ISP.
927 * The same example in DT syntax would look like this:
930 * compatible = "nokia,smia";
936 * remote-endpoint = <&isp 4 0>;
947 * remote-endpoint = <&cam 0 0>;
953 * Return: 0 on success
954 * -ENOENT if no entries (or the property itself) were found
955 * -EINVAL if property parsing otherwise failed
956 * -ENOMEM if memory allocation failed
958 static struct fwnode_handle
*
959 v4l2_fwnode_reference_get_int_prop(struct fwnode_handle
*fwnode
,
962 const char * const *props
,
965 struct fwnode_reference_args fwnode_args
;
966 u64
*args
= fwnode_args
.args
;
967 struct fwnode_handle
*child
;
971 * Obtain remote fwnode as well as the integer arguments.
973 * Note that right now both -ENODATA and -ENOENT may signal
974 * out-of-bounds access. Return -ENOENT in that case.
976 ret
= fwnode_property_get_reference_args(fwnode
, prop
, NULL
, nprops
,
977 index
, &fwnode_args
);
979 return ERR_PTR(ret
== -ENODATA
? -ENOENT
: ret
);
982 * Find a node in the tree under the referred fwnode corresponding to
983 * the integer arguments.
985 fwnode
= fwnode_args
.fwnode
;
989 /* Loop over all child nodes under fwnode. */
990 fwnode_for_each_child_node(fwnode
, child
) {
991 if (fwnode_property_read_u32(child
, *props
, &val
))
994 /* Found property, see if its value matches. */
999 fwnode_handle_put(fwnode
);
1001 /* No property found; return an error here. */
1003 fwnode
= ERR_PTR(-ENOENT
);
1015 struct v4l2_fwnode_int_props
{
1017 const char * const *props
;
1018 unsigned int nprops
;
1022 * v4l2_fwnode_reference_parse_int_props - parse references for async
1024 * @dev: struct device pointer
1025 * @notifier: notifier for @dev
1026 * @prop: the name of the property
1027 * @props: the array of integer property names
1028 * @nprops: the number of integer properties
1030 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
1031 * property @prop with integer arguments with child nodes matching in properties
1032 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
1035 * While it is technically possible to use this function on DT, it is only
1036 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
1037 * on ACPI the references are limited to devices.
1039 * Return: 0 on success
1040 * -ENOENT if no entries (or the property itself) were found
1041 * -EINVAL if property parsing otherwisefailed
1042 * -ENOMEM if memory allocation failed
1045 v4l2_fwnode_reference_parse_int_props(struct device
*dev
,
1046 struct v4l2_async_notifier
*notifier
,
1047 const struct v4l2_fwnode_int_props
*p
)
1049 struct fwnode_handle
*fwnode
;
1052 const char *prop
= p
->name
;
1053 const char * const *props
= p
->props
;
1054 unsigned int nprops
= p
->nprops
;
1058 fwnode
= v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev
),
1061 if (IS_ERR(fwnode
)) {
1063 * Note that right now both -ENODATA and -ENOENT may
1064 * signal out-of-bounds access. Return the error in
1065 * cases other than that.
1067 if (PTR_ERR(fwnode
) != -ENOENT
&&
1068 PTR_ERR(fwnode
) != -ENODATA
)
1069 return PTR_ERR(fwnode
);
1072 fwnode_handle_put(fwnode
);
1077 !IS_ERR((fwnode
= v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev
),
1082 struct v4l2_async_subdev
*asd
;
1084 asd
= v4l2_async_notifier_add_fwnode_subdev(notifier
, fwnode
,
1088 /* not an error if asd already exists */
1089 if (ret
== -EEXIST
) {
1090 fwnode_handle_put(fwnode
);
1098 return !fwnode
|| PTR_ERR(fwnode
) == -ENOENT
? 0 : PTR_ERR(fwnode
);
1101 fwnode_handle_put(fwnode
);
1105 int v4l2_async_notifier_parse_fwnode_sensor_common(struct device
*dev
,
1106 struct v4l2_async_notifier
*notifier
)
1108 static const char * const led_props
[] = { "led" };
1109 static const struct v4l2_fwnode_int_props props
[] = {
1110 { "flash-leds", led_props
, ARRAY_SIZE(led_props
) },
1111 { "lens-focus", NULL
, 0 },
1115 for (i
= 0; i
< ARRAY_SIZE(props
); i
++) {
1118 if (props
[i
].props
&& is_acpi_node(dev_fwnode(dev
)))
1119 ret
= v4l2_fwnode_reference_parse_int_props(dev
,
1123 ret
= v4l2_fwnode_reference_parse(dev
, notifier
,
1125 if (ret
&& ret
!= -ENOENT
) {
1126 dev_warn(dev
, "parsing property \"%s\" failed (%d)\n",
1127 props
[i
].name
, ret
);
1134 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common
);
1136 int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev
*sd
)
1138 struct v4l2_async_notifier
*notifier
;
1141 if (WARN_ON(!sd
->dev
))
1144 notifier
= kzalloc(sizeof(*notifier
), GFP_KERNEL
);
1148 v4l2_async_notifier_init(notifier
);
1150 ret
= v4l2_async_notifier_parse_fwnode_sensor_common(sd
->dev
,
1155 ret
= v4l2_async_subdev_notifier_register(sd
, notifier
);
1159 ret
= v4l2_async_register_subdev(sd
);
1161 goto out_unregister
;
1163 sd
->subdev_notifier
= notifier
;
1168 v4l2_async_notifier_unregister(notifier
);
1171 v4l2_async_notifier_cleanup(notifier
);
1176 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common
);
1178 int v4l2_async_register_fwnode_subdev(struct v4l2_subdev
*sd
,
1179 size_t asd_struct_size
,
1180 unsigned int *ports
,
1181 unsigned int num_ports
,
1182 parse_endpoint_func parse_endpoint
)
1184 struct v4l2_async_notifier
*notifier
;
1185 struct device
*dev
= sd
->dev
;
1186 struct fwnode_handle
*fwnode
;
1192 fwnode
= dev_fwnode(dev
);
1193 if (!fwnode_device_is_available(fwnode
))
1196 notifier
= kzalloc(sizeof(*notifier
), GFP_KERNEL
);
1200 v4l2_async_notifier_init(notifier
);
1203 ret
= v4l2_async_notifier_parse_fwnode_endpoints(dev
, notifier
,
1211 for (i
= 0; i
< num_ports
; i
++) {
1212 ret
= v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev
, notifier
, asd_struct_size
, ports
[i
], parse_endpoint
);
1218 ret
= v4l2_async_subdev_notifier_register(sd
, notifier
);
1222 ret
= v4l2_async_register_subdev(sd
);
1224 goto out_unregister
;
1226 sd
->subdev_notifier
= notifier
;
1231 v4l2_async_notifier_unregister(notifier
);
1233 v4l2_async_notifier_cleanup(notifier
);
1238 EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev
);
1240 MODULE_LICENSE("GPL");
1241 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1242 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1243 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");