1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * V4L2 fwnode binding parsing library
4  *
5  * The origins of the V4L2 fwnode library are in V4L2 OF library that
6  * formerly was located in v4l2-of.c.
7  *
8  * Copyright (c) 2016 Intel Corporation.
9  * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
10  *
11  * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
12  * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
13  *
14  * Copyright (C) 2012 Renesas Electronics Corp.
15  * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
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 static const struct v4l2_fwnode_bus_conv {
32 	enum v4l2_fwnode_bus_type fwnode_bus_type;
33 	enum v4l2_mbus_type mbus_type;
34 	const char *name;
35 } buses[] = {
36 	{
37 		V4L2_FWNODE_BUS_TYPE_GUESS,
38 		V4L2_MBUS_UNKNOWN,
39 		"not specified",
40 	}, {
41 		V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
42 		V4L2_MBUS_CSI2_CPHY,
43 		"MIPI CSI-2 C-PHY",
44 	}, {
45 		V4L2_FWNODE_BUS_TYPE_CSI1,
46 		V4L2_MBUS_CSI1,
47 		"MIPI CSI-1",
48 	}, {
49 		V4L2_FWNODE_BUS_TYPE_CCP2,
50 		V4L2_MBUS_CCP2,
51 		"compact camera port 2",
52 	}, {
53 		V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
54 		V4L2_MBUS_CSI2_DPHY,
55 		"MIPI CSI-2 D-PHY",
56 	}, {
57 		V4L2_FWNODE_BUS_TYPE_PARALLEL,
58 		V4L2_MBUS_PARALLEL,
59 		"parallel",
60 	}, {
61 		V4L2_FWNODE_BUS_TYPE_BT656,
62 		V4L2_MBUS_BT656,
63 		"Bt.656",
64 	}, {
65 		V4L2_FWNODE_BUS_TYPE_DPI,
66 		V4L2_MBUS_DPI,
67 		"DPI",
68 	}
69 };
70 
71 static const struct v4l2_fwnode_bus_conv *
72 get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
73 {
74 	unsigned int i;
75 
76 	for (i = 0; i < ARRAY_SIZE(buses); i++)
77 		if (buses[i].fwnode_bus_type == type)
78 			return &buses[i];
79 
80 	return NULL;
81 }
82 
83 static enum v4l2_mbus_type
84 v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
85 {
86 	const struct v4l2_fwnode_bus_conv *conv =
87 		get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
88 
89 	return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
90 }
91 
92 static const char *
93 v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
94 {
95 	const struct v4l2_fwnode_bus_conv *conv =
96 		get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
97 
98 	return conv ? conv->name : "not found";
99 }
100 
101 static const struct v4l2_fwnode_bus_conv *
102 get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
103 {
104 	unsigned int i;
105 
106 	for (i = 0; i < ARRAY_SIZE(buses); i++)
107 		if (buses[i].mbus_type == type)
108 			return &buses[i];
109 
110 	return NULL;
111 }
112 
113 static const char *
114 v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
115 {
116 	const struct v4l2_fwnode_bus_conv *conv =
117 		get_v4l2_fwnode_bus_conv_by_mbus(type);
118 
119 	return conv ? conv->name : "not found";
120 }
121 
122 static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
123 					       struct v4l2_fwnode_endpoint *vep,
124 					       enum v4l2_mbus_type bus_type)
125 {
126 	struct v4l2_mbus_config_mipi_csi2 *bus = &vep->bus.mipi_csi2;
127 	bool have_clk_lane = false, have_data_lanes = false,
128 		have_lane_polarities = false;
129 	unsigned int flags = 0, lanes_used = 0;
130 	u32 array[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES];
131 	u32 clock_lane = 0;
132 	unsigned int num_data_lanes = 0;
133 	bool use_default_lane_mapping = false;
134 	unsigned int i;
135 	u32 v;
136 	int rval;
137 
138 	if (bus_type == V4L2_MBUS_CSI2_DPHY ||
139 	    bus_type == V4L2_MBUS_CSI2_CPHY) {
140 		use_default_lane_mapping = true;
141 
142 		num_data_lanes = min_t(u32, bus->num_data_lanes,
143 				       V4L2_MBUS_CSI2_MAX_DATA_LANES);
144 
145 		clock_lane = bus->clock_lane;
146 		if (clock_lane)
147 			use_default_lane_mapping = false;
148 
149 		for (i = 0; i < num_data_lanes; i++) {
150 			array[i] = bus->data_lanes[i];
151 			if (array[i])
152 				use_default_lane_mapping = false;
153 		}
154 
155 		if (use_default_lane_mapping)
156 			pr_debug("no lane mapping given, using defaults\n");
157 	}
158 
159 	rval = fwnode_property_count_u32(fwnode, "data-lanes");
160 	if (rval > 0) {
161 		num_data_lanes =
162 			min_t(int, V4L2_MBUS_CSI2_MAX_DATA_LANES, rval);
163 
164 		fwnode_property_read_u32_array(fwnode, "data-lanes", array,
165 					       num_data_lanes);
166 
167 		have_data_lanes = true;
168 		if (use_default_lane_mapping) {
169 			pr_debug("data-lanes property exists; disabling default mapping\n");
170 			use_default_lane_mapping = false;
171 		}
172 	}
173 
174 	for (i = 0; i < num_data_lanes; i++) {
175 		if (lanes_used & BIT(array[i])) {
176 			if (have_data_lanes || !use_default_lane_mapping)
177 				pr_warn("duplicated lane %u in data-lanes, using defaults\n",
178 					array[i]);
179 			use_default_lane_mapping = true;
180 		}
181 		lanes_used |= BIT(array[i]);
182 
183 		if (have_data_lanes)
184 			pr_debug("lane %u position %u\n", i, array[i]);
185 	}
186 
187 	rval = fwnode_property_count_u32(fwnode, "lane-polarities");
188 	if (rval > 0) {
189 		if (rval != 1 + num_data_lanes /* clock+data */) {
190 			pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
191 				1 + num_data_lanes, rval);
192 			return -EINVAL;
193 		}
194 
195 		have_lane_polarities = true;
196 	}
197 
198 	if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
199 		clock_lane = v;
200 		pr_debug("clock lane position %u\n", v);
201 		have_clk_lane = true;
202 	}
203 
204 	if (have_clk_lane && lanes_used & BIT(clock_lane) &&
205 	    !use_default_lane_mapping) {
206 		pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
207 			v);
208 		use_default_lane_mapping = true;
209 	}
210 
211 	if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
212 		flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
213 		pr_debug("non-continuous clock\n");
214 	}
215 
216 	if (bus_type == V4L2_MBUS_CSI2_DPHY ||
217 	    bus_type == V4L2_MBUS_CSI2_CPHY ||
218 	    lanes_used || have_clk_lane || flags) {
219 		/* Only D-PHY has a clock lane. */
220 		unsigned int dfl_data_lane_index =
221 			bus_type == V4L2_MBUS_CSI2_DPHY;
222 
223 		bus->flags = flags;
224 		if (bus_type == V4L2_MBUS_UNKNOWN)
225 			vep->bus_type = V4L2_MBUS_CSI2_DPHY;
226 		bus->num_data_lanes = num_data_lanes;
227 
228 		if (use_default_lane_mapping) {
229 			bus->clock_lane = 0;
230 			for (i = 0; i < num_data_lanes; i++)
231 				bus->data_lanes[i] = dfl_data_lane_index + i;
232 		} else {
233 			bus->clock_lane = clock_lane;
234 			for (i = 0; i < num_data_lanes; i++)
235 				bus->data_lanes[i] = array[i];
236 		}
237 
238 		if (have_lane_polarities) {
239 			fwnode_property_read_u32_array(fwnode,
240 						       "lane-polarities", array,
241 						       1 + num_data_lanes);
242 
243 			for (i = 0; i < 1 + num_data_lanes; i++) {
244 				bus->lane_polarities[i] = array[i];
245 				pr_debug("lane %u polarity %sinverted",
246 					 i, array[i] ? "" : "not ");
247 			}
248 		} else {
249 			pr_debug("no lane polarities defined, assuming not inverted\n");
250 		}
251 	}
252 
253 	return 0;
254 }
255 
256 #define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH |	\
257 			     V4L2_MBUS_HSYNC_ACTIVE_LOW |	\
258 			     V4L2_MBUS_VSYNC_ACTIVE_HIGH |	\
259 			     V4L2_MBUS_VSYNC_ACTIVE_LOW |	\
260 			     V4L2_MBUS_FIELD_EVEN_HIGH |	\
261 			     V4L2_MBUS_FIELD_EVEN_LOW)
262 
263 static void
264 v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
265 					struct v4l2_fwnode_endpoint *vep,
266 					enum v4l2_mbus_type bus_type)
267 {
268 	struct v4l2_mbus_config_parallel *bus = &vep->bus.parallel;
269 	unsigned int flags = 0;
270 	u32 v;
271 
272 	if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
273 		flags = bus->flags;
274 
275 	if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
276 		flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
277 			   V4L2_MBUS_HSYNC_ACTIVE_LOW);
278 		flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
279 			V4L2_MBUS_HSYNC_ACTIVE_LOW;
280 		pr_debug("hsync-active %s\n", v ? "high" : "low");
281 	}
282 
283 	if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
284 		flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
285 			   V4L2_MBUS_VSYNC_ACTIVE_LOW);
286 		flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
287 			V4L2_MBUS_VSYNC_ACTIVE_LOW;
288 		pr_debug("vsync-active %s\n", v ? "high" : "low");
289 	}
290 
291 	if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
292 		flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
293 			   V4L2_MBUS_FIELD_EVEN_LOW);
294 		flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
295 			V4L2_MBUS_FIELD_EVEN_LOW;
296 		pr_debug("field-even-active %s\n", v ? "high" : "low");
297 	}
298 
299 	if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
300 		flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
301 			   V4L2_MBUS_PCLK_SAMPLE_FALLING |
302 			   V4L2_MBUS_PCLK_SAMPLE_DUALEDGE);
303 		switch (v) {
304 		case 0:
305 			flags |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
306 			pr_debug("pclk-sample low\n");
307 			break;
308 		case 1:
309 			flags |= V4L2_MBUS_PCLK_SAMPLE_RISING;
310 			pr_debug("pclk-sample high\n");
311 			break;
312 		case 2:
313 			flags |= V4L2_MBUS_PCLK_SAMPLE_DUALEDGE;
314 			pr_debug("pclk-sample dual edge\n");
315 			break;
316 		default:
317 			pr_warn("invalid argument for pclk-sample");
318 			break;
319 		}
320 	}
321 
322 	if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
323 		flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
324 			   V4L2_MBUS_DATA_ACTIVE_LOW);
325 		flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
326 			V4L2_MBUS_DATA_ACTIVE_LOW;
327 		pr_debug("data-active %s\n", v ? "high" : "low");
328 	}
329 
330 	if (fwnode_property_present(fwnode, "slave-mode")) {
331 		pr_debug("slave mode\n");
332 		flags &= ~V4L2_MBUS_MASTER;
333 		flags |= V4L2_MBUS_SLAVE;
334 	} else {
335 		flags &= ~V4L2_MBUS_SLAVE;
336 		flags |= V4L2_MBUS_MASTER;
337 	}
338 
339 	if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
340 		bus->bus_width = v;
341 		pr_debug("bus-width %u\n", v);
342 	}
343 
344 	if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
345 		bus->data_shift = v;
346 		pr_debug("data-shift %u\n", v);
347 	}
348 
349 	if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
350 		flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
351 			   V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
352 		flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
353 			V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
354 		pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
355 	}
356 
357 	if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
358 		flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
359 			   V4L2_MBUS_DATA_ENABLE_LOW);
360 		flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
361 			V4L2_MBUS_DATA_ENABLE_LOW;
362 		pr_debug("data-enable-active %s\n", v ? "high" : "low");
363 	}
364 
365 	switch (bus_type) {
366 	default:
367 		bus->flags = flags;
368 		if (flags & PARALLEL_MBUS_FLAGS)
369 			vep->bus_type = V4L2_MBUS_PARALLEL;
370 		else
371 			vep->bus_type = V4L2_MBUS_BT656;
372 		break;
373 	case V4L2_MBUS_PARALLEL:
374 		vep->bus_type = V4L2_MBUS_PARALLEL;
375 		bus->flags = flags;
376 		break;
377 	case V4L2_MBUS_BT656:
378 		vep->bus_type = V4L2_MBUS_BT656;
379 		bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
380 		break;
381 	}
382 }
383 
384 static void
385 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
386 				    struct v4l2_fwnode_endpoint *vep,
387 				    enum v4l2_mbus_type bus_type)
388 {
389 	struct v4l2_mbus_config_mipi_csi1 *bus = &vep->bus.mipi_csi1;
390 	u32 v;
391 
392 	if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
393 		bus->clock_inv = v;
394 		pr_debug("clock-inv %u\n", v);
395 	}
396 
397 	if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
398 		bus->strobe = v;
399 		pr_debug("strobe %u\n", v);
400 	}
401 
402 	if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
403 		bus->data_lane = v;
404 		pr_debug("data-lanes %u\n", v);
405 	}
406 
407 	if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
408 		bus->clock_lane = v;
409 		pr_debug("clock-lanes %u\n", v);
410 	}
411 
412 	if (bus_type == V4L2_MBUS_CCP2)
413 		vep->bus_type = V4L2_MBUS_CCP2;
414 	else
415 		vep->bus_type = V4L2_MBUS_CSI1;
416 }
417 
418 static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
419 					struct v4l2_fwnode_endpoint *vep)
420 {
421 	u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
422 	enum v4l2_mbus_type mbus_type;
423 	int rval;
424 
425 	pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
426 
427 	fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
428 	pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
429 		 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
430 		 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
431 		 vep->bus_type);
432 	mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
433 	if (mbus_type == V4L2_MBUS_INVALID) {
434 		pr_debug("unsupported bus type %u\n", bus_type);
435 		return -EINVAL;
436 	}
437 
438 	if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
439 		if (mbus_type != V4L2_MBUS_UNKNOWN &&
440 		    vep->bus_type != mbus_type) {
441 			pr_debug("expecting bus type %s\n",
442 				 v4l2_fwnode_mbus_type_to_string(vep->bus_type));
443 			return -ENXIO;
444 		}
445 	} else {
446 		vep->bus_type = mbus_type;
447 	}
448 
449 	switch (vep->bus_type) {
450 	case V4L2_MBUS_UNKNOWN:
451 		rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
452 							   V4L2_MBUS_UNKNOWN);
453 		if (rval)
454 			return rval;
455 
456 		if (vep->bus_type == V4L2_MBUS_UNKNOWN)
457 			v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
458 								V4L2_MBUS_UNKNOWN);
459 
460 		pr_debug("assuming media bus type %s (%u)\n",
461 			 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
462 			 vep->bus_type);
463 
464 		break;
465 	case V4L2_MBUS_CCP2:
466 	case V4L2_MBUS_CSI1:
467 		v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
468 
469 		break;
470 	case V4L2_MBUS_CSI2_DPHY:
471 	case V4L2_MBUS_CSI2_CPHY:
472 		rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
473 							   vep->bus_type);
474 		if (rval)
475 			return rval;
476 
477 		break;
478 	case V4L2_MBUS_PARALLEL:
479 	case V4L2_MBUS_BT656:
480 		v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
481 							vep->bus_type);
482 
483 		break;
484 	default:
485 		pr_warn("unsupported bus type %u\n", mbus_type);
486 		return -EINVAL;
487 	}
488 
489 	fwnode_graph_parse_endpoint(fwnode, &vep->base);
490 
491 	return 0;
492 }
493 
494 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
495 			       struct v4l2_fwnode_endpoint *vep)
496 {
497 	int ret;
498 
499 	ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
500 
501 	pr_debug("===== end parsing endpoint %pfw\n", fwnode);
502 
503 	return ret;
504 }
505 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
506 
507 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
508 {
509 	if (IS_ERR_OR_NULL(vep))
510 		return;
511 
512 	kfree(vep->link_frequencies);
513 	vep->link_frequencies = NULL;
514 }
515 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
516 
517 int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
518 				     struct v4l2_fwnode_endpoint *vep)
519 {
520 	int rval;
521 
522 	rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
523 	if (rval < 0)
524 		return rval;
525 
526 	rval = fwnode_property_count_u64(fwnode, "link-frequencies");
527 	if (rval > 0) {
528 		unsigned int i;
529 
530 		vep->link_frequencies =
531 			kmalloc_array(rval, sizeof(*vep->link_frequencies),
532 				      GFP_KERNEL);
533 		if (!vep->link_frequencies)
534 			return -ENOMEM;
535 
536 		vep->nr_of_link_frequencies = rval;
537 
538 		rval = fwnode_property_read_u64_array(fwnode,
539 						      "link-frequencies",
540 						      vep->link_frequencies,
541 						      vep->nr_of_link_frequencies);
542 		if (rval < 0) {
543 			v4l2_fwnode_endpoint_free(vep);
544 			return rval;
545 		}
546 
547 		for (i = 0; i < vep->nr_of_link_frequencies; i++)
548 			pr_debug("link-frequencies %u value %llu\n", i,
549 				 vep->link_frequencies[i]);
550 	}
551 
552 	pr_debug("===== end parsing endpoint %pfw\n", fwnode);
553 
554 	return 0;
555 }
556 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
557 
558 int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
559 			   struct v4l2_fwnode_link *link)
560 {
561 	struct fwnode_endpoint fwep;
562 
563 	memset(link, 0, sizeof(*link));
564 
565 	fwnode_graph_parse_endpoint(fwnode, &fwep);
566 	link->local_id = fwep.id;
567 	link->local_port = fwep.port;
568 	link->local_node = fwnode_graph_get_port_parent(fwnode);
569 
570 	fwnode = fwnode_graph_get_remote_endpoint(fwnode);
571 	if (!fwnode) {
572 		fwnode_handle_put(fwnode);
573 		return -ENOLINK;
574 	}
575 
576 	fwnode_graph_parse_endpoint(fwnode, &fwep);
577 	link->remote_id = fwep.id;
578 	link->remote_port = fwep.port;
579 	link->remote_node = fwnode_graph_get_port_parent(fwnode);
580 
581 	return 0;
582 }
583 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
584 
585 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
586 {
587 	fwnode_handle_put(link->local_node);
588 	fwnode_handle_put(link->remote_node);
589 }
590 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
591 
592 static const struct v4l2_fwnode_connector_conv {
593 	enum v4l2_connector_type type;
594 	const char *compatible;
595 } connectors[] = {
596 	{
597 		.type = V4L2_CONN_COMPOSITE,
598 		.compatible = "composite-video-connector",
599 	}, {
600 		.type = V4L2_CONN_SVIDEO,
601 		.compatible = "svideo-connector",
602 	},
603 };
604 
605 static enum v4l2_connector_type
606 v4l2_fwnode_string_to_connector_type(const char *con_str)
607 {
608 	unsigned int i;
609 
610 	for (i = 0; i < ARRAY_SIZE(connectors); i++)
611 		if (!strcmp(con_str, connectors[i].compatible))
612 			return connectors[i].type;
613 
614 	return V4L2_CONN_UNKNOWN;
615 }
616 
617 static void
618 v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
619 				   struct v4l2_fwnode_connector *vc)
620 {
621 	u32 stds;
622 	int ret;
623 
624 	ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
625 
626 	/* The property is optional. */
627 	vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
628 }
629 
630 void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
631 {
632 	struct v4l2_connector_link *link, *tmp;
633 
634 	if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
635 		return;
636 
637 	list_for_each_entry_safe(link, tmp, &connector->links, head) {
638 		v4l2_fwnode_put_link(&link->fwnode_link);
639 		list_del(&link->head);
640 		kfree(link);
641 	}
642 
643 	kfree(connector->label);
644 	connector->label = NULL;
645 	connector->type = V4L2_CONN_UNKNOWN;
646 }
647 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
648 
649 static enum v4l2_connector_type
650 v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
651 {
652 	const char *type_name;
653 	int err;
654 
655 	if (!fwnode)
656 		return V4L2_CONN_UNKNOWN;
657 
658 	/* The connector-type is stored within the compatible string. */
659 	err = fwnode_property_read_string(fwnode, "compatible", &type_name);
660 	if (err)
661 		return V4L2_CONN_UNKNOWN;
662 
663 	return v4l2_fwnode_string_to_connector_type(type_name);
664 }
665 
666 int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
667 				struct v4l2_fwnode_connector *connector)
668 {
669 	struct fwnode_handle *connector_node;
670 	enum v4l2_connector_type connector_type;
671 	const char *label;
672 	int err;
673 
674 	if (!fwnode)
675 		return -EINVAL;
676 
677 	memset(connector, 0, sizeof(*connector));
678 
679 	INIT_LIST_HEAD(&connector->links);
680 
681 	connector_node = fwnode_graph_get_port_parent(fwnode);
682 	connector_type = v4l2_fwnode_get_connector_type(connector_node);
683 	if (connector_type == V4L2_CONN_UNKNOWN) {
684 		fwnode_handle_put(connector_node);
685 		connector_node = fwnode_graph_get_remote_port_parent(fwnode);
686 		connector_type = v4l2_fwnode_get_connector_type(connector_node);
687 	}
688 
689 	if (connector_type == V4L2_CONN_UNKNOWN) {
690 		pr_err("Unknown connector type\n");
691 		err = -ENOTCONN;
692 		goto out;
693 	}
694 
695 	connector->type = connector_type;
696 	connector->name = fwnode_get_name(connector_node);
697 	err = fwnode_property_read_string(connector_node, "label", &label);
698 	connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
699 
700 	/* Parse the connector specific properties. */
701 	switch (connector->type) {
702 	case V4L2_CONN_COMPOSITE:
703 	case V4L2_CONN_SVIDEO:
704 		v4l2_fwnode_connector_parse_analog(connector_node, connector);
705 		break;
706 	/* Avoid compiler warnings */
707 	case V4L2_CONN_UNKNOWN:
708 		break;
709 	}
710 
711 out:
712 	fwnode_handle_put(connector_node);
713 
714 	return err;
715 }
716 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
717 
718 int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
719 				   struct v4l2_fwnode_connector *connector)
720 {
721 	struct fwnode_handle *connector_ep;
722 	struct v4l2_connector_link *link;
723 	int err;
724 
725 	if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
726 		return -EINVAL;
727 
728 	connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
729 	if (!connector_ep)
730 		return -ENOTCONN;
731 
732 	link = kzalloc(sizeof(*link), GFP_KERNEL);
733 	if (!link) {
734 		err = -ENOMEM;
735 		goto err;
736 	}
737 
738 	err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
739 	if (err)
740 		goto err;
741 
742 	fwnode_handle_put(connector_ep);
743 
744 	list_add(&link->head, &connector->links);
745 	connector->nr_of_links++;
746 
747 	return 0;
748 
749 err:
750 	kfree(link);
751 	fwnode_handle_put(connector_ep);
752 
753 	return err;
754 }
755 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
756 
757 int v4l2_fwnode_device_parse(struct device *dev,
758 			     struct v4l2_fwnode_device_properties *props)
759 {
760 	struct fwnode_handle *fwnode = dev_fwnode(dev);
761 	u32 val;
762 	int ret;
763 
764 	memset(props, 0, sizeof(*props));
765 
766 	props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
767 	ret = fwnode_property_read_u32(fwnode, "orientation", &val);
768 	if (!ret) {
769 		switch (val) {
770 		case V4L2_FWNODE_ORIENTATION_FRONT:
771 		case V4L2_FWNODE_ORIENTATION_BACK:
772 		case V4L2_FWNODE_ORIENTATION_EXTERNAL:
773 			break;
774 		default:
775 			dev_warn(dev, "Unsupported device orientation: %u\n", val);
776 			return -EINVAL;
777 		}
778 
779 		props->orientation = val;
780 		dev_dbg(dev, "device orientation: %u\n", val);
781 	}
782 
783 	props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
784 	ret = fwnode_property_read_u32(fwnode, "rotation", &val);
785 	if (!ret) {
786 		if (val >= 360) {
787 			dev_warn(dev, "Unsupported device rotation: %u\n", val);
788 			return -EINVAL;
789 		}
790 
791 		props->rotation = val;
792 		dev_dbg(dev, "device rotation: %u\n", val);
793 	}
794 
795 	return 0;
796 }
797 EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
798 
799 static int
800 v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
801 				    struct v4l2_async_notifier *notifier,
802 				    struct fwnode_handle *endpoint,
803 				    unsigned int asd_struct_size,
804 				    parse_endpoint_func parse_endpoint)
805 {
806 	struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
807 	struct v4l2_async_subdev *asd;
808 	int ret;
809 
810 	asd = kzalloc(asd_struct_size, GFP_KERNEL);
811 	if (!asd)
812 		return -ENOMEM;
813 
814 	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
815 	asd->match.fwnode =
816 		fwnode_graph_get_remote_port_parent(endpoint);
817 	if (!asd->match.fwnode) {
818 		dev_dbg(dev, "no remote endpoint found\n");
819 		ret = -ENOTCONN;
820 		goto out_err;
821 	}
822 
823 	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
824 	if (ret) {
825 		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
826 			 ret);
827 		goto out_err;
828 	}
829 
830 	ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
831 	if (ret == -ENOTCONN)
832 		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
833 			vep.base.id);
834 	else if (ret < 0)
835 		dev_warn(dev,
836 			 "driver could not parse port@%u/endpoint@%u (%d)\n",
837 			 vep.base.port, vep.base.id, ret);
838 	v4l2_fwnode_endpoint_free(&vep);
839 	if (ret < 0)
840 		goto out_err;
841 
842 	ret = __v4l2_async_nf_add_subdev(notifier, asd);
843 	if (ret < 0) {
844 		/* not an error if asd already exists */
845 		if (ret == -EEXIST)
846 			ret = 0;
847 		goto out_err;
848 	}
849 
850 	return 0;
851 
852 out_err:
853 	fwnode_handle_put(asd->match.fwnode);
854 	kfree(asd);
855 
856 	return ret == -ENOTCONN ? 0 : ret;
857 }
858 
859 int
860 v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
861 				     struct v4l2_async_notifier *notifier,
862 				     size_t asd_struct_size,
863 				     parse_endpoint_func parse_endpoint)
864 {
865 	struct fwnode_handle *fwnode;
866 	int ret = 0;
867 
868 	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
869 		return -EINVAL;
870 
871 	fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
872 		struct fwnode_handle *dev_fwnode;
873 		bool is_available;
874 
875 		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
876 		is_available = fwnode_device_is_available(dev_fwnode);
877 		fwnode_handle_put(dev_fwnode);
878 		if (!is_available)
879 			continue;
880 
881 
882 		ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier,
883 							  fwnode,
884 							  asd_struct_size,
885 							  parse_endpoint);
886 		if (ret < 0)
887 			break;
888 	}
889 
890 	fwnode_handle_put(fwnode);
891 
892 	return ret;
893 }
894 EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints);
895 
896 /*
897  * v4l2_fwnode_reference_parse - parse references for async sub-devices
898  * @dev: the device node the properties of which are parsed for references
899  * @notifier: the async notifier where the async subdevs will be added
900  * @prop: the name of the property
901  *
902  * Return: 0 on success
903  *	   -ENOENT if no entries were found
904  *	   -ENOMEM if memory allocation failed
905  *	   -EINVAL if property parsing failed
906  */
907 static int v4l2_fwnode_reference_parse(struct device *dev,
908 				       struct v4l2_async_notifier *notifier,
909 				       const char *prop)
910 {
911 	struct fwnode_reference_args args;
912 	unsigned int index;
913 	int ret;
914 
915 	for (index = 0;
916 	     !(ret = fwnode_property_get_reference_args(dev_fwnode(dev), prop,
917 							NULL, 0, index, &args));
918 	     index++) {
919 		struct v4l2_async_subdev *asd;
920 
921 		asd = v4l2_async_nf_add_fwnode(notifier, args.fwnode,
922 					       struct v4l2_async_subdev);
923 		fwnode_handle_put(args.fwnode);
924 		if (IS_ERR(asd)) {
925 			/* not an error if asd already exists */
926 			if (PTR_ERR(asd) == -EEXIST)
927 				continue;
928 
929 			return PTR_ERR(asd);
930 		}
931 	}
932 
933 	/* -ENOENT here means successful parsing */
934 	if (ret != -ENOENT)
935 		return ret;
936 
937 	/* Return -ENOENT if no references were found */
938 	return index ? 0 : -ENOENT;
939 }
940 
941 /*
942  * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
943  *					arguments
944  * @fwnode: fwnode to read @prop from
945  * @notifier: notifier for @dev
946  * @prop: the name of the property
947  * @index: the index of the reference to get
948  * @props: the array of integer property names
949  * @nprops: the number of integer property names in @nprops
950  *
951  * First find an fwnode referred to by the reference at @index in @prop.
952  *
953  * Then under that fwnode, @nprops times, for each property in @props,
954  * iteratively follow child nodes starting from fwnode such that they have the
955  * property in @props array at the index of the child node distance from the
956  * root node and the value of that property matching with the integer argument
957  * of the reference, at the same index.
958  *
959  * The child fwnode reached at the end of the iteration is then returned to the
960  * caller.
961  *
962  * The core reason for this is that you cannot refer to just any node in ACPI.
963  * So to refer to an endpoint (easy in DT) you need to refer to a device, then
964  * provide a list of (property name, property value) tuples where each tuple
965  * uniquely identifies a child node. The first tuple identifies a child directly
966  * underneath the device fwnode, the next tuple identifies a child node
967  * underneath the fwnode identified by the previous tuple, etc. until you
968  * reached the fwnode you need.
969  *
970  * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A
971  * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under
972  * Documentation/firmware-guide/acpi/dsd/ instead and especially graph.txt,
973  * data-node-references.txt and leds.txt .
974  *
975  *	Scope (\_SB.PCI0.I2C2)
976  *	{
977  *		Device (CAM0)
978  *		{
979  *			Name (_DSD, Package () {
980  *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
981  *				Package () {
982  *					Package () {
983  *						"compatible",
984  *						Package () { "nokia,smia" }
985  *					},
986  *				},
987  *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
988  *				Package () {
989  *					Package () { "port0", "PRT0" },
990  *				}
991  *			})
992  *			Name (PRT0, Package() {
993  *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
994  *				Package () {
995  *					Package () { "port", 0 },
996  *				},
997  *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
998  *				Package () {
999  *					Package () { "endpoint0", "EP00" },
1000  *				}
1001  *			})
1002  *			Name (EP00, Package() {
1003  *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1004  *				Package () {
1005  *					Package () { "endpoint", 0 },
1006  *					Package () {
1007  *						"remote-endpoint",
1008  *						Package() {
1009  *							\_SB.PCI0.ISP, 4, 0
1010  *						}
1011  *					},
1012  *				}
1013  *			})
1014  *		}
1015  *	}
1016  *
1017  *	Scope (\_SB.PCI0)
1018  *	{
1019  *		Device (ISP)
1020  *		{
1021  *			Name (_DSD, Package () {
1022  *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1023  *				Package () {
1024  *					Package () { "port4", "PRT4" },
1025  *				}
1026  *			})
1027  *
1028  *			Name (PRT4, Package() {
1029  *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1030  *				Package () {
1031  *					Package () { "port", 4 },
1032  *				},
1033  *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1034  *				Package () {
1035  *					Package () { "endpoint0", "EP40" },
1036  *				}
1037  *			})
1038  *
1039  *			Name (EP40, Package() {
1040  *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1041  *				Package () {
1042  *					Package () { "endpoint", 0 },
1043  *					Package () {
1044  *						"remote-endpoint",
1045  *						Package () {
1046  *							\_SB.PCI0.I2C2.CAM0,
1047  *							0, 0
1048  *						}
1049  *					},
1050  *				}
1051  *			})
1052  *		}
1053  *	}
1054  *
1055  * From the EP40 node under ISP device, you could parse the graph remote
1056  * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
1057  *
1058  *  @fwnode: fwnode referring to EP40 under ISP.
1059  *  @prop: "remote-endpoint"
1060  *  @index: 0
1061  *  @props: "port", "endpoint"
1062  *  @nprops: 2
1063  *
1064  * And you'd get back fwnode referring to EP00 under CAM0.
1065  *
1066  * The same works the other way around: if you use EP00 under CAM0 as the
1067  * fwnode, you'll get fwnode referring to EP40 under ISP.
1068  *
1069  * The same example in DT syntax would look like this:
1070  *
1071  * cam: cam0 {
1072  *	compatible = "nokia,smia";
1073  *
1074  *	port {
1075  *		port = <0>;
1076  *		endpoint {
1077  *			endpoint = <0>;
1078  *			remote-endpoint = <&isp 4 0>;
1079  *		};
1080  *	};
1081  * };
1082  *
1083  * isp: isp {
1084  *	ports {
1085  *		port@4 {
1086  *			port = <4>;
1087  *			endpoint {
1088  *				endpoint = <0>;
1089  *				remote-endpoint = <&cam 0 0>;
1090  *			};
1091  *		};
1092  *	};
1093  * };
1094  *
1095  * Return: 0 on success
1096  *	   -ENOENT if no entries (or the property itself) were found
1097  *	   -EINVAL if property parsing otherwise failed
1098  *	   -ENOMEM if memory allocation failed
1099  */
1100 static struct fwnode_handle *
1101 v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
1102 				   const char *prop,
1103 				   unsigned int index,
1104 				   const char * const *props,
1105 				   unsigned int nprops)
1106 {
1107 	struct fwnode_reference_args fwnode_args;
1108 	u64 *args = fwnode_args.args;
1109 	struct fwnode_handle *child;
1110 	int ret;
1111 
1112 	/*
1113 	 * Obtain remote fwnode as well as the integer arguments.
1114 	 *
1115 	 * Note that right now both -ENODATA and -ENOENT may signal
1116 	 * out-of-bounds access. Return -ENOENT in that case.
1117 	 */
1118 	ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
1119 						 index, &fwnode_args);
1120 	if (ret)
1121 		return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
1122 
1123 	/*
1124 	 * Find a node in the tree under the referred fwnode corresponding to
1125 	 * the integer arguments.
1126 	 */
1127 	fwnode = fwnode_args.fwnode;
1128 	while (nprops--) {
1129 		u32 val;
1130 
1131 		/* Loop over all child nodes under fwnode. */
1132 		fwnode_for_each_child_node(fwnode, child) {
1133 			if (fwnode_property_read_u32(child, *props, &val))
1134 				continue;
1135 
1136 			/* Found property, see if its value matches. */
1137 			if (val == *args)
1138 				break;
1139 		}
1140 
1141 		fwnode_handle_put(fwnode);
1142 
1143 		/* No property found; return an error here. */
1144 		if (!child) {
1145 			fwnode = ERR_PTR(-ENOENT);
1146 			break;
1147 		}
1148 
1149 		props++;
1150 		args++;
1151 		fwnode = child;
1152 	}
1153 
1154 	return fwnode;
1155 }
1156 
1157 struct v4l2_fwnode_int_props {
1158 	const char *name;
1159 	const char * const *props;
1160 	unsigned int nprops;
1161 };
1162 
1163 /*
1164  * v4l2_fwnode_reference_parse_int_props - parse references for async
1165  *					   sub-devices
1166  * @dev: struct device pointer
1167  * @notifier: notifier for @dev
1168  * @prop: the name of the property
1169  * @props: the array of integer property names
1170  * @nprops: the number of integer properties
1171  *
1172  * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
1173  * property @prop with integer arguments with child nodes matching in properties
1174  * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
1175  * accordingly.
1176  *
1177  * While it is technically possible to use this function on DT, it is only
1178  * meaningful on ACPI. On Device tree you can refer to any node in the tree but
1179  * on ACPI the references are limited to devices.
1180  *
1181  * Return: 0 on success
1182  *	   -ENOENT if no entries (or the property itself) were found
1183  *	   -EINVAL if property parsing otherwisefailed
1184  *	   -ENOMEM if memory allocation failed
1185  */
1186 static int
1187 v4l2_fwnode_reference_parse_int_props(struct device *dev,
1188 				      struct v4l2_async_notifier *notifier,
1189 				      const struct v4l2_fwnode_int_props *p)
1190 {
1191 	struct fwnode_handle *fwnode;
1192 	unsigned int index;
1193 	int ret;
1194 	const char *prop = p->name;
1195 	const char * const *props = p->props;
1196 	unsigned int nprops = p->nprops;
1197 
1198 	index = 0;
1199 	do {
1200 		fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1201 							    prop, index,
1202 							    props, nprops);
1203 		if (IS_ERR(fwnode)) {
1204 			/*
1205 			 * Note that right now both -ENODATA and -ENOENT may
1206 			 * signal out-of-bounds access. Return the error in
1207 			 * cases other than that.
1208 			 */
1209 			if (PTR_ERR(fwnode) != -ENOENT &&
1210 			    PTR_ERR(fwnode) != -ENODATA)
1211 				return PTR_ERR(fwnode);
1212 			break;
1213 		}
1214 		fwnode_handle_put(fwnode);
1215 		index++;
1216 	} while (1);
1217 
1218 	for (index = 0;
1219 	     !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1220 								  prop, index,
1221 								  props,
1222 								  nprops)));
1223 	     index++) {
1224 		struct v4l2_async_subdev *asd;
1225 
1226 		asd = v4l2_async_nf_add_fwnode(notifier, fwnode,
1227 					       struct v4l2_async_subdev);
1228 		fwnode_handle_put(fwnode);
1229 		if (IS_ERR(asd)) {
1230 			ret = PTR_ERR(asd);
1231 			/* not an error if asd already exists */
1232 			if (ret == -EEXIST)
1233 				continue;
1234 
1235 			return PTR_ERR(asd);
1236 		}
1237 	}
1238 
1239 	return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1240 }
1241 
1242 /**
1243  * v4l2_async_nf_parse_fwnode_sensor - parse common references on
1244  *					     sensors for async sub-devices
1245  * @dev: the device node the properties of which are parsed for references
1246  * @notifier: the async notifier where the async subdevs will be added
1247  *
1248  * Parse common sensor properties for remote devices related to the
1249  * sensor and set up async sub-devices for them.
1250  *
1251  * Any notifier populated using this function must be released with a call to
1252  * v4l2_async_nf_release() after it has been unregistered and the async
1253  * sub-devices are no longer in use, even in the case the function returned an
1254  * error.
1255  *
1256  * Return: 0 on success
1257  *	   -ENOMEM if memory allocation failed
1258  *	   -EINVAL if property parsing failed
1259  */
1260 static int
1261 v4l2_async_nf_parse_fwnode_sensor(struct device *dev,
1262 				  struct v4l2_async_notifier *notifier)
1263 {
1264 	static const char * const led_props[] = { "led" };
1265 	static const struct v4l2_fwnode_int_props props[] = {
1266 		{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
1267 		{ "lens-focus", NULL, 0 },
1268 	};
1269 	unsigned int i;
1270 
1271 	for (i = 0; i < ARRAY_SIZE(props); i++) {
1272 		int ret;
1273 
1274 		if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1275 			ret = v4l2_fwnode_reference_parse_int_props(dev,
1276 								    notifier,
1277 								    &props[i]);
1278 		else
1279 			ret = v4l2_fwnode_reference_parse(dev, notifier,
1280 							  props[i].name);
1281 		if (ret && ret != -ENOENT) {
1282 			dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1283 				 props[i].name, ret);
1284 			return ret;
1285 		}
1286 	}
1287 
1288 	return 0;
1289 }
1290 
1291 int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
1292 {
1293 	struct v4l2_async_notifier *notifier;
1294 	int ret;
1295 
1296 	if (WARN_ON(!sd->dev))
1297 		return -ENODEV;
1298 
1299 	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1300 	if (!notifier)
1301 		return -ENOMEM;
1302 
1303 	v4l2_async_nf_init(notifier);
1304 
1305 	ret = v4l2_async_nf_parse_fwnode_sensor(sd->dev, notifier);
1306 	if (ret < 0)
1307 		goto out_cleanup;
1308 
1309 	ret = v4l2_async_subdev_nf_register(sd, notifier);
1310 	if (ret < 0)
1311 		goto out_cleanup;
1312 
1313 	ret = v4l2_async_register_subdev(sd);
1314 	if (ret < 0)
1315 		goto out_unregister;
1316 
1317 	sd->subdev_notifier = notifier;
1318 
1319 	return 0;
1320 
1321 out_unregister:
1322 	v4l2_async_nf_unregister(notifier);
1323 
1324 out_cleanup:
1325 	v4l2_async_nf_cleanup(notifier);
1326 	kfree(notifier);
1327 
1328 	return ret;
1329 }
1330 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor);
1331 
1332 MODULE_LICENSE("GPL");
1333 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1334 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1335 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1336