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