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_INVALID
;
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_count_u32(fwnode
, "data-lanes");
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_count_u32(fwnode
, "lane-polarities");
196 if (rval
!= 1 + num_data_lanes
/* clock+data */) {
197 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
198 1 + num_data_lanes
, rval
);
202 have_lane_polarities
= true;
205 if (!fwnode_property_read_u32(fwnode
, "clock-lanes", &v
)) {
207 pr_debug("clock lane position %u\n", v
);
208 have_clk_lane
= true;
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",
215 use_default_lane_mapping
= true;
218 if (fwnode_property_present(fwnode
, "clock-noncontinuous")) {
219 flags
|= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK
;
220 pr_debug("non-continuous clock\n");
222 flags
|= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK
;
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 /* Only D-PHY has a clock lane. */
229 unsigned int dfl_data_lane_index
=
230 bus_type
== V4L2_MBUS_CSI2_DPHY
;
233 if (bus_type
== V4L2_MBUS_UNKNOWN
)
234 vep
->bus_type
= V4L2_MBUS_CSI2_DPHY
;
235 bus
->num_data_lanes
= num_data_lanes
;
237 if (use_default_lane_mapping
) {
239 for (i
= 0; i
< num_data_lanes
; i
++)
240 bus
->data_lanes
[i
] = dfl_data_lane_index
+ i
;
242 bus
->clock_lane
= clock_lane
;
243 for (i
= 0; i
< num_data_lanes
; i
++)
244 bus
->data_lanes
[i
] = array
[i
];
247 if (have_lane_polarities
) {
248 fwnode_property_read_u32_array(fwnode
,
249 "lane-polarities", array
,
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 ");
258 pr_debug("no lane polarities defined, assuming not inverted\n");
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)
273 v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle
*fwnode
,
274 struct v4l2_fwnode_endpoint
*vep
,
275 enum v4l2_mbus_type bus_type
)
277 struct v4l2_fwnode_bus_parallel
*bus
= &vep
->bus
.parallel
;
278 unsigned int flags
= 0;
281 if (bus_type
== V4L2_MBUS_PARALLEL
|| bus_type
== V4L2_MBUS_BT656
)
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");
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");
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");
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");
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");
324 if (fwnode_property_present(fwnode
, "slave-mode")) {
325 pr_debug("slave mode\n");
326 flags
&= ~V4L2_MBUS_MASTER
;
327 flags
|= V4L2_MBUS_SLAVE
;
329 flags
&= ~V4L2_MBUS_SLAVE
;
330 flags
|= V4L2_MBUS_MASTER
;
333 if (!fwnode_property_read_u32(fwnode
, "bus-width", &v
)) {
335 pr_debug("bus-width %u\n", v
);
338 if (!fwnode_property_read_u32(fwnode
, "data-shift", &v
)) {
340 pr_debug("data-shift %u\n", v
);
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");
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");
362 if (flags
& PARALLEL_MBUS_FLAGS
)
363 vep
->bus_type
= V4L2_MBUS_PARALLEL
;
365 vep
->bus_type
= V4L2_MBUS_BT656
;
367 case V4L2_MBUS_PARALLEL
:
368 vep
->bus_type
= V4L2_MBUS_PARALLEL
;
371 case V4L2_MBUS_BT656
:
372 vep
->bus_type
= V4L2_MBUS_BT656
;
373 bus
->flags
= flags
& ~PARALLEL_MBUS_FLAGS
;
379 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle
*fwnode
,
380 struct v4l2_fwnode_endpoint
*vep
,
381 enum v4l2_mbus_type bus_type
)
383 struct v4l2_fwnode_bus_mipi_csi1
*bus
= &vep
->bus
.mipi_csi1
;
386 if (!fwnode_property_read_u32(fwnode
, "clock-inv", &v
)) {
388 pr_debug("clock-inv %u\n", v
);
391 if (!fwnode_property_read_u32(fwnode
, "strobe", &v
)) {
393 pr_debug("strobe %u\n", v
);
396 if (!fwnode_property_read_u32(fwnode
, "data-lanes", &v
)) {
398 pr_debug("data-lanes %u\n", v
);
401 if (!fwnode_property_read_u32(fwnode
, "clock-lanes", &v
)) {
403 pr_debug("clock-lanes %u\n", v
);
406 if (bus_type
== V4L2_MBUS_CCP2
)
407 vep
->bus_type
= V4L2_MBUS_CCP2
;
409 vep
->bus_type
= V4L2_MBUS_CSI1
;
412 static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle
*fwnode
,
413 struct v4l2_fwnode_endpoint
*vep
)
415 u32 bus_type
= V4L2_FWNODE_BUS_TYPE_GUESS
;
416 enum v4l2_mbus_type mbus_type
;
419 pr_debug("===== begin parsing endpoint %pfw\n", fwnode
);
421 fwnode_property_read_u32(fwnode
, "bus-type", &bus_type
);
422 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
423 v4l2_fwnode_bus_type_to_string(bus_type
), bus_type
,
424 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
),
426 mbus_type
= v4l2_fwnode_bus_type_to_mbus(bus_type
);
427 if (mbus_type
== V4L2_MBUS_INVALID
) {
428 pr_debug("unsupported bus type %u\n", bus_type
);
432 if (vep
->bus_type
!= V4L2_MBUS_UNKNOWN
) {
433 if (mbus_type
!= V4L2_MBUS_UNKNOWN
&&
434 vep
->bus_type
!= mbus_type
) {
435 pr_debug("expecting bus type %s\n",
436 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
));
440 vep
->bus_type
= mbus_type
;
443 switch (vep
->bus_type
) {
444 case V4L2_MBUS_UNKNOWN
:
445 rval
= v4l2_fwnode_endpoint_parse_csi2_bus(fwnode
, vep
,
450 if (vep
->bus_type
== V4L2_MBUS_UNKNOWN
)
451 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode
, vep
,
454 pr_debug("assuming media bus type %s (%u)\n",
455 v4l2_fwnode_mbus_type_to_string(vep
->bus_type
),
461 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode
, vep
, vep
->bus_type
);
464 case V4L2_MBUS_CSI2_DPHY
:
465 case V4L2_MBUS_CSI2_CPHY
:
466 rval
= v4l2_fwnode_endpoint_parse_csi2_bus(fwnode
, vep
,
472 case V4L2_MBUS_PARALLEL
:
473 case V4L2_MBUS_BT656
:
474 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode
, vep
,
479 pr_warn("unsupported bus type %u\n", mbus_type
);
483 fwnode_graph_parse_endpoint(fwnode
, &vep
->base
);
488 int v4l2_fwnode_endpoint_parse(struct fwnode_handle
*fwnode
,
489 struct v4l2_fwnode_endpoint
*vep
)
493 ret
= __v4l2_fwnode_endpoint_parse(fwnode
, vep
);
495 pr_debug("===== end parsing endpoint %pfw\n", fwnode
);
499 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse
);
501 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint
*vep
)
503 if (IS_ERR_OR_NULL(vep
))
506 kfree(vep
->link_frequencies
);
507 vep
->link_frequencies
= NULL
;
509 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free
);
511 int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle
*fwnode
,
512 struct v4l2_fwnode_endpoint
*vep
)
516 rval
= __v4l2_fwnode_endpoint_parse(fwnode
, vep
);
520 rval
= fwnode_property_count_u64(fwnode
, "link-frequencies");
524 vep
->link_frequencies
=
525 kmalloc_array(rval
, sizeof(*vep
->link_frequencies
),
527 if (!vep
->link_frequencies
)
530 vep
->nr_of_link_frequencies
= rval
;
532 rval
= fwnode_property_read_u64_array(fwnode
,
534 vep
->link_frequencies
,
535 vep
->nr_of_link_frequencies
);
537 v4l2_fwnode_endpoint_free(vep
);
541 for (i
= 0; i
< vep
->nr_of_link_frequencies
; i
++)
542 pr_debug("link-frequencies %u value %llu\n", i
,
543 vep
->link_frequencies
[i
]);
546 pr_debug("===== end parsing endpoint %pfw\n", fwnode
);
550 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse
);
552 int v4l2_fwnode_parse_link(struct fwnode_handle
*fwnode
,
553 struct v4l2_fwnode_link
*link
)
555 struct fwnode_endpoint fwep
;
557 memset(link
, 0, sizeof(*link
));
559 fwnode_graph_parse_endpoint(fwnode
, &fwep
);
560 link
->local_id
= fwep
.id
;
561 link
->local_port
= fwep
.port
;
562 link
->local_node
= fwnode_graph_get_port_parent(fwnode
);
564 fwnode
= fwnode_graph_get_remote_endpoint(fwnode
);
566 fwnode_handle_put(fwnode
);
570 fwnode_graph_parse_endpoint(fwnode
, &fwep
);
571 link
->remote_id
= fwep
.id
;
572 link
->remote_port
= fwep
.port
;
573 link
->remote_node
= fwnode_graph_get_port_parent(fwnode
);
577 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link
);
579 void v4l2_fwnode_put_link(struct v4l2_fwnode_link
*link
)
581 fwnode_handle_put(link
->local_node
);
582 fwnode_handle_put(link
->remote_node
);
584 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link
);
586 static const struct v4l2_fwnode_connector_conv
{
587 enum v4l2_connector_type type
;
588 const char *compatible
;
591 .type
= V4L2_CONN_COMPOSITE
,
592 .compatible
= "composite-video-connector",
594 .type
= V4L2_CONN_SVIDEO
,
595 .compatible
= "svideo-connector",
599 static enum v4l2_connector_type
600 v4l2_fwnode_string_to_connector_type(const char *con_str
)
604 for (i
= 0; i
< ARRAY_SIZE(connectors
); i
++)
605 if (!strcmp(con_str
, connectors
[i
].compatible
))
606 return connectors
[i
].type
;
608 return V4L2_CONN_UNKNOWN
;
612 v4l2_fwnode_connector_parse_analog(struct fwnode_handle
*fwnode
,
613 struct v4l2_fwnode_connector
*vc
)
618 ret
= fwnode_property_read_u32(fwnode
, "sdtv-standards", &stds
);
620 /* The property is optional. */
621 vc
->connector
.analog
.sdtv_stds
= ret
? V4L2_STD_ALL
: stds
;
624 void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector
*connector
)
626 struct v4l2_connector_link
*link
, *tmp
;
628 if (IS_ERR_OR_NULL(connector
) || connector
->type
== V4L2_CONN_UNKNOWN
)
631 list_for_each_entry_safe(link
, tmp
, &connector
->links
, head
) {
632 v4l2_fwnode_put_link(&link
->fwnode_link
);
633 list_del(&link
->head
);
637 kfree(connector
->label
);
638 connector
->label
= NULL
;
639 connector
->type
= V4L2_CONN_UNKNOWN
;
641 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free
);
643 static enum v4l2_connector_type
644 v4l2_fwnode_get_connector_type(struct fwnode_handle
*fwnode
)
646 const char *type_name
;
650 return V4L2_CONN_UNKNOWN
;
652 /* The connector-type is stored within the compatible string. */
653 err
= fwnode_property_read_string(fwnode
, "compatible", &type_name
);
655 return V4L2_CONN_UNKNOWN
;
657 return v4l2_fwnode_string_to_connector_type(type_name
);
660 int v4l2_fwnode_connector_parse(struct fwnode_handle
*fwnode
,
661 struct v4l2_fwnode_connector
*connector
)
663 struct fwnode_handle
*connector_node
;
664 enum v4l2_connector_type connector_type
;
671 memset(connector
, 0, sizeof(*connector
));
673 INIT_LIST_HEAD(&connector
->links
);
675 connector_node
= fwnode_graph_get_port_parent(fwnode
);
676 connector_type
= v4l2_fwnode_get_connector_type(connector_node
);
677 if (connector_type
== V4L2_CONN_UNKNOWN
) {
678 fwnode_handle_put(connector_node
);
679 connector_node
= fwnode_graph_get_remote_port_parent(fwnode
);
680 connector_type
= v4l2_fwnode_get_connector_type(connector_node
);
683 if (connector_type
== V4L2_CONN_UNKNOWN
) {
684 pr_err("Unknown connector type\n");
689 connector
->type
= connector_type
;
690 connector
->name
= fwnode_get_name(connector_node
);
691 err
= fwnode_property_read_string(connector_node
, "label", &label
);
692 connector
->label
= err
? NULL
: kstrdup_const(label
, GFP_KERNEL
);
694 /* Parse the connector specific properties. */
695 switch (connector
->type
) {
696 case V4L2_CONN_COMPOSITE
:
697 case V4L2_CONN_SVIDEO
:
698 v4l2_fwnode_connector_parse_analog(connector_node
, connector
);
700 /* Avoid compiler warnings */
701 case V4L2_CONN_UNKNOWN
:
706 fwnode_handle_put(connector_node
);
710 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse
);
712 int v4l2_fwnode_connector_add_link(struct fwnode_handle
*fwnode
,
713 struct v4l2_fwnode_connector
*connector
)
715 struct fwnode_handle
*connector_ep
;
716 struct v4l2_connector_link
*link
;
719 if (!fwnode
|| !connector
|| connector
->type
== V4L2_CONN_UNKNOWN
)
722 connector_ep
= fwnode_graph_get_remote_endpoint(fwnode
);
726 link
= kzalloc(sizeof(*link
), GFP_KERNEL
);
732 err
= v4l2_fwnode_parse_link(connector_ep
, &link
->fwnode_link
);
736 fwnode_handle_put(connector_ep
);
738 list_add(&link
->head
, &connector
->links
);
739 connector
->nr_of_links
++;
745 fwnode_handle_put(connector_ep
);
749 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link
);
751 int v4l2_fwnode_device_parse(struct device
*dev
,
752 struct v4l2_fwnode_device_properties
*props
)
754 struct fwnode_handle
*fwnode
= dev_fwnode(dev
);
758 memset(props
, 0, sizeof(*props
));
760 props
->orientation
= V4L2_FWNODE_PROPERTY_UNSET
;
761 ret
= fwnode_property_read_u32(fwnode
, "orientation", &val
);
764 case V4L2_FWNODE_ORIENTATION_FRONT
:
765 case V4L2_FWNODE_ORIENTATION_BACK
:
766 case V4L2_FWNODE_ORIENTATION_EXTERNAL
:
769 dev_warn(dev
, "Unsupported device orientation: %u\n", val
);
773 props
->orientation
= val
;
774 dev_dbg(dev
, "device orientation: %u\n", val
);
777 props
->rotation
= V4L2_FWNODE_PROPERTY_UNSET
;
778 ret
= fwnode_property_read_u32(fwnode
, "rotation", &val
);
781 dev_warn(dev
, "Unsupported device rotation: %u\n", val
);
785 props
->rotation
= val
;
786 dev_dbg(dev
, "device rotation: %u\n", val
);
791 EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse
);
794 v4l2_async_notifier_fwnode_parse_endpoint(struct device
*dev
,
795 struct v4l2_async_notifier
*notifier
,
796 struct fwnode_handle
*endpoint
,
797 unsigned int asd_struct_size
,
798 parse_endpoint_func parse_endpoint
)
800 struct v4l2_fwnode_endpoint vep
= { .bus_type
= 0 };
801 struct v4l2_async_subdev
*asd
;
804 asd
= kzalloc(asd_struct_size
, GFP_KERNEL
);
808 asd
->match_type
= V4L2_ASYNC_MATCH_FWNODE
;
810 fwnode_graph_get_remote_port_parent(endpoint
);
811 if (!asd
->match
.fwnode
) {
812 dev_dbg(dev
, "no remote endpoint found\n");
817 ret
= v4l2_fwnode_endpoint_alloc_parse(endpoint
, &vep
);
819 dev_warn(dev
, "unable to parse V4L2 fwnode endpoint (%d)\n",
824 ret
= parse_endpoint
? parse_endpoint(dev
, &vep
, asd
) : 0;
825 if (ret
== -ENOTCONN
)
826 dev_dbg(dev
, "ignoring port@%u/endpoint@%u\n", vep
.base
.port
,
830 "driver could not parse port@%u/endpoint@%u (%d)\n",
831 vep
.base
.port
, vep
.base
.id
, ret
);
832 v4l2_fwnode_endpoint_free(&vep
);
836 ret
= v4l2_async_notifier_add_subdev(notifier
, asd
);
838 /* not an error if asd already exists */
847 fwnode_handle_put(asd
->match
.fwnode
);
850 return ret
== -ENOTCONN
? 0 : ret
;
854 __v4l2_async_notifier_parse_fwnode_ep(struct device
*dev
,
855 struct v4l2_async_notifier
*notifier
,
856 size_t asd_struct_size
,
859 parse_endpoint_func parse_endpoint
)
861 struct fwnode_handle
*fwnode
;
864 if (WARN_ON(asd_struct_size
< sizeof(struct v4l2_async_subdev
)))
867 fwnode_graph_for_each_endpoint(dev_fwnode(dev
), fwnode
) {
868 struct fwnode_handle
*dev_fwnode
;
871 dev_fwnode
= fwnode_graph_get_port_parent(fwnode
);
872 is_available
= fwnode_device_is_available(dev_fwnode
);
873 fwnode_handle_put(dev_fwnode
);
878 struct fwnode_endpoint ep
;
880 ret
= fwnode_graph_parse_endpoint(fwnode
, &ep
);
888 ret
= v4l2_async_notifier_fwnode_parse_endpoint(dev
,
897 fwnode_handle_put(fwnode
);
903 v4l2_async_notifier_parse_fwnode_endpoints(struct device
*dev
,
904 struct v4l2_async_notifier
*notifier
,
905 size_t asd_struct_size
,
906 parse_endpoint_func parse_endpoint
)
908 return __v4l2_async_notifier_parse_fwnode_ep(dev
, notifier
,
910 false, parse_endpoint
);
912 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints
);
915 * v4l2_fwnode_reference_parse - parse references for async sub-devices
916 * @dev: the device node the properties of which are parsed for references
917 * @notifier: the async notifier where the async subdevs will be added
918 * @prop: the name of the property
920 * Return: 0 on success
921 * -ENOENT if no entries were found
922 * -ENOMEM if memory allocation failed
923 * -EINVAL if property parsing failed
925 static int v4l2_fwnode_reference_parse(struct device
*dev
,
926 struct v4l2_async_notifier
*notifier
,
929 struct fwnode_reference_args args
;
934 !(ret
= fwnode_property_get_reference_args(dev_fwnode(dev
),
938 fwnode_handle_put(args
.fwnode
);
944 * Note that right now both -ENODATA and -ENOENT may signal
945 * out-of-bounds access. Return the error in cases other than that.
947 if (ret
!= -ENOENT
&& ret
!= -ENODATA
)
951 !fwnode_property_get_reference_args(dev_fwnode(dev
), prop
, NULL
,
954 struct v4l2_async_subdev
*asd
;
956 asd
= v4l2_async_notifier_add_fwnode_subdev(notifier
,
959 fwnode_handle_put(args
.fwnode
);
961 /* not an error if asd already exists */
962 if (PTR_ERR(asd
) == -EEXIST
)
973 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
975 * @fwnode: fwnode to read @prop from
976 * @notifier: notifier for @dev
977 * @prop: the name of the property
978 * @index: the index of the reference to get
979 * @props: the array of integer property names
980 * @nprops: the number of integer property names in @nprops
982 * First find an fwnode referred to by the reference at @index in @prop.
984 * Then under that fwnode, @nprops times, for each property in @props,
985 * iteratively follow child nodes starting from fwnode such that they have the
986 * property in @props array at the index of the child node distance from the
987 * root node and the value of that property matching with the integer argument
988 * of the reference, at the same index.
990 * The child fwnode reached at the end of the iteration is then returned to the
993 * The core reason for this is that you cannot refer to just any node in ACPI.
994 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
995 * provide a list of (property name, property value) tuples where each tuple
996 * uniquely identifies a child node. The first tuple identifies a child directly
997 * underneath the device fwnode, the next tuple identifies a child node
998 * underneath the fwnode identified by the previous tuple, etc. until you
999 * reached the fwnode you need.
1001 * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A
1002 * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under
1003 * Documentation/firmware-guide/acpi/dsd/ instead and especially graph.txt,
1004 * data-node-references.txt and leds.txt .
1006 * Scope (\_SB.PCI0.I2C2)
1010 * Name (_DSD, Package () {
1011 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1015 * Package () { "nokia,smia" }
1018 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1020 * Package () { "port0", "PRT0" },
1023 * Name (PRT0, Package() {
1024 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1026 * Package () { "port", 0 },
1028 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1030 * Package () { "endpoint0", "EP00" },
1033 * Name (EP00, Package() {
1034 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1036 * Package () { "endpoint", 0 },
1038 * "remote-endpoint",
1040 * \_SB.PCI0.ISP, 4, 0
1052 * Name (_DSD, Package () {
1053 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1055 * Package () { "port4", "PRT4" },
1059 * Name (PRT4, Package() {
1060 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1062 * Package () { "port", 4 },
1064 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1066 * Package () { "endpoint0", "EP40" },
1070 * Name (EP40, Package() {
1071 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1073 * Package () { "endpoint", 0 },
1075 * "remote-endpoint",
1077 * \_SB.PCI0.I2C2.CAM0,
1086 * From the EP40 node under ISP device, you could parse the graph remote
1087 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
1089 * @fwnode: fwnode referring to EP40 under ISP.
1090 * @prop: "remote-endpoint"
1092 * @props: "port", "endpoint"
1095 * And you'd get back fwnode referring to EP00 under CAM0.
1097 * The same works the other way around: if you use EP00 under CAM0 as the
1098 * fwnode, you'll get fwnode referring to EP40 under ISP.
1100 * The same example in DT syntax would look like this:
1103 * compatible = "nokia,smia";
1109 * remote-endpoint = <&isp 4 0>;
1120 * remote-endpoint = <&cam 0 0>;
1126 * Return: 0 on success
1127 * -ENOENT if no entries (or the property itself) were found
1128 * -EINVAL if property parsing otherwise failed
1129 * -ENOMEM if memory allocation failed
1131 static struct fwnode_handle
*
1132 v4l2_fwnode_reference_get_int_prop(struct fwnode_handle
*fwnode
,
1135 const char * const *props
,
1136 unsigned int nprops
)
1138 struct fwnode_reference_args fwnode_args
;
1139 u64
*args
= fwnode_args
.args
;
1140 struct fwnode_handle
*child
;
1144 * Obtain remote fwnode as well as the integer arguments.
1146 * Note that right now both -ENODATA and -ENOENT may signal
1147 * out-of-bounds access. Return -ENOENT in that case.
1149 ret
= fwnode_property_get_reference_args(fwnode
, prop
, NULL
, nprops
,
1150 index
, &fwnode_args
);
1152 return ERR_PTR(ret
== -ENODATA
? -ENOENT
: ret
);
1155 * Find a node in the tree under the referred fwnode corresponding to
1156 * the integer arguments.
1158 fwnode
= fwnode_args
.fwnode
;
1162 /* Loop over all child nodes under fwnode. */
1163 fwnode_for_each_child_node(fwnode
, child
) {
1164 if (fwnode_property_read_u32(child
, *props
, &val
))
1167 /* Found property, see if its value matches. */
1172 fwnode_handle_put(fwnode
);
1174 /* No property found; return an error here. */
1176 fwnode
= ERR_PTR(-ENOENT
);
1188 struct v4l2_fwnode_int_props
{
1190 const char * const *props
;
1191 unsigned int nprops
;
1195 * v4l2_fwnode_reference_parse_int_props - parse references for async
1197 * @dev: struct device pointer
1198 * @notifier: notifier for @dev
1199 * @prop: the name of the property
1200 * @props: the array of integer property names
1201 * @nprops: the number of integer properties
1203 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
1204 * property @prop with integer arguments with child nodes matching in properties
1205 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
1208 * While it is technically possible to use this function on DT, it is only
1209 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
1210 * on ACPI the references are limited to devices.
1212 * Return: 0 on success
1213 * -ENOENT if no entries (or the property itself) were found
1214 * -EINVAL if property parsing otherwisefailed
1215 * -ENOMEM if memory allocation failed
1218 v4l2_fwnode_reference_parse_int_props(struct device
*dev
,
1219 struct v4l2_async_notifier
*notifier
,
1220 const struct v4l2_fwnode_int_props
*p
)
1222 struct fwnode_handle
*fwnode
;
1225 const char *prop
= p
->name
;
1226 const char * const *props
= p
->props
;
1227 unsigned int nprops
= p
->nprops
;
1231 fwnode
= v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev
),
1234 if (IS_ERR(fwnode
)) {
1236 * Note that right now both -ENODATA and -ENOENT may
1237 * signal out-of-bounds access. Return the error in
1238 * cases other than that.
1240 if (PTR_ERR(fwnode
) != -ENOENT
&&
1241 PTR_ERR(fwnode
) != -ENODATA
)
1242 return PTR_ERR(fwnode
);
1245 fwnode_handle_put(fwnode
);
1250 !IS_ERR((fwnode
= v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev
),
1255 struct v4l2_async_subdev
*asd
;
1257 asd
= v4l2_async_notifier_add_fwnode_subdev(notifier
, fwnode
,
1259 fwnode_handle_put(fwnode
);
1262 /* not an error if asd already exists */
1266 return PTR_ERR(asd
);
1270 return !fwnode
|| PTR_ERR(fwnode
) == -ENOENT
? 0 : PTR_ERR(fwnode
);
1273 int v4l2_async_notifier_parse_fwnode_sensor_common(struct device
*dev
,
1274 struct v4l2_async_notifier
*notifier
)
1276 static const char * const led_props
[] = { "led" };
1277 static const struct v4l2_fwnode_int_props props
[] = {
1278 { "flash-leds", led_props
, ARRAY_SIZE(led_props
) },
1279 { "lens-focus", NULL
, 0 },
1283 for (i
= 0; i
< ARRAY_SIZE(props
); i
++) {
1286 if (props
[i
].props
&& is_acpi_node(dev_fwnode(dev
)))
1287 ret
= v4l2_fwnode_reference_parse_int_props(dev
,
1291 ret
= v4l2_fwnode_reference_parse(dev
, notifier
,
1293 if (ret
&& ret
!= -ENOENT
) {
1294 dev_warn(dev
, "parsing property \"%s\" failed (%d)\n",
1295 props
[i
].name
, ret
);
1302 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common
);
1304 int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev
*sd
)
1306 struct v4l2_async_notifier
*notifier
;
1309 if (WARN_ON(!sd
->dev
))
1312 notifier
= kzalloc(sizeof(*notifier
), GFP_KERNEL
);
1316 v4l2_async_notifier_init(notifier
);
1318 ret
= v4l2_async_notifier_parse_fwnode_sensor_common(sd
->dev
,
1323 ret
= v4l2_async_subdev_notifier_register(sd
, notifier
);
1327 ret
= v4l2_async_register_subdev(sd
);
1329 goto out_unregister
;
1331 sd
->subdev_notifier
= notifier
;
1336 v4l2_async_notifier_unregister(notifier
);
1339 v4l2_async_notifier_cleanup(notifier
);
1344 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common
);
1346 MODULE_LICENSE("GPL");
1347 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1348 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1349 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");