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
31static 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};
66
67static const struct v4l2_fwnode_bus_conv *
68get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
69{
70 unsigned int i;
71
72 for (i = 0; i < ARRAY_SIZE(buses); i++)
73 if (buses[i].fwnode_bus_type == type)
74 return &buses[i];
75
76 return NULL;
77}
78
79static enum v4l2_mbus_type
80v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
81{
82 const struct v4l2_fwnode_bus_conv *conv =
83 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
84
85 return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
86}
87
88static const char *
89v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
90{
91 const struct v4l2_fwnode_bus_conv *conv =
92 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
93
94 return conv ? conv->name : "not found";
95}
96
97static const struct v4l2_fwnode_bus_conv *
98get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
99{
100 unsigned int i;
101
102 for (i = 0; i < ARRAY_SIZE(buses); i++)
103 if (buses[i].mbus_type == type)
104 return &buses[i];
105
106 return NULL;
107}
108
109static const char *
110v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
111{
112 const struct v4l2_fwnode_bus_conv *conv =
113 get_v4l2_fwnode_bus_conv_by_mbus(type);
114
115 return conv ? conv->name : "not found";
116}
117
118static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
119 struct v4l2_fwnode_endpoint *vep,
120 enum v4l2_mbus_type bus_type)
121{
122 struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
123 bool have_clk_lane = false, have_data_lanes = false,
124 have_lane_polarities = false;
125 unsigned int flags = 0, lanes_used = 0;
126 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
127 u32 clock_lane = 0;
128 unsigned int num_data_lanes = 0;
129 bool use_default_lane_mapping = false;
130 unsigned int i;
131 u32 v;
132 int rval;
133
134 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
135 bus_type == V4L2_MBUS_CSI2_CPHY) {
136 use_default_lane_mapping = true;
137
138 num_data_lanes = min_t(u32, bus->num_data_lanes,
139 V4L2_FWNODE_CSI2_MAX_DATA_LANES);
140
141 clock_lane = bus->clock_lane;
142 if (clock_lane)
143 use_default_lane_mapping = false;
144
145 for (i = 0; i < num_data_lanes; i++) {
146 array[i] = bus->data_lanes[i];
147 if (array[i])
148 use_default_lane_mapping = false;
149 }
150
151 if (use_default_lane_mapping)
152 pr_debug("no lane mapping given, using defaults\n");
153 }
154
155 rval = fwnode_property_count_u32(fwnode, "data-lanes");
156 if (rval > 0) {
157 num_data_lanes =
158 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
159
160 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
161 num_data_lanes);
162
163 have_data_lanes = true;
164 if (use_default_lane_mapping) {
165 pr_debug("data-lanes property exists; disabling default mapping\n");
166 use_default_lane_mapping = false;
167 }
168 }
169
170 for (i = 0; i < num_data_lanes; i++) {
171 if (lanes_used & BIT(array[i])) {
172 if (have_data_lanes || !use_default_lane_mapping)
173 pr_warn("duplicated lane %u in data-lanes, using defaults\n",
174 array[i]);
175 use_default_lane_mapping = true;
176 }
177 lanes_used |= BIT(array[i]);
178
179 if (have_data_lanes)
180 pr_debug("lane %u position %u\n", i, array[i]);
181 }
182
183 rval = fwnode_property_count_u32(fwnode, "lane-polarities");
184 if (rval > 0) {
185 if (rval != 1 + num_data_lanes ) {
186 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
187 1 + num_data_lanes, rval);
188 return -EINVAL;
189 }
190
191 have_lane_polarities = true;
192 }
193
194 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
195 clock_lane = v;
196 pr_debug("clock lane position %u\n", v);
197 have_clk_lane = true;
198 }
199
200 if (have_clk_lane && lanes_used & BIT(clock_lane) &&
201 !use_default_lane_mapping) {
202 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
203 v);
204 use_default_lane_mapping = true;
205 }
206
207 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
208 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
209 pr_debug("non-continuous clock\n");
210 } else {
211 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
212 }
213
214 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
215 bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
216 have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
217
218 unsigned int dfl_data_lane_index =
219 bus_type == V4L2_MBUS_CSI2_DPHY;
220
221 bus->flags = flags;
222 if (bus_type == V4L2_MBUS_UNKNOWN)
223 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
224 bus->num_data_lanes = num_data_lanes;
225
226 if (use_default_lane_mapping) {
227 bus->clock_lane = 0;
228 for (i = 0; i < num_data_lanes; i++)
229 bus->data_lanes[i] = dfl_data_lane_index + i;
230 } else {
231 bus->clock_lane = clock_lane;
232 for (i = 0; i < num_data_lanes; i++)
233 bus->data_lanes[i] = array[i];
234 }
235
236 if (have_lane_polarities) {
237 fwnode_property_read_u32_array(fwnode,
238 "lane-polarities", array,
239 1 + num_data_lanes);
240
241 for (i = 0; i < 1 + num_data_lanes; i++) {
242 bus->lane_polarities[i] = array[i];
243 pr_debug("lane %u polarity %sinverted",
244 i, array[i] ? "" : "not ");
245 }
246 } else {
247 pr_debug("no lane polarities defined, assuming not inverted\n");
248 }
249 }
250
251 return 0;
252}
253
254#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
255 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
256 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
257 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
258 V4L2_MBUS_FIELD_EVEN_HIGH | \
259 V4L2_MBUS_FIELD_EVEN_LOW)
260
261static void
262v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
263 struct v4l2_fwnode_endpoint *vep,
264 enum v4l2_mbus_type bus_type)
265{
266 struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
267 unsigned int flags = 0;
268 u32 v;
269
270 if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
271 flags = bus->flags;
272
273 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
274 flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
275 V4L2_MBUS_HSYNC_ACTIVE_LOW);
276 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
277 V4L2_MBUS_HSYNC_ACTIVE_LOW;
278 pr_debug("hsync-active %s\n", v ? "high" : "low");
279 }
280
281 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
282 flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
283 V4L2_MBUS_VSYNC_ACTIVE_LOW);
284 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
285 V4L2_MBUS_VSYNC_ACTIVE_LOW;
286 pr_debug("vsync-active %s\n", v ? "high" : "low");
287 }
288
289 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
290 flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
291 V4L2_MBUS_FIELD_EVEN_LOW);
292 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
293 V4L2_MBUS_FIELD_EVEN_LOW;
294 pr_debug("field-even-active %s\n", v ? "high" : "low");
295 }
296
297 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
298 flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
299 V4L2_MBUS_PCLK_SAMPLE_FALLING);
300 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
301 V4L2_MBUS_PCLK_SAMPLE_FALLING;
302 pr_debug("pclk-sample %s\n", v ? "high" : "low");
303 }
304
305 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
306 flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
307 V4L2_MBUS_DATA_ACTIVE_LOW);
308 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
309 V4L2_MBUS_DATA_ACTIVE_LOW;
310 pr_debug("data-active %s\n", v ? "high" : "low");
311 }
312
313 if (fwnode_property_present(fwnode, "slave-mode")) {
314 pr_debug("slave mode\n");
315 flags &= ~V4L2_MBUS_MASTER;
316 flags |= V4L2_MBUS_SLAVE;
317 } else {
318 flags &= ~V4L2_MBUS_SLAVE;
319 flags |= V4L2_MBUS_MASTER;
320 }
321
322 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
323 bus->bus_width = v;
324 pr_debug("bus-width %u\n", v);
325 }
326
327 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
328 bus->data_shift = v;
329 pr_debug("data-shift %u\n", v);
330 }
331
332 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
333 flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
334 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
335 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
336 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
337 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
338 }
339
340 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
341 flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
342 V4L2_MBUS_DATA_ENABLE_LOW);
343 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
344 V4L2_MBUS_DATA_ENABLE_LOW;
345 pr_debug("data-enable-active %s\n", v ? "high" : "low");
346 }
347
348 switch (bus_type) {
349 default:
350 bus->flags = flags;
351 if (flags & PARALLEL_MBUS_FLAGS)
352 vep->bus_type = V4L2_MBUS_PARALLEL;
353 else
354 vep->bus_type = V4L2_MBUS_BT656;
355 break;
356 case V4L2_MBUS_PARALLEL:
357 vep->bus_type = V4L2_MBUS_PARALLEL;
358 bus->flags = flags;
359 break;
360 case V4L2_MBUS_BT656:
361 vep->bus_type = V4L2_MBUS_BT656;
362 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
363 break;
364 }
365}
366
367static void
368v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
369 struct v4l2_fwnode_endpoint *vep,
370 enum v4l2_mbus_type bus_type)
371{
372 struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
373 u32 v;
374
375 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
376 bus->clock_inv = v;
377 pr_debug("clock-inv %u\n", v);
378 }
379
380 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
381 bus->strobe = v;
382 pr_debug("strobe %u\n", v);
383 }
384
385 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
386 bus->data_lane = v;
387 pr_debug("data-lanes %u\n", v);
388 }
389
390 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
391 bus->clock_lane = v;
392 pr_debug("clock-lanes %u\n", v);
393 }
394
395 if (bus_type == V4L2_MBUS_CCP2)
396 vep->bus_type = V4L2_MBUS_CCP2;
397 else
398 vep->bus_type = V4L2_MBUS_CSI1;
399}
400
401static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
402 struct v4l2_fwnode_endpoint *vep)
403{
404 u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
405 enum v4l2_mbus_type mbus_type;
406 int rval;
407
408 pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
409
410 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
411 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
412 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
413 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
414 vep->bus_type);
415 mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
416 if (mbus_type == V4L2_MBUS_INVALID) {
417 pr_debug("unsupported bus type %u\n", bus_type);
418 return -EINVAL;
419 }
420
421 if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
422 if (mbus_type != V4L2_MBUS_UNKNOWN &&
423 vep->bus_type != mbus_type) {
424 pr_debug("expecting bus type %s\n",
425 v4l2_fwnode_mbus_type_to_string(vep->bus_type));
426 return -ENXIO;
427 }
428 } else {
429 vep->bus_type = mbus_type;
430 }
431
432 switch (vep->bus_type) {
433 case V4L2_MBUS_UNKNOWN:
434 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
435 V4L2_MBUS_UNKNOWN);
436 if (rval)
437 return rval;
438
439 if (vep->bus_type == V4L2_MBUS_UNKNOWN)
440 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
441 V4L2_MBUS_UNKNOWN);
442
443 pr_debug("assuming media bus type %s (%u)\n",
444 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
445 vep->bus_type);
446
447 break;
448 case V4L2_MBUS_CCP2:
449 case V4L2_MBUS_CSI1:
450 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
451
452 break;
453 case V4L2_MBUS_CSI2_DPHY:
454 case V4L2_MBUS_CSI2_CPHY:
455 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
456 vep->bus_type);
457 if (rval)
458 return rval;
459
460 break;
461 case V4L2_MBUS_PARALLEL:
462 case V4L2_MBUS_BT656:
463 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
464 vep->bus_type);
465
466 break;
467 default:
468 pr_warn("unsupported bus type %u\n", mbus_type);
469 return -EINVAL;
470 }
471
472 fwnode_graph_parse_endpoint(fwnode, &vep->base);
473
474 return 0;
475}
476
477int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
478 struct v4l2_fwnode_endpoint *vep)
479{
480 int ret;
481
482 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
483
484 pr_debug("===== end parsing endpoint %pfw\n", fwnode);
485
486 return ret;
487}
488EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
489
490void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
491{
492 if (IS_ERR_OR_NULL(vep))
493 return;
494
495 kfree(vep->link_frequencies);
496 vep->link_frequencies = NULL;
497}
498EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
499
500int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
501 struct v4l2_fwnode_endpoint *vep)
502{
503 int rval;
504
505 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
506 if (rval < 0)
507 return rval;
508
509 rval = fwnode_property_count_u64(fwnode, "link-frequencies");
510 if (rval > 0) {
511 unsigned int i;
512
513 vep->link_frequencies =
514 kmalloc_array(rval, sizeof(*vep->link_frequencies),
515 GFP_KERNEL);
516 if (!vep->link_frequencies)
517 return -ENOMEM;
518
519 vep->nr_of_link_frequencies = rval;
520
521 rval = fwnode_property_read_u64_array(fwnode,
522 "link-frequencies",
523 vep->link_frequencies,
524 vep->nr_of_link_frequencies);
525 if (rval < 0) {
526 v4l2_fwnode_endpoint_free(vep);
527 return rval;
528 }
529
530 for (i = 0; i < vep->nr_of_link_frequencies; i++)
531 pr_debug("link-frequencies %u value %llu\n", i,
532 vep->link_frequencies[i]);
533 }
534
535 pr_debug("===== end parsing endpoint %pfw\n", fwnode);
536
537 return 0;
538}
539EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
540
541int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
542 struct v4l2_fwnode_link *link)
543{
544 struct fwnode_endpoint fwep;
545
546 memset(link, 0, sizeof(*link));
547
548 fwnode_graph_parse_endpoint(fwnode, &fwep);
549 link->local_id = fwep.id;
550 link->local_port = fwep.port;
551 link->local_node = fwnode_graph_get_port_parent(fwnode);
552
553 fwnode = fwnode_graph_get_remote_endpoint(fwnode);
554 if (!fwnode) {
555 fwnode_handle_put(fwnode);
556 return -ENOLINK;
557 }
558
559 fwnode_graph_parse_endpoint(fwnode, &fwep);
560 link->remote_id = fwep.id;
561 link->remote_port = fwep.port;
562 link->remote_node = fwnode_graph_get_port_parent(fwnode);
563
564 return 0;
565}
566EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
567
568void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
569{
570 fwnode_handle_put(link->local_node);
571 fwnode_handle_put(link->remote_node);
572}
573EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
574
575static const struct v4l2_fwnode_connector_conv {
576 enum v4l2_connector_type type;
577 const char *compatible;
578} connectors[] = {
579 {
580 .type = V4L2_CONN_COMPOSITE,
581 .compatible = "composite-video-connector",
582 }, {
583 .type = V4L2_CONN_SVIDEO,
584 .compatible = "svideo-connector",
585 },
586};
587
588static enum v4l2_connector_type
589v4l2_fwnode_string_to_connector_type(const char *con_str)
590{
591 unsigned int i;
592
593 for (i = 0; i < ARRAY_SIZE(connectors); i++)
594 if (!strcmp(con_str, connectors[i].compatible))
595 return connectors[i].type;
596
597 return V4L2_CONN_UNKNOWN;
598}
599
600static void
601v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
602 struct v4l2_fwnode_connector *vc)
603{
604 u32 stds;
605 int ret;
606
607 ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
608
609
610 vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
611}
612
613void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
614{
615 struct v4l2_connector_link *link, *tmp;
616
617 if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
618 return;
619
620 list_for_each_entry_safe(link, tmp, &connector->links, head) {
621 v4l2_fwnode_put_link(&link->fwnode_link);
622 list_del(&link->head);
623 kfree(link);
624 }
625
626 kfree(connector->label);
627 connector->label = NULL;
628 connector->type = V4L2_CONN_UNKNOWN;
629}
630EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
631
632static enum v4l2_connector_type
633v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
634{
635 const char *type_name;
636 int err;
637
638 if (!fwnode)
639 return V4L2_CONN_UNKNOWN;
640
641
642 err = fwnode_property_read_string(fwnode, "compatible", &type_name);
643 if (err)
644 return V4L2_CONN_UNKNOWN;
645
646 return v4l2_fwnode_string_to_connector_type(type_name);
647}
648
649int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
650 struct v4l2_fwnode_connector *connector)
651{
652 struct fwnode_handle *connector_node;
653 enum v4l2_connector_type connector_type;
654 const char *label;
655 int err;
656
657 if (!fwnode)
658 return -EINVAL;
659
660 memset(connector, 0, sizeof(*connector));
661
662 INIT_LIST_HEAD(&connector->links);
663
664 connector_node = fwnode_graph_get_port_parent(fwnode);
665 connector_type = v4l2_fwnode_get_connector_type(connector_node);
666 if (connector_type == V4L2_CONN_UNKNOWN) {
667 fwnode_handle_put(connector_node);
668 connector_node = fwnode_graph_get_remote_port_parent(fwnode);
669 connector_type = v4l2_fwnode_get_connector_type(connector_node);
670 }
671
672 if (connector_type == V4L2_CONN_UNKNOWN) {
673 pr_err("Unknown connector type\n");
674 err = -ENOTCONN;
675 goto out;
676 }
677
678 connector->type = connector_type;
679 connector->name = fwnode_get_name(connector_node);
680 err = fwnode_property_read_string(connector_node, "label", &label);
681 connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
682
683
684 switch (connector->type) {
685 case V4L2_CONN_COMPOSITE:
686 case V4L2_CONN_SVIDEO:
687 v4l2_fwnode_connector_parse_analog(connector_node, connector);
688 break;
689
690 case V4L2_CONN_UNKNOWN:
691 break;
692 }
693
694out:
695 fwnode_handle_put(connector_node);
696
697 return err;
698}
699EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
700
701int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
702 struct v4l2_fwnode_connector *connector)
703{
704 struct fwnode_handle *connector_ep;
705 struct v4l2_connector_link *link;
706 int err;
707
708 if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
709 return -EINVAL;
710
711 connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
712 if (!connector_ep)
713 return -ENOTCONN;
714
715 link = kzalloc(sizeof(*link), GFP_KERNEL);
716 if (!link) {
717 err = -ENOMEM;
718 goto err;
719 }
720
721 err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
722 if (err)
723 goto err;
724
725 fwnode_handle_put(connector_ep);
726
727 list_add(&link->head, &connector->links);
728 connector->nr_of_links++;
729
730 return 0;
731
732err:
733 kfree(link);
734 fwnode_handle_put(connector_ep);
735
736 return err;
737}
738EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
739
740int v4l2_fwnode_device_parse(struct device *dev,
741 struct v4l2_fwnode_device_properties *props)
742{
743 struct fwnode_handle *fwnode = dev_fwnode(dev);
744 u32 val;
745 int ret;
746
747 memset(props, 0, sizeof(*props));
748
749 props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
750 ret = fwnode_property_read_u32(fwnode, "orientation", &val);
751 if (!ret) {
752 switch (val) {
753 case V4L2_FWNODE_ORIENTATION_FRONT:
754 case V4L2_FWNODE_ORIENTATION_BACK:
755 case V4L2_FWNODE_ORIENTATION_EXTERNAL:
756 break;
757 default:
758 dev_warn(dev, "Unsupported device orientation: %u\n", val);
759 return -EINVAL;
760 }
761
762 props->orientation = val;
763 dev_dbg(dev, "device orientation: %u\n", val);
764 }
765
766 props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
767 ret = fwnode_property_read_u32(fwnode, "rotation", &val);
768 if (!ret) {
769 if (val >= 360) {
770 dev_warn(dev, "Unsupported device rotation: %u\n", val);
771 return -EINVAL;
772 }
773
774 props->rotation = val;
775 dev_dbg(dev, "device rotation: %u\n", val);
776 }
777
778 return 0;
779}
780EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
781
782static int
783v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
784 struct v4l2_async_notifier *notifier,
785 struct fwnode_handle *endpoint,
786 unsigned int asd_struct_size,
787 parse_endpoint_func parse_endpoint)
788{
789 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
790 struct v4l2_async_subdev *asd;
791 int ret;
792
793 asd = kzalloc(asd_struct_size, GFP_KERNEL);
794 if (!asd)
795 return -ENOMEM;
796
797 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
798 asd->match.fwnode =
799 fwnode_graph_get_remote_port_parent(endpoint);
800 if (!asd->match.fwnode) {
801 dev_dbg(dev, "no remote endpoint found\n");
802 ret = -ENOTCONN;
803 goto out_err;
804 }
805
806 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
807 if (ret) {
808 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
809 ret);
810 goto out_err;
811 }
812
813 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
814 if (ret == -ENOTCONN)
815 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
816 vep.base.id);
817 else if (ret < 0)
818 dev_warn(dev,
819 "driver could not parse port@%u/endpoint@%u (%d)\n",
820 vep.base.port, vep.base.id, ret);
821 v4l2_fwnode_endpoint_free(&vep);
822 if (ret < 0)
823 goto out_err;
824
825 ret = __v4l2_async_notifier_add_subdev(notifier, asd);
826 if (ret < 0) {
827
828 if (ret == -EEXIST)
829 ret = 0;
830 goto out_err;
831 }
832
833 return 0;
834
835out_err:
836 fwnode_handle_put(asd->match.fwnode);
837 kfree(asd);
838
839 return ret == -ENOTCONN ? 0 : ret;
840}
841
842static int
843__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
844 struct v4l2_async_notifier *notifier,
845 size_t asd_struct_size,
846 unsigned int port,
847 bool has_port,
848 parse_endpoint_func parse_endpoint)
849{
850 struct fwnode_handle *fwnode;
851 int ret = 0;
852
853 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
854 return -EINVAL;
855
856 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
857 struct fwnode_handle *dev_fwnode;
858 bool is_available;
859
860 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
861 is_available = fwnode_device_is_available(dev_fwnode);
862 fwnode_handle_put(dev_fwnode);
863 if (!is_available)
864 continue;
865
866 if (has_port) {
867 struct fwnode_endpoint ep;
868
869 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
870 if (ret)
871 break;
872
873 if (ep.port != port)
874 continue;
875 }
876
877 ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
878 notifier,
879 fwnode,
880 asd_struct_size,
881 parse_endpoint);
882 if (ret < 0)
883 break;
884 }
885
886 fwnode_handle_put(fwnode);
887
888 return ret;
889}
890
891int
892v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
893 struct v4l2_async_notifier *notifier,
894 size_t asd_struct_size,
895 parse_endpoint_func parse_endpoint)
896{
897 return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
898 asd_struct_size, 0,
899 false, parse_endpoint);
900}
901EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
902
903
904
905
906
907
908
909
910
911
912
913
914static int v4l2_fwnode_reference_parse(struct device *dev,
915 struct v4l2_async_notifier *notifier,
916 const char *prop)
917{
918 struct fwnode_reference_args args;
919 unsigned int index;
920 int ret;
921
922 for (index = 0;
923 !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
924 prop, NULL, 0,
925 index, &args));
926 index++)
927 fwnode_handle_put(args.fwnode);
928
929 if (!index)
930 return -ENOENT;
931
932
933
934
935
936 if (ret != -ENOENT && ret != -ENODATA)
937 return ret;
938
939 for (index = 0;
940 !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
941 0, index, &args);
942 index++) {
943 struct v4l2_async_subdev *asd;
944
945 asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
946 args.fwnode,
947 struct v4l2_async_subdev);
948 fwnode_handle_put(args.fwnode);
949 if (IS_ERR(asd)) {
950
951 if (PTR_ERR(asd) == -EEXIST)
952 continue;
953
954 return PTR_ERR(asd);
955 }
956 }
957
958 return 0;
959}
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
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
1120static struct fwnode_handle *
1121v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
1122 const char *prop,
1123 unsigned int index,
1124 const char * const *props,
1125 unsigned int nprops)
1126{
1127 struct fwnode_reference_args fwnode_args;
1128 u64 *args = fwnode_args.args;
1129 struct fwnode_handle *child;
1130 int ret;
1131
1132
1133
1134
1135
1136
1137
1138 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
1139 index, &fwnode_args);
1140 if (ret)
1141 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
1142
1143
1144
1145
1146
1147 fwnode = fwnode_args.fwnode;
1148 while (nprops--) {
1149 u32 val;
1150
1151
1152 fwnode_for_each_child_node(fwnode, child) {
1153 if (fwnode_property_read_u32(child, *props, &val))
1154 continue;
1155
1156
1157 if (val == *args)
1158 break;
1159 }
1160
1161 fwnode_handle_put(fwnode);
1162
1163
1164 if (!child) {
1165 fwnode = ERR_PTR(-ENOENT);
1166 break;
1167 }
1168
1169 props++;
1170 args++;
1171 fwnode = child;
1172 }
1173
1174 return fwnode;
1175}
1176
1177struct v4l2_fwnode_int_props {
1178 const char *name;
1179 const char * const *props;
1180 unsigned int nprops;
1181};
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206static int
1207v4l2_fwnode_reference_parse_int_props(struct device *dev,
1208 struct v4l2_async_notifier *notifier,
1209 const struct v4l2_fwnode_int_props *p)
1210{
1211 struct fwnode_handle *fwnode;
1212 unsigned int index;
1213 int ret;
1214 const char *prop = p->name;
1215 const char * const *props = p->props;
1216 unsigned int nprops = p->nprops;
1217
1218 index = 0;
1219 do {
1220 fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1221 prop, index,
1222 props, nprops);
1223 if (IS_ERR(fwnode)) {
1224
1225
1226
1227
1228
1229 if (PTR_ERR(fwnode) != -ENOENT &&
1230 PTR_ERR(fwnode) != -ENODATA)
1231 return PTR_ERR(fwnode);
1232 break;
1233 }
1234 fwnode_handle_put(fwnode);
1235 index++;
1236 } while (1);
1237
1238 for (index = 0;
1239 !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1240 prop, index,
1241 props,
1242 nprops)));
1243 index++) {
1244 struct v4l2_async_subdev *asd;
1245
1246 asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1247 struct v4l2_async_subdev);
1248 fwnode_handle_put(fwnode);
1249 if (IS_ERR(asd)) {
1250 ret = PTR_ERR(asd);
1251
1252 if (ret == -EEXIST)
1253 continue;
1254
1255 return PTR_ERR(asd);
1256 }
1257 }
1258
1259 return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1260}
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280static int
1281v4l2_async_notifier_parse_fwnode_sensor(struct device *dev,
1282 struct v4l2_async_notifier *notifier)
1283{
1284 static const char * const led_props[] = { "led" };
1285 static const struct v4l2_fwnode_int_props props[] = {
1286 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
1287 { "lens-focus", NULL, 0 },
1288 };
1289 unsigned int i;
1290
1291 for (i = 0; i < ARRAY_SIZE(props); i++) {
1292 int ret;
1293
1294 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1295 ret = v4l2_fwnode_reference_parse_int_props(dev,
1296 notifier,
1297 &props[i]);
1298 else
1299 ret = v4l2_fwnode_reference_parse(dev, notifier,
1300 props[i].name);
1301 if (ret && ret != -ENOENT) {
1302 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1303 props[i].name, ret);
1304 return ret;
1305 }
1306 }
1307
1308 return 0;
1309}
1310
1311int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
1312{
1313 struct v4l2_async_notifier *notifier;
1314 int ret;
1315
1316 if (WARN_ON(!sd->dev))
1317 return -ENODEV;
1318
1319 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1320 if (!notifier)
1321 return -ENOMEM;
1322
1323 v4l2_async_notifier_init(notifier);
1324
1325 ret = v4l2_async_notifier_parse_fwnode_sensor(sd->dev, notifier);
1326 if (ret < 0)
1327 goto out_cleanup;
1328
1329 ret = v4l2_async_subdev_notifier_register(sd, notifier);
1330 if (ret < 0)
1331 goto out_cleanup;
1332
1333 ret = v4l2_async_register_subdev(sd);
1334 if (ret < 0)
1335 goto out_unregister;
1336
1337 sd->subdev_notifier = notifier;
1338
1339 return 0;
1340
1341out_unregister:
1342 v4l2_async_notifier_unregister(notifier);
1343
1344out_cleanup:
1345 v4l2_async_notifier_cleanup(notifier);
1346 kfree(notifier);
1347
1348 return ret;
1349}
1350EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor);
1351
1352MODULE_LICENSE("GPL");
1353MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1354MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1355MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1356