Merge tag 'extcon-next-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux/fpc-iii.git] / drivers / media / v4l2-core / v4l2-fwnode.c
blob7e740d332a54e2c6371d6e12e611da86309af53c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
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>
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>
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;
45 const char *name;
46 } buses[] = {
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",
78 static const struct v4l2_fwnode_bus_conv *
79 get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
81 unsigned int i;
83 for (i = 0; i < ARRAY_SIZE(buses); i++)
84 if (buses[i].fwnode_bus_type == type)
85 return &buses[i];
87 return NULL;
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;
99 static const char *
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)
111 unsigned int i;
113 for (i = 0; i < ARRAY_SIZE(buses); i++)
114 if (buses[i].mbus_type == type)
115 return &buses[i];
117 return NULL;
120 static const char *
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];
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;
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;
153 if (clock_lane)
154 use_default_lane_mapping = false;
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;
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);
167 if (rval > 0) {
168 num_data_lanes =
169 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
171 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
172 num_data_lanes);
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",
185 array[i]);
186 use_default_lane_mapping = true;
188 lanes_used |= BIT(array[i]);
190 if (have_data_lanes)
191 pr_debug("lane %u position %u\n", i, array[i]);
194 rval = fwnode_property_read_u32_array(fwnode, "lane-polarities", NULL,
196 if (rval > 0) {
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);
200 return -EINVAL;
203 have_lane_polarities = true;
206 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
207 clock_lane = 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");
222 } else {
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;
233 bus->flags = flags;
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) {
239 bus->clock_lane = 0;
240 for (i = 0; i < num_data_lanes; i++)
241 bus->data_lanes[i] = dfl_data_lane_index + i;
242 } else {
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,
251 1 + num_data_lanes);
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 ");
258 } else {
259 pr_debug("no lane polarities defined, assuming not inverted\n");
263 return 0;
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)
273 static void
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;
280 u32 v;
282 if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
283 flags = bus->flags;
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;
329 } else {
330 flags &= ~V4L2_MBUS_SLAVE;
331 flags |= V4L2_MBUS_MASTER;
334 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
335 bus->bus_width = v;
336 pr_debug("bus-width %u\n", v);
339 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
340 bus->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");
360 switch (bus_type) {
361 default:
362 bus->flags = flags;
363 if (flags & PARALLEL_MBUS_FLAGS)
364 vep->bus_type = V4L2_MBUS_PARALLEL;
365 else
366 vep->bus_type = V4L2_MBUS_BT656;
367 break;
368 case V4L2_MBUS_PARALLEL:
369 vep->bus_type = V4L2_MBUS_PARALLEL;
370 bus->flags = flags;
371 break;
372 case V4L2_MBUS_BT656:
373 vep->bus_type = V4L2_MBUS_BT656;
374 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
375 break;
379 static void
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;
385 u32 v;
387 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
388 bus->clock_inv = v;
389 pr_debug("clock-inv %u\n", v);
392 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
393 bus->strobe = v;
394 pr_debug("strobe %u\n", v);
397 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
398 bus->data_lane = v;
399 pr_debug("data-lanes %u\n", v);
402 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
403 bus->clock_lane = v;
404 pr_debug("clock-lanes %u\n", v);
407 if (bus_type == V4L2_MBUS_CCP2)
408 vep->bus_type = V4L2_MBUS_CCP2;
409 else
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;
418 int rval;
420 if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
421 /* Zero fields from bus union to until the end */
422 memset(&vep->bus, 0,
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
430 * the endpoint.
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),
438 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));
446 return -ENXIO;
448 } else {
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,
455 V4L2_MBUS_UNKNOWN);
456 if (rval)
457 return rval;
459 if (vep->bus_type == V4L2_MBUS_UNKNOWN)
460 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
461 V4L2_MBUS_UNKNOWN);
463 pr_debug("assuming media bus type %s (%u)\n",
464 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
465 vep->bus_type);
467 break;
468 case V4L2_MBUS_CCP2:
469 case V4L2_MBUS_CSI1:
470 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
472 break;
473 case V4L2_MBUS_CSI2_DPHY:
474 case V4L2_MBUS_CSI2_CPHY:
475 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
476 vep->bus_type);
477 if (rval)
478 return rval;
480 break;
481 case V4L2_MBUS_PARALLEL:
482 case V4L2_MBUS_BT656:
483 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
484 vep->bus_type);
486 break;
487 default:
488 pr_warn("unsupported bus type %u\n", mbus_type);
489 return -EINVAL;
492 fwnode_graph_parse_endpoint(fwnode, &vep->base);
494 return 0;
497 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
498 struct v4l2_fwnode_endpoint *vep)
500 int ret;
502 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
504 pr_debug("===== end V4L2 endpoint properties\n");
506 return ret;
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))
513 return;
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)
522 int rval;
524 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
525 if (rval < 0)
526 return rval;
528 rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
529 NULL, 0);
530 if (rval > 0) {
531 unsigned int i;
533 vep->link_frequencies =
534 kmalloc_array(rval, sizeof(*vep->link_frequencies),
535 GFP_KERNEL);
536 if (!vep->link_frequencies)
537 return -ENOMEM;
539 vep->nr_of_link_frequencies = rval;
541 rval = fwnode_property_read_u64_array(fwnode,
542 "link-frequencies",
543 vep->link_frequencies,
544 vep->nr_of_link_frequencies);
545 if (rval < 0) {
546 v4l2_fwnode_endpoint_free(vep);
547 return rval;
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");
557 return 0;
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);
577 if (!fwnode) {
578 fwnode_handle_put(fwnode);
579 return -ENOLINK;
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;
589 return 0;
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);
600 static int
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;
609 int ret;
611 asd = kzalloc(asd_struct_size, GFP_KERNEL);
612 if (!asd)
613 return -ENOMEM;
615 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
616 asd->match.fwnode =
617 fwnode_graph_get_remote_port_parent(endpoint);
618 if (!asd->match.fwnode) {
619 dev_dbg(dev, "no remote endpoint found\n");
620 ret = -ENOTCONN;
621 goto out_err;
624 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
625 if (ret) {
626 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
627 ret);
628 goto out_err;
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,
634 vep.base.id);
635 else if (ret < 0)
636 dev_warn(dev,
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);
640 if (ret < 0)
641 goto out_err;
643 ret = v4l2_async_notifier_add_subdev(notifier, asd);
644 if (ret < 0) {
645 /* not an error if asd already exists */
646 if (ret == -EEXIST)
647 ret = 0;
648 goto out_err;
651 return 0;
653 out_err:
654 fwnode_handle_put(asd->match.fwnode);
655 kfree(asd);
657 return ret == -ENOTCONN ? 0 : ret;
660 static int
661 __v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
662 struct v4l2_async_notifier *notifier,
663 size_t asd_struct_size,
664 unsigned int port,
665 bool has_port,
666 parse_endpoint_func parse_endpoint)
668 struct fwnode_handle *fwnode;
669 int ret = 0;
671 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
672 return -EINVAL;
674 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
675 struct fwnode_handle *dev_fwnode;
676 bool is_available;
678 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
679 is_available = fwnode_device_is_available(dev_fwnode);
680 fwnode_handle_put(dev_fwnode);
681 if (!is_available)
682 continue;
684 if (has_port) {
685 struct fwnode_endpoint ep;
687 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
688 if (ret)
689 break;
691 if (ep.port != port)
692 continue;
695 ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
696 notifier,
697 fwnode,
698 asd_struct_size,
699 parse_endpoint);
700 if (ret < 0)
701 break;
704 fwnode_handle_put(fwnode);
706 return ret;
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,
716 asd_struct_size, 0,
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,
725 unsigned int port,
726 parse_endpoint_func parse_endpoint)
728 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
729 asd_struct_size,
730 port, true,
731 parse_endpoint);
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,
748 const char *prop)
750 struct fwnode_reference_args args;
751 unsigned int index;
752 int ret;
754 for (index = 0;
755 !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
756 prop, NULL, 0,
757 index, &args));
758 index++)
759 fwnode_handle_put(args.fwnode);
761 if (!index)
762 return -ENOENT;
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)
769 return ret;
771 for (index = 0;
772 !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
773 0, index, &args);
774 index++) {
775 struct v4l2_async_subdev *asd;
777 asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
778 args.fwnode,
779 sizeof(*asd));
780 if (IS_ERR(asd)) {
781 ret = PTR_ERR(asd);
782 /* not an error if asd already exists */
783 if (ret == -EEXIST) {
784 fwnode_handle_put(args.fwnode);
785 continue;
788 goto error;
792 return 0;
794 error:
795 fwnode_handle_put(args.fwnode);
796 return ret;
800 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
801 * arguments
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
818 * caller.
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)
835 * Device (CAM0)
837 * Name (_DSD, Package () {
838 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
839 * Package () {
840 * Package () {
841 * "compatible",
842 * Package () { "nokia,smia" }
843 * },
844 * },
845 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
846 * Package () {
847 * Package () { "port0", "PRT0" },
849 * })
850 * Name (PRT0, Package() {
851 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
852 * Package () {
853 * Package () { "port", 0 },
854 * },
855 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
856 * Package () {
857 * Package () { "endpoint0", "EP00" },
859 * })
860 * Name (EP00, Package() {
861 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
862 * Package () {
863 * Package () { "endpoint", 0 },
864 * Package () {
865 * "remote-endpoint",
866 * Package() {
867 * \_SB.PCI0.ISP, 4, 0
869 * },
871 * })
875 * Scope (\_SB.PCI0)
877 * Device (ISP)
879 * Name (_DSD, Package () {
880 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
881 * Package () {
882 * Package () { "port4", "PRT4" },
884 * })
886 * Name (PRT4, Package() {
887 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
888 * Package () {
889 * Package () { "port", 4 },
890 * },
891 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
892 * Package () {
893 * Package () { "endpoint0", "EP40" },
895 * })
897 * Name (EP40, Package() {
898 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
899 * Package () {
900 * Package () { "endpoint", 0 },
901 * Package () {
902 * "remote-endpoint",
903 * Package () {
904 * \_SB.PCI0.I2C2.CAM0,
905 * 0, 0
907 * },
909 * })
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"
918 * @index: 0
919 * @props: "port", "endpoint"
920 * @nprops: 2
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:
929 * cam: cam0 {
930 * compatible = "nokia,smia";
932 * port {
933 * port = <0>;
934 * endpoint {
935 * endpoint = <0>;
936 * remote-endpoint = <&isp 4 0>;
937 * };
938 * };
939 * };
941 * isp: isp {
942 * ports {
943 * port@4 {
944 * port = <4>;
945 * endpoint {
946 * endpoint = <0>;
947 * remote-endpoint = <&cam 0 0>;
948 * };
949 * };
950 * };
951 * };
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,
960 const char *prop,
961 unsigned int index,
962 const char * const *props,
963 unsigned int nprops)
965 struct fwnode_reference_args fwnode_args;
966 u64 *args = fwnode_args.args;
967 struct fwnode_handle *child;
968 int ret;
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);
978 if (ret)
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;
986 while (nprops--) {
987 u32 val;
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))
992 continue;
994 /* Found property, see if its value matches. */
995 if (val == *args)
996 break;
999 fwnode_handle_put(fwnode);
1001 /* No property found; return an error here. */
1002 if (!child) {
1003 fwnode = ERR_PTR(-ENOENT);
1004 break;
1007 props++;
1008 args++;
1009 fwnode = child;
1012 return fwnode;
1015 struct v4l2_fwnode_int_props {
1016 const char *name;
1017 const char * const *props;
1018 unsigned int nprops;
1022 * v4l2_fwnode_reference_parse_int_props - parse references for async
1023 * sub-devices
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
1033 * accordingly.
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
1044 static int
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;
1050 unsigned int index;
1051 int ret;
1052 const char *prop = p->name;
1053 const char * const *props = p->props;
1054 unsigned int nprops = p->nprops;
1056 index = 0;
1057 do {
1058 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1059 prop, index,
1060 props, nprops);
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);
1070 break;
1072 fwnode_handle_put(fwnode);
1073 index++;
1074 } while (1);
1076 for (index = 0;
1077 !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1078 prop, index,
1079 props,
1080 nprops)));
1081 index++) {
1082 struct v4l2_async_subdev *asd;
1084 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1085 sizeof(*asd));
1086 if (IS_ERR(asd)) {
1087 ret = PTR_ERR(asd);
1088 /* not an error if asd already exists */
1089 if (ret == -EEXIST) {
1090 fwnode_handle_put(fwnode);
1091 continue;
1094 goto error;
1098 return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1100 error:
1101 fwnode_handle_put(fwnode);
1102 return ret;
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 },
1113 unsigned int i;
1115 for (i = 0; i < ARRAY_SIZE(props); i++) {
1116 int ret;
1118 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1119 ret = v4l2_fwnode_reference_parse_int_props(dev,
1120 notifier,
1121 &props[i]);
1122 else
1123 ret = v4l2_fwnode_reference_parse(dev, notifier,
1124 props[i].name);
1125 if (ret && ret != -ENOENT) {
1126 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1127 props[i].name, ret);
1128 return ret;
1132 return 0;
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;
1139 int ret;
1141 if (WARN_ON(!sd->dev))
1142 return -ENODEV;
1144 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1145 if (!notifier)
1146 return -ENOMEM;
1148 v4l2_async_notifier_init(notifier);
1150 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
1151 notifier);
1152 if (ret < 0)
1153 goto out_cleanup;
1155 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1156 if (ret < 0)
1157 goto out_cleanup;
1159 ret = v4l2_async_register_subdev(sd);
1160 if (ret < 0)
1161 goto out_unregister;
1163 sd->subdev_notifier = notifier;
1165 return 0;
1167 out_unregister:
1168 v4l2_async_notifier_unregister(notifier);
1170 out_cleanup:
1171 v4l2_async_notifier_cleanup(notifier);
1172 kfree(notifier);
1174 return ret;
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;
1187 int ret;
1189 if (WARN_ON(!dev))
1190 return -ENODEV;
1192 fwnode = dev_fwnode(dev);
1193 if (!fwnode_device_is_available(fwnode))
1194 return -ENODEV;
1196 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1197 if (!notifier)
1198 return -ENOMEM;
1200 v4l2_async_notifier_init(notifier);
1202 if (!ports) {
1203 ret = v4l2_async_notifier_parse_fwnode_endpoints(dev, notifier,
1204 asd_struct_size,
1205 parse_endpoint);
1206 if (ret < 0)
1207 goto out_cleanup;
1208 } else {
1209 unsigned int i;
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);
1213 if (ret < 0)
1214 goto out_cleanup;
1218 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1219 if (ret < 0)
1220 goto out_cleanup;
1222 ret = v4l2_async_register_subdev(sd);
1223 if (ret < 0)
1224 goto out_unregister;
1226 sd->subdev_notifier = notifier;
1228 return 0;
1230 out_unregister:
1231 v4l2_async_notifier_unregister(notifier);
1232 out_cleanup:
1233 v4l2_async_notifier_cleanup(notifier);
1234 kfree(notifier);
1236 return ret;
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>");