1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
31enum 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,
40};
41
42static 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[] = {
47 {
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",
75 }
76};
77
78static const struct v4l2_fwnode_bus_conv *
79get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
80{
81 unsigned int i;
82
83 for (i = 0; i < ARRAY_SIZE(buses); i++)
84 if (buses[i].fwnode_bus_type == type)
85 return &buses[i];
86
87 return NULL;
88}
89
90static enum v4l2_mbus_type
91v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
92{
93 const struct v4l2_fwnode_bus_conv *conv =
94 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
95
96 return conv ? conv->mbus_type : V4L2_MBUS_UNKNOWN;
97}
98
99static const char *
100v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
101{
102 const struct v4l2_fwnode_bus_conv *conv =
103 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
104
105 return conv ? conv->name : "not found";
106}
107
108static const struct v4l2_fwnode_bus_conv *
109get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
110{
111 unsigned int i;
112
113 for (i = 0; i < ARRAY_SIZE(buses); i++)
114 if (buses[i].mbus_type == type)
115 return &buses[i];
116
117 return NULL;
118}
119
120static const char *
121v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
122{
123 const struct v4l2_fwnode_bus_conv *conv =
124 get_v4l2_fwnode_bus_conv_by_mbus(type);
125
126 return conv ? conv->name : "not found";
127}
128
129static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
130 struct v4l2_fwnode_endpoint *vep,
131 enum v4l2_mbus_type bus_type)
132{
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;
144
145 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
146 bus_type == V4L2_MBUS_CSI2_CPHY) {
147 use_default_lane_mapping = true;
148
149 num_data_lanes = min_t(u32, bus->num_data_lanes,
150 V4L2_FWNODE_CSI2_MAX_DATA_LANES);
151
152 clock_lane = bus->clock_lane;
153 if (clock_lane)
154 use_default_lane_mapping = false;
155
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;
160 }
161
162 if (use_default_lane_mapping)
163 pr_debug("no lane mapping given, using defaults\n");
164 }
165
166 rval = fwnode_property_count_u32(fwnode, "data-lanes");
167 if (rval > 0) {
168 num_data_lanes =
169 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
170
171 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
172 num_data_lanes);
173
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;
178 }
179 }
180
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;
187 }
188 lanes_used |= BIT(array[i]);
189
190 if (have_data_lanes)
191 pr_debug("lane %u position %u\n", i, array[i]);
192 }
193
194 rval = fwnode_property_count_u32(fwnode, "lane-polarities");
195 if (rval > 0) {
196 if (rval != 1 + num_data_lanes ) {
197 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
198 1 + num_data_lanes, rval);
199 return -EINVAL;
200 }
201
202 have_lane_polarities = true;
203 }
204
205 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
206 clock_lane = v;
207 pr_debug("clock lane position %u\n", v);
208 have_clk_lane = true;
209 }
210
211 if (have_clk_lane && lanes_used & BIT(clock_lane) &&
212 !use_default_lane_mapping) {
213 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
214 v);
215 use_default_lane_mapping = true;
216 }
217
218 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
219 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
220 pr_debug("non-continuous clock\n");
221 } else {
222 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
223 }
224
225 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
226 bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
227 have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
228
229 unsigned int dfl_data_lane_index =
230 bus_type == V4L2_MBUS_CSI2_DPHY;
231
232 bus->flags = flags;
233 if (bus_type == V4L2_MBUS_UNKNOWN)
234 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
235 bus->num_data_lanes = num_data_lanes;
236
237 if (use_default_lane_mapping) {
238 bus->clock_lane = 0;
239 for (i = 0; i < num_data_lanes; i++)
240 bus->data_lanes[i] = dfl_data_lane_index + i;
241 } else {
242 bus->clock_lane = clock_lane;
243 for (i = 0; i < num_data_lanes; i++)
244 bus->data_lanes[i] = array[i];
245 }
246
247 if (have_lane_polarities) {
248 fwnode_property_read_u32_array(fwnode,
249 "lane-polarities", array,
250 1 + num_data_lanes);
251
252 for (i = 0; i < 1 + num_data_lanes; i++) {
253 bus->lane_polarities[i] = array[i];
254 pr_debug("lane %u polarity %sinverted",
255 i, array[i] ? "" : "not ");
256 }
257 } else {
258 pr_debug("no lane polarities defined, assuming not inverted\n");
259 }
260 }
261
262 return 0;
263}
264
265#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
266 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
267 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
268 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
269 V4L2_MBUS_FIELD_EVEN_HIGH | \
270 V4L2_MBUS_FIELD_EVEN_LOW)
271
272static void
273v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
274 struct v4l2_fwnode_endpoint *vep,
275 enum v4l2_mbus_type bus_type)
276{
277 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
278 unsigned int flags = 0;
279 u32 v;
280
281 if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
282 flags = bus->flags;
283
284 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
285 flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
286 V4L2_MBUS_HSYNC_ACTIVE_LOW);
287 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
288 V4L2_MBUS_HSYNC_ACTIVE_LOW;
289 pr_debug("hsync-active %s\n", v ? "high" : "low");
290 }
291
292 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
293 flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
294 V4L2_MBUS_VSYNC_ACTIVE_LOW);
295 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
296 V4L2_MBUS_VSYNC_ACTIVE_LOW;
297 pr_debug("vsync-active %s\n", v ? "high" : "low");
298 }
299
300 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
301 flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
302 V4L2_MBUS_FIELD_EVEN_LOW);
303 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
304 V4L2_MBUS_FIELD_EVEN_LOW;
305 pr_debug("field-even-active %s\n", v ? "high" : "low");
306 }
307
308 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
309 flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
310 V4L2_MBUS_PCLK_SAMPLE_FALLING);
311 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
312 V4L2_MBUS_PCLK_SAMPLE_FALLING;
313 pr_debug("pclk-sample %s\n", v ? "high" : "low");
314 }
315
316 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
317 flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
318 V4L2_MBUS_DATA_ACTIVE_LOW);
319 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
320 V4L2_MBUS_DATA_ACTIVE_LOW;
321 pr_debug("data-active %s\n", v ? "high" : "low");
322 }
323
324 if (fwnode_property_present(fwnode, "slave-mode")) {
325 pr_debug("slave mode\n");
326 flags &= ~V4L2_MBUS_MASTER;
327 flags |= V4L2_MBUS_SLAVE;
328 } else {
329 flags &= ~V4L2_MBUS_SLAVE;
330 flags |= V4L2_MBUS_MASTER;
331 }
332
333 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
334 bus->bus_width = v;
335 pr_debug("bus-width %u\n", v);
336 }
337
338 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
339 bus->data_shift = v;
340 pr_debug("data-shift %u\n", v);
341 }
342
343 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
344 flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
345 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
346 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
347 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
348 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
349 }
350
351 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
352 flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
353 V4L2_MBUS_DATA_ENABLE_LOW);
354 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
355 V4L2_MBUS_DATA_ENABLE_LOW;
356 pr_debug("data-enable-active %s\n", v ? "high" : "low");
357 }
358
359 switch (bus_type) {
360 default:
361 bus->flags = flags;
362 if (flags & PARALLEL_MBUS_FLAGS)
363 vep->bus_type = V4L2_MBUS_PARALLEL;
364 else
365 vep->bus_type = V4L2_MBUS_BT656;
366 break;
367 case V4L2_MBUS_PARALLEL:
368 vep->bus_type = V4L2_MBUS_PARALLEL;
369 bus->flags = flags;
370 break;
371 case V4L2_MBUS_BT656:
372 vep->bus_type = V4L2_MBUS_BT656;
373 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
374 break;
375 }
376}
377
378static void
379v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
380 struct v4l2_fwnode_endpoint *vep,
381 enum v4l2_mbus_type bus_type)
382{
383 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
384 u32 v;
385
386 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
387 bus->clock_inv = v;
388 pr_debug("clock-inv %u\n", v);
389 }
390
391 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
392 bus->strobe = v;
393 pr_debug("strobe %u\n", v);
394 }
395
396 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
397 bus->data_lane = v;
398 pr_debug("data-lanes %u\n", v);
399 }
400
401 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
402 bus->clock_lane = v;
403 pr_debug("clock-lanes %u\n", v);
404 }
405
406 if (bus_type == V4L2_MBUS_CCP2)
407 vep->bus_type = V4L2_MBUS_CCP2;
408 else
409 vep->bus_type = V4L2_MBUS_CSI1;
410}
411
412static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
413 struct v4l2_fwnode_endpoint *vep)
414{
415 u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
416 enum v4l2_mbus_type mbus_type;
417 int rval;
418
419 if (vep->bus_type == V4L2_MBUS_UNKNOWN) {
420
421 memset(&vep->bus, 0,
422 sizeof(*vep) - offsetof(typeof(*vep), bus));
423 }
424
425 pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
426
427
428
429
430
431 memset(&vep->base, 0, sizeof(vep->base));
432
433 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
434 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
435 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
436 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
437 vep->bus_type);
438 mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
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
572 fwnode = fwnode_graph_get_remote_endpoint(fwnode);
573 if (!fwnode) {
574 fwnode_handle_put(fwnode);
575 return -ENOLINK;
576 }
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
583 return 0;
584}
585EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
586
587void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
588{
589 fwnode_handle_put(link->local_node);
590 fwnode_handle_put(link->remote_node);
591}
592EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
593
594static const struct v4l2_fwnode_connector_conv {
595 enum v4l2_connector_type type;
596 const char *compatible;
597} connectors[] = {
598 {
599 .type = V4L2_CONN_COMPOSITE,
600 .compatible = "composite-video-connector",
601 }, {
602 .type = V4L2_CONN_SVIDEO,
603 .compatible = "svideo-connector",
604 },
605};
606
607static enum v4l2_connector_type
608v4l2_fwnode_string_to_connector_type(const char *con_str)
609{
610 unsigned int i;
611
612 for (i = 0; i < ARRAY_SIZE(connectors); i++)
613 if (!strcmp(con_str, connectors[i].compatible))
614 return connectors[i].type;
615
616 return V4L2_CONN_UNKNOWN;
617}
618
619static void
620v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
621 struct v4l2_fwnode_connector *vc)
622{
623 u32 stds;
624 int ret;
625
626 ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
627
628
629 vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
630}
631
632void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
633{
634 struct v4l2_connector_link *link, *tmp;
635
636 if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
637 return;
638
639 list_for_each_entry_safe(link, tmp, &connector->links, head) {
640 v4l2_fwnode_put_link(&link->fwnode_link);
641 list_del(&link->head);
642 kfree(link);
643 }
644
645 kfree(connector->label);
646 connector->label = NULL;
647 connector->type = V4L2_CONN_UNKNOWN;
648}
649EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
650
651static enum v4l2_connector_type
652v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
653{
654 const char *type_name;
655 int err;
656
657 if (!fwnode)
658 return V4L2_CONN_UNKNOWN;
659
660
661 err = fwnode_property_read_string(fwnode, "compatible", &type_name);
662 if (err)
663 return V4L2_CONN_UNKNOWN;
664
665 return v4l2_fwnode_string_to_connector_type(type_name);
666}
667
668int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
669 struct v4l2_fwnode_connector *connector)
670{
671 struct fwnode_handle *connector_node;
672 enum v4l2_connector_type connector_type;
673 const char *label;
674 int err;
675
676 if (!fwnode)
677 return -EINVAL;
678
679 memset(connector, 0, sizeof(*connector));
680
681 INIT_LIST_HEAD(&connector->links);
682
683 connector_node = fwnode_graph_get_port_parent(fwnode);
684 connector_type = v4l2_fwnode_get_connector_type(connector_node);
685 if (connector_type == V4L2_CONN_UNKNOWN) {
686 fwnode_handle_put(connector_node);
687 connector_node = fwnode_graph_get_remote_port_parent(fwnode);
688 connector_type = v4l2_fwnode_get_connector_type(connector_node);
689 }
690
691 if (connector_type == V4L2_CONN_UNKNOWN) {
692 pr_err("Unknown connector type\n");
693 err = -ENOTCONN;
694 goto out;
695 }
696
697 connector->type = connector_type;
698 connector->name = fwnode_get_name(connector_node);
699 err = fwnode_property_read_string(connector_node, "label", &label);
700 connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
701
702
703 switch (connector->type) {
704 case V4L2_CONN_COMPOSITE:
705 case V4L2_CONN_SVIDEO:
706 v4l2_fwnode_connector_parse_analog(connector_node, connector);
707 break;
708
709 case V4L2_CONN_UNKNOWN:
710 break;
711 }
712
713out:
714 fwnode_handle_put(connector_node);
715
716 return err;
717}
718EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
719
720int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
721 struct v4l2_fwnode_connector *connector)
722{
723 struct fwnode_handle *connector_ep;
724 struct v4l2_connector_link *link;
725 int err;
726
727 if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
728 return -EINVAL;
729
730 connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
731 if (!connector_ep)
732 return -ENOTCONN;
733
734 link = kzalloc(sizeof(*link), GFP_KERNEL);
735 if (!link) {
736 err = -ENOMEM;
737 goto err;
738 }
739
740 err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
741 if (err)
742 goto err;
743
744 fwnode_handle_put(connector_ep);
745
746 list_add(&link->head, &connector->links);
747 connector->nr_of_links++;
748
749 return 0;
750
751err:
752 kfree(link);
753 fwnode_handle_put(connector_ep);
754
755 return err;
756}
757EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
758
759int v4l2_fwnode_device_parse(struct device *dev,
760 struct v4l2_fwnode_device_properties *props)
761{
762 struct fwnode_handle *fwnode = dev_fwnode(dev);
763 u32 val;
764 int ret;
765
766 memset(props, 0, sizeof(*props));
767
768 props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
769 ret = fwnode_property_read_u32(fwnode, "orientation", &val);
770 if (!ret) {
771 switch (val) {
772 case V4L2_FWNODE_ORIENTATION_FRONT:
773 case V4L2_FWNODE_ORIENTATION_BACK:
774 case V4L2_FWNODE_ORIENTATION_EXTERNAL:
775 break;
776 default:
777 dev_warn(dev, "Unsupported device orientation: %u\n", val);
778 return -EINVAL;
779 }
780
781 props->orientation = val;
782 dev_dbg(dev, "device orientation: %u\n", val);
783 }
784
785 props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
786 ret = fwnode_property_read_u32(fwnode, "rotation", &val);
787 if (!ret) {
788 if (val >= 360) {
789 dev_warn(dev, "Unsupported device rotation: %u\n", val);
790 return -EINVAL;
791 }
792
793 props->rotation = val;
794 dev_dbg(dev, "device rotation: %u\n", val);
795 }
796
797 return 0;
798}
799EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
800
801static int
802v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
803 struct v4l2_async_notifier *notifier,
804 struct fwnode_handle *endpoint,
805 unsigned int asd_struct_size,
806 parse_endpoint_func parse_endpoint)
807{
808 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
809 struct v4l2_async_subdev *asd;
810 int ret;
811
812 asd = kzalloc(asd_struct_size, GFP_KERNEL);
813 if (!asd)
814 return -ENOMEM;
815
816 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
817 asd->match.fwnode =
818 fwnode_graph_get_remote_port_parent(endpoint);
819 if (!asd->match.fwnode) {
820 dev_dbg(dev, "no remote endpoint found\n");
821 ret = -ENOTCONN;
822 goto out_err;
823 }
824
825 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
826 if (ret) {
827 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
828 ret);
829 goto out_err;
830 }
831
832 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
833 if (ret == -ENOTCONN)
834 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
835 vep.base.id);
836 else if (ret < 0)
837 dev_warn(dev,
838 "driver could not parse port@%u/endpoint@%u (%d)\n",
839 vep.base.port, vep.base.id, ret);
840 v4l2_fwnode_endpoint_free(&vep);
841 if (ret < 0)
842 goto out_err;
843
844 ret = v4l2_async_notifier_add_subdev(notifier, asd);
845 if (ret < 0) {
846
847 if (ret == -EEXIST)
848 ret = 0;
849 goto out_err;
850 }
851
852 return 0;
853
854out_err:
855 fwnode_handle_put(asd->match.fwnode);
856 kfree(asd);
857
858 return ret == -ENOTCONN ? 0 : ret;
859}
860
861static int
862__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
863 struct v4l2_async_notifier *notifier,
864 size_t asd_struct_size,
865 unsigned int port,
866 bool has_port,
867 parse_endpoint_func parse_endpoint)
868{
869 struct fwnode_handle *fwnode;
870 int ret = 0;
871
872 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
873 return -EINVAL;
874
875 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
876 struct fwnode_handle *dev_fwnode;
877 bool is_available;
878
879 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
880 is_available = fwnode_device_is_available(dev_fwnode);
881 fwnode_handle_put(dev_fwnode);
882 if (!is_available)
883 continue;
884
885 if (has_port) {
886 struct fwnode_endpoint ep;
887
888 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
889 if (ret)
890 break;
891
892 if (ep.port != port)
893 continue;
894 }
895
896 ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
897 notifier,
898 fwnode,
899 asd_struct_size,
900 parse_endpoint);
901 if (ret < 0)
902 break;
903 }
904
905 fwnode_handle_put(fwnode);
906
907 return ret;
908}
909
910int
911v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
912 struct v4l2_async_notifier *notifier,
913 size_t asd_struct_size,
914 parse_endpoint_func parse_endpoint)
915{
916 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
917 asd_struct_size, 0,
918 false, parse_endpoint);
919}
920EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
921
922int
923v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
924 struct v4l2_async_notifier *notifier,
925 size_t asd_struct_size,
926 unsigned int port,
927 parse_endpoint_func parse_endpoint)
928{
929 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
930 asd_struct_size,
931 port, true,
932 parse_endpoint);
933}
934EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
935
936
937
938
939
940
941
942
943
944
945
946
947static int v4l2_fwnode_reference_parse(struct device *dev,
948 struct v4l2_async_notifier *notifier,
949 const char *prop)
950{
951 struct fwnode_reference_args args;
952 unsigned int index;
953 int ret;
954
955 for (index = 0;
956 !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
957 prop, NULL, 0,
958 index, &args));
959 index++)
960 fwnode_handle_put(args.fwnode);
961
962 if (!index)
963 return -ENOENT;
964
965
966
967
968
969 if (ret != -ENOENT && ret != -ENODATA)
970 return ret;
971
972 for (index = 0;
973 !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
974 0, index, &args);
975 index++) {
976 struct v4l2_async_subdev *asd;
977
978 asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
979 args.fwnode,
980 sizeof(*asd));
981 fwnode_handle_put(args.fwnode);
982 if (IS_ERR(asd)) {
983
984 if (PTR_ERR(asd) == -EEXIST)
985 continue;
986
987 return PTR_ERR(asd);
988 }
989 }
990
991 return 0;
992}
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153static struct fwnode_handle *
1154v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
1155 const char *prop,
1156 unsigned int index,
1157 const char * const *props,
1158 unsigned int nprops)
1159{
1160 struct fwnode_reference_args fwnode_args;
1161 u64 *args = fwnode_args.args;
1162 struct fwnode_handle *child;
1163 int ret;
1164
1165
1166
1167
1168
1169
1170
1171 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
1172 index, &fwnode_args);
1173 if (ret)
1174 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
1175
1176
1177
1178
1179
1180 fwnode = fwnode_args.fwnode;
1181 while (nprops--) {
1182 u32 val;
1183
1184
1185 fwnode_for_each_child_node(fwnode, child) {
1186 if (fwnode_property_read_u32(child, *props, &val))
1187 continue;
1188
1189
1190 if (val == *args)
1191 break;
1192 }
1193
1194 fwnode_handle_put(fwnode);
1195
1196
1197 if (!child) {
1198 fwnode = ERR_PTR(-ENOENT);
1199 break;
1200 }
1201
1202 props++;
1203 args++;
1204 fwnode = child;
1205 }
1206
1207 return fwnode;
1208}
1209
1210struct v4l2_fwnode_int_props {
1211 const char *name;
1212 const char * const *props;
1213 unsigned int nprops;
1214};
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239static int
1240v4l2_fwnode_reference_parse_int_props(struct device *dev,
1241 struct v4l2_async_notifier *notifier,
1242 const struct v4l2_fwnode_int_props *p)
1243{
1244 struct fwnode_handle *fwnode;
1245 unsigned int index;
1246 int ret;
1247 const char *prop = p->name;
1248 const char * const *props = p->props;
1249 unsigned int nprops = p->nprops;
1250
1251 index = 0;
1252 do {
1253 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1254 prop, index,
1255 props, nprops);
1256 if (IS_ERR(fwnode)) {
1257
1258
1259
1260
1261
1262 if (PTR_ERR(fwnode) != -ENOENT &&
1263 PTR_ERR(fwnode) != -ENODATA)
1264 return PTR_ERR(fwnode);
1265 break;
1266 }
1267 fwnode_handle_put(fwnode);
1268 index++;
1269 } while (1);
1270
1271 for (index = 0;
1272 !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1273 prop, index,
1274 props,
1275 nprops)));
1276 index++) {
1277 struct v4l2_async_subdev *asd;
1278
1279 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1280 sizeof(*asd));
1281 fwnode_handle_put(fwnode);
1282 if (IS_ERR(asd)) {
1283 ret = PTR_ERR(asd);
1284
1285 if (ret == -EEXIST)
1286 continue;
1287
1288 return PTR_ERR(asd);
1289 }
1290 }
1291
1292 return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1293}
1294
1295int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev,
1296 struct v4l2_async_notifier *notifier)
1297{
1298 static const char * const led_props[] = { "led" };
1299 static const struct v4l2_fwnode_int_props props[] = {
1300 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
1301 { "lens-focus", NULL, 0 },
1302 };
1303 unsigned int i;
1304
1305 for (i = 0; i < ARRAY_SIZE(props); i++) {
1306 int ret;
1307
1308 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1309 ret = v4l2_fwnode_reference_parse_int_props(dev,
1310 notifier,
1311 &props[i]);
1312 else
1313 ret = v4l2_fwnode_reference_parse(dev, notifier,
1314 props[i].name);
1315 if (ret && ret != -ENOENT) {
1316 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1317 props[i].name, ret);
1318 return ret;
1319 }
1320 }
1321
1322 return 0;
1323}
1324EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
1325
1326int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
1327{
1328 struct v4l2_async_notifier *notifier;
1329 int ret;
1330
1331 if (WARN_ON(!sd->dev))
1332 return -ENODEV;
1333
1334 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1335 if (!notifier)
1336 return -ENOMEM;
1337
1338 v4l2_async_notifier_init(notifier);
1339
1340 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
1341 notifier);
1342 if (ret < 0)
1343 goto out_cleanup;
1344
1345 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1346 if (ret < 0)
1347 goto out_cleanup;
1348
1349 ret = v4l2_async_register_subdev(sd);
1350 if (ret < 0)
1351 goto out_unregister;
1352
1353 sd->subdev_notifier = notifier;
1354
1355 return 0;
1356
1357out_unregister:
1358 v4l2_async_notifier_unregister(notifier);
1359
1360out_cleanup:
1361 v4l2_async_notifier_cleanup(notifier);
1362 kfree(notifier);
1363
1364 return ret;
1365}
1366EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
1367
1368MODULE_LICENSE("GPL");
1369MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1370MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1371MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1372