]> Git Repo - linux.git/blob - drivers/media/v4l2-core/v4l2-fwnode.c
Merge tag 'gvt-next-2017-12-14' of https://github.com/intel/gvt-linux into drm-intel...
[linux.git] / drivers / media / v4l2-core / v4l2-fwnode.c
1 /*
2  * V4L2 fwnode binding parsing library
3  *
4  * The origins of the V4L2 fwnode library are in V4L2 OF library that
5  * formerly was located in v4l2-of.c.
6  *
7  * Copyright (c) 2016 Intel Corporation.
8  * Author: Sakari Ailus <[email protected]>
9  *
10  * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
11  * Author: Sylwester Nawrocki <[email protected]>
12  *
13  * Copyright (C) 2012 Renesas Electronics Corp.
14  * Author: Guennadi Liakhovetski <[email protected]>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of version 2 of the GNU General Public License as
18  * published by the Free Software Foundation.
19  */
20 #include <linux/acpi.h>
21 #include <linux/kernel.h>
22 #include <linux/mm.h>
23 #include <linux/module.h>
24 #include <linux/of.h>
25 #include <linux/property.h>
26 #include <linux/slab.h>
27 #include <linux/string.h>
28 #include <linux/types.h>
29
30 #include <media/v4l2-async.h>
31 #include <media/v4l2-fwnode.h>
32 #include <media/v4l2-subdev.h>
33
34 enum v4l2_fwnode_bus_type {
35         V4L2_FWNODE_BUS_TYPE_GUESS = 0,
36         V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
37         V4L2_FWNODE_BUS_TYPE_CSI1,
38         V4L2_FWNODE_BUS_TYPE_CCP2,
39         NR_OF_V4L2_FWNODE_BUS_TYPE,
40 };
41
42 static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
43                                                struct v4l2_fwnode_endpoint *vep)
44 {
45         struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
46         bool have_clk_lane = false;
47         unsigned int flags = 0, lanes_used = 0;
48         unsigned int i;
49         u32 v;
50         int rval;
51
52         rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0);
53         if (rval > 0) {
54                 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
55
56                 bus->num_data_lanes =
57                         min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
58
59                 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
60                                                bus->num_data_lanes);
61
62                 for (i = 0; i < bus->num_data_lanes; i++) {
63                         if (lanes_used & BIT(array[i]))
64                                 pr_warn("duplicated lane %u in data-lanes\n",
65                                         array[i]);
66                         lanes_used |= BIT(array[i]);
67
68                         bus->data_lanes[i] = array[i];
69                 }
70
71                 rval = fwnode_property_read_u32_array(fwnode,
72                                                       "lane-polarities", NULL,
73                                                       0);
74                 if (rval > 0) {
75                         if (rval != 1 + bus->num_data_lanes /* clock+data */) {
76                                 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
77                                         1 + bus->num_data_lanes, rval);
78                                 return -EINVAL;
79                         }
80
81                         fwnode_property_read_u32_array(fwnode,
82                                                        "lane-polarities", array,
83                                                        1 + bus->num_data_lanes);
84
85                         for (i = 0; i < 1 + bus->num_data_lanes; i++)
86                                 bus->lane_polarities[i] = array[i];
87                 }
88
89         }
90
91         if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
92                 if (lanes_used & BIT(v))
93                         pr_warn("duplicated lane %u in clock-lanes\n", v);
94                 lanes_used |= BIT(v);
95
96                 bus->clock_lane = v;
97                 have_clk_lane = true;
98         }
99
100         if (fwnode_property_present(fwnode, "clock-noncontinuous"))
101                 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
102         else if (have_clk_lane || bus->num_data_lanes > 0)
103                 flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
104
105         bus->flags = flags;
106         vep->bus_type = V4L2_MBUS_CSI2;
107
108         return 0;
109 }
110
111 static void v4l2_fwnode_endpoint_parse_parallel_bus(
112         struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
113 {
114         struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
115         unsigned int flags = 0;
116         u32 v;
117
118         if (!fwnode_property_read_u32(fwnode, "hsync-active", &v))
119                 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
120                         V4L2_MBUS_HSYNC_ACTIVE_LOW;
121
122         if (!fwnode_property_read_u32(fwnode, "vsync-active", &v))
123                 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
124                         V4L2_MBUS_VSYNC_ACTIVE_LOW;
125
126         if (!fwnode_property_read_u32(fwnode, "field-even-active", &v))
127                 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
128                         V4L2_MBUS_FIELD_EVEN_LOW;
129         if (flags)
130                 vep->bus_type = V4L2_MBUS_PARALLEL;
131         else
132                 vep->bus_type = V4L2_MBUS_BT656;
133
134         if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v))
135                 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
136                         V4L2_MBUS_PCLK_SAMPLE_FALLING;
137
138         if (!fwnode_property_read_u32(fwnode, "data-active", &v))
139                 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
140                         V4L2_MBUS_DATA_ACTIVE_LOW;
141
142         if (fwnode_property_present(fwnode, "slave-mode"))
143                 flags |= V4L2_MBUS_SLAVE;
144         else
145                 flags |= V4L2_MBUS_MASTER;
146
147         if (!fwnode_property_read_u32(fwnode, "bus-width", &v))
148                 bus->bus_width = v;
149
150         if (!fwnode_property_read_u32(fwnode, "data-shift", &v))
151                 bus->data_shift = v;
152
153         if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v))
154                 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
155                         V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
156
157         bus->flags = flags;
158
159 }
160
161 static void
162 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
163                                     struct v4l2_fwnode_endpoint *vep,
164                                     u32 bus_type)
165 {
166         struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
167         u32 v;
168
169         if (!fwnode_property_read_u32(fwnode, "clock-inv", &v))
170                 bus->clock_inv = v;
171
172         if (!fwnode_property_read_u32(fwnode, "strobe", &v))
173                 bus->strobe = v;
174
175         if (!fwnode_property_read_u32(fwnode, "data-lanes", &v))
176                 bus->data_lane = v;
177
178         if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v))
179                 bus->clock_lane = v;
180
181         if (bus_type == V4L2_FWNODE_BUS_TYPE_CCP2)
182                 vep->bus_type = V4L2_MBUS_CCP2;
183         else
184                 vep->bus_type = V4L2_MBUS_CSI1;
185 }
186
187 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
188                                struct v4l2_fwnode_endpoint *vep)
189 {
190         u32 bus_type = 0;
191         int rval;
192
193         fwnode_graph_parse_endpoint(fwnode, &vep->base);
194
195         /* Zero fields from bus_type to until the end */
196         memset(&vep->bus_type, 0, sizeof(*vep) -
197                offsetof(typeof(*vep), bus_type));
198
199         fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
200
201         switch (bus_type) {
202         case V4L2_FWNODE_BUS_TYPE_GUESS:
203                 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep);
204                 if (rval)
205                         return rval;
206                 /*
207                  * Parse the parallel video bus properties only if none
208                  * of the MIPI CSI-2 specific properties were found.
209                  */
210                 if (vep->bus.mipi_csi2.flags == 0)
211                         v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep);
212
213                 return 0;
214         case V4L2_FWNODE_BUS_TYPE_CCP2:
215         case V4L2_FWNODE_BUS_TYPE_CSI1:
216                 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, bus_type);
217
218                 return 0;
219         default:
220                 pr_warn("unsupported bus type %u\n", bus_type);
221                 return -EINVAL;
222         }
223 }
224 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
225
226 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
227 {
228         if (IS_ERR_OR_NULL(vep))
229                 return;
230
231         kfree(vep->link_frequencies);
232         kfree(vep);
233 }
234 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
235
236 struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
237         struct fwnode_handle *fwnode)
238 {
239         struct v4l2_fwnode_endpoint *vep;
240         int rval;
241
242         vep = kzalloc(sizeof(*vep), GFP_KERNEL);
243         if (!vep)
244                 return ERR_PTR(-ENOMEM);
245
246         rval = v4l2_fwnode_endpoint_parse(fwnode, vep);
247         if (rval < 0)
248                 goto out_err;
249
250         rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
251                                               NULL, 0);
252         if (rval > 0) {
253                 vep->link_frequencies =
254                         kmalloc_array(rval, sizeof(*vep->link_frequencies),
255                                       GFP_KERNEL);
256                 if (!vep->link_frequencies) {
257                         rval = -ENOMEM;
258                         goto out_err;
259                 }
260
261                 vep->nr_of_link_frequencies = rval;
262
263                 rval = fwnode_property_read_u64_array(
264                         fwnode, "link-frequencies", vep->link_frequencies,
265                         vep->nr_of_link_frequencies);
266                 if (rval < 0)
267                         goto out_err;
268         }
269
270         return vep;
271
272 out_err:
273         v4l2_fwnode_endpoint_free(vep);
274         return ERR_PTR(rval);
275 }
276 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
277
278 int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
279                            struct v4l2_fwnode_link *link)
280 {
281         const char *port_prop = is_of_node(__fwnode) ? "reg" : "port";
282         struct fwnode_handle *fwnode;
283
284         memset(link, 0, sizeof(*link));
285
286         fwnode = fwnode_get_parent(__fwnode);
287         fwnode_property_read_u32(fwnode, port_prop, &link->local_port);
288         fwnode = fwnode_get_next_parent(fwnode);
289         if (is_of_node(fwnode) &&
290             of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
291                 fwnode = fwnode_get_next_parent(fwnode);
292         link->local_node = fwnode;
293
294         fwnode = fwnode_graph_get_remote_endpoint(__fwnode);
295         if (!fwnode) {
296                 fwnode_handle_put(fwnode);
297                 return -ENOLINK;
298         }
299
300         fwnode = fwnode_get_parent(fwnode);
301         fwnode_property_read_u32(fwnode, port_prop, &link->remote_port);
302         fwnode = fwnode_get_next_parent(fwnode);
303         if (is_of_node(fwnode) &&
304             of_node_cmp(to_of_node(fwnode)->name, "ports") == 0)
305                 fwnode = fwnode_get_next_parent(fwnode);
306         link->remote_node = fwnode;
307
308         return 0;
309 }
310 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
311
312 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
313 {
314         fwnode_handle_put(link->local_node);
315         fwnode_handle_put(link->remote_node);
316 }
317 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
318
319 static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
320                                        unsigned int max_subdevs)
321 {
322         struct v4l2_async_subdev **subdevs;
323
324         if (max_subdevs <= notifier->max_subdevs)
325                 return 0;
326
327         subdevs = kvmalloc_array(
328                 max_subdevs, sizeof(*notifier->subdevs),
329                 GFP_KERNEL | __GFP_ZERO);
330         if (!subdevs)
331                 return -ENOMEM;
332
333         if (notifier->subdevs) {
334                 memcpy(subdevs, notifier->subdevs,
335                        sizeof(*subdevs) * notifier->num_subdevs);
336
337                 kvfree(notifier->subdevs);
338         }
339
340         notifier->subdevs = subdevs;
341         notifier->max_subdevs = max_subdevs;
342
343         return 0;
344 }
345
346 static int v4l2_async_notifier_fwnode_parse_endpoint(
347         struct device *dev, struct v4l2_async_notifier *notifier,
348         struct fwnode_handle *endpoint, unsigned int asd_struct_size,
349         int (*parse_endpoint)(struct device *dev,
350                             struct v4l2_fwnode_endpoint *vep,
351                             struct v4l2_async_subdev *asd))
352 {
353         struct v4l2_async_subdev *asd;
354         struct v4l2_fwnode_endpoint *vep;
355         int ret = 0;
356
357         asd = kzalloc(asd_struct_size, GFP_KERNEL);
358         if (!asd)
359                 return -ENOMEM;
360
361         asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
362         asd->match.fwnode.fwnode =
363                 fwnode_graph_get_remote_port_parent(endpoint);
364         if (!asd->match.fwnode.fwnode) {
365                 dev_warn(dev, "bad remote port parent\n");
366                 ret = -EINVAL;
367                 goto out_err;
368         }
369
370         vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
371         if (IS_ERR(vep)) {
372                 ret = PTR_ERR(vep);
373                 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
374                          ret);
375                 goto out_err;
376         }
377
378         ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
379         if (ret == -ENOTCONN)
380                 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
381                         vep->base.id);
382         else if (ret < 0)
383                 dev_warn(dev,
384                          "driver could not parse port@%u/endpoint@%u (%d)\n",
385                          vep->base.port, vep->base.id, ret);
386         v4l2_fwnode_endpoint_free(vep);
387         if (ret < 0)
388                 goto out_err;
389
390         notifier->subdevs[notifier->num_subdevs] = asd;
391         notifier->num_subdevs++;
392
393         return 0;
394
395 out_err:
396         fwnode_handle_put(asd->match.fwnode.fwnode);
397         kfree(asd);
398
399         return ret == -ENOTCONN ? 0 : ret;
400 }
401
402 static int __v4l2_async_notifier_parse_fwnode_endpoints(
403         struct device *dev, struct v4l2_async_notifier *notifier,
404         size_t asd_struct_size, unsigned int port, bool has_port,
405         int (*parse_endpoint)(struct device *dev,
406                             struct v4l2_fwnode_endpoint *vep,
407                             struct v4l2_async_subdev *asd))
408 {
409         struct fwnode_handle *fwnode;
410         unsigned int max_subdevs = notifier->max_subdevs;
411         int ret;
412
413         if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
414                 return -EINVAL;
415
416         for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
417                                      dev_fwnode(dev), fwnode)); ) {
418                 struct fwnode_handle *dev_fwnode;
419                 bool is_available;
420
421                 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
422                 is_available = fwnode_device_is_available(dev_fwnode);
423                 fwnode_handle_put(dev_fwnode);
424                 if (!is_available)
425                         continue;
426
427                 if (has_port) {
428                         struct fwnode_endpoint ep;
429
430                         ret = fwnode_graph_parse_endpoint(fwnode, &ep);
431                         if (ret) {
432                                 fwnode_handle_put(fwnode);
433                                 return ret;
434                         }
435
436                         if (ep.port != port)
437                                 continue;
438                 }
439                 max_subdevs++;
440         }
441
442         /* No subdevs to add? Return here. */
443         if (max_subdevs == notifier->max_subdevs)
444                 return 0;
445
446         ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
447         if (ret)
448                 return ret;
449
450         for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
451                                      dev_fwnode(dev), fwnode)); ) {
452                 struct fwnode_handle *dev_fwnode;
453                 bool is_available;
454
455                 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
456                 is_available = fwnode_device_is_available(dev_fwnode);
457                 fwnode_handle_put(dev_fwnode);
458                 if (!is_available)
459                         continue;
460
461                 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
462                         ret = -EINVAL;
463                         break;
464                 }
465
466                 if (has_port) {
467                         struct fwnode_endpoint ep;
468
469                         ret = fwnode_graph_parse_endpoint(fwnode, &ep);
470                         if (ret)
471                                 break;
472
473                         if (ep.port != port)
474                                 continue;
475                 }
476
477                 ret = v4l2_async_notifier_fwnode_parse_endpoint(
478                         dev, notifier, fwnode, asd_struct_size, parse_endpoint);
479                 if (ret < 0)
480                         break;
481         }
482
483         fwnode_handle_put(fwnode);
484
485         return ret;
486 }
487
488 int v4l2_async_notifier_parse_fwnode_endpoints(
489         struct device *dev, struct v4l2_async_notifier *notifier,
490         size_t asd_struct_size,
491         int (*parse_endpoint)(struct device *dev,
492                             struct v4l2_fwnode_endpoint *vep,
493                             struct v4l2_async_subdev *asd))
494 {
495         return __v4l2_async_notifier_parse_fwnode_endpoints(
496                 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
497 }
498 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
499
500 int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
501         struct device *dev, struct v4l2_async_notifier *notifier,
502         size_t asd_struct_size, unsigned int port,
503         int (*parse_endpoint)(struct device *dev,
504                             struct v4l2_fwnode_endpoint *vep,
505                             struct v4l2_async_subdev *asd))
506 {
507         return __v4l2_async_notifier_parse_fwnode_endpoints(
508                 dev, notifier, asd_struct_size, port, true, parse_endpoint);
509 }
510 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
511
512 /*
513  * v4l2_fwnode_reference_parse - parse references for async sub-devices
514  * @dev: the device node the properties of which are parsed for references
515  * @notifier: the async notifier where the async subdevs will be added
516  * @prop: the name of the property
517  *
518  * Return: 0 on success
519  *         -ENOENT if no entries were found
520  *         -ENOMEM if memory allocation failed
521  *         -EINVAL if property parsing failed
522  */
523 static int v4l2_fwnode_reference_parse(
524         struct device *dev, struct v4l2_async_notifier *notifier,
525         const char *prop)
526 {
527         struct fwnode_reference_args args;
528         unsigned int index;
529         int ret;
530
531         for (index = 0;
532              !(ret = fwnode_property_get_reference_args(
533                        dev_fwnode(dev), prop, NULL, 0, index, &args));
534              index++)
535                 fwnode_handle_put(args.fwnode);
536
537         if (!index)
538                 return -ENOENT;
539
540         /*
541          * Note that right now both -ENODATA and -ENOENT may signal
542          * out-of-bounds access. Return the error in cases other than that.
543          */
544         if (ret != -ENOENT && ret != -ENODATA)
545                 return ret;
546
547         ret = v4l2_async_notifier_realloc(notifier,
548                                           notifier->num_subdevs + index);
549         if (ret)
550                 return ret;
551
552         for (index = 0; !fwnode_property_get_reference_args(
553                      dev_fwnode(dev), prop, NULL, 0, index, &args);
554              index++) {
555                 struct v4l2_async_subdev *asd;
556
557                 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
558                         ret = -EINVAL;
559                         goto error;
560                 }
561
562                 asd = kzalloc(sizeof(*asd), GFP_KERNEL);
563                 if (!asd) {
564                         ret = -ENOMEM;
565                         goto error;
566                 }
567
568                 notifier->subdevs[notifier->num_subdevs] = asd;
569                 asd->match.fwnode.fwnode = args.fwnode;
570                 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
571                 notifier->num_subdevs++;
572         }
573
574         return 0;
575
576 error:
577         fwnode_handle_put(args.fwnode);
578         return ret;
579 }
580
581 /*
582  * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
583  *                                      arguments
584  * @fwnode: fwnode to read @prop from
585  * @notifier: notifier for @dev
586  * @prop: the name of the property
587  * @index: the index of the reference to get
588  * @props: the array of integer property names
589  * @nprops: the number of integer property names in @nprops
590  *
591  * First find an fwnode referred to by the reference at @index in @prop.
592  *
593  * Then under that fwnode, @nprops times, for each property in @props,
594  * iteratively follow child nodes starting from fwnode such that they have the
595  * property in @props array at the index of the child node distance from the
596  * root node and the value of that property matching with the integer argument
597  * of the reference, at the same index.
598  *
599  * The child fwnode reched at the end of the iteration is then returned to the
600  * caller.
601  *
602  * The core reason for this is that you cannot refer to just any node in ACPI.
603  * So to refer to an endpoint (easy in DT) you need to refer to a device, then
604  * provide a list of (property name, property value) tuples where each tuple
605  * uniquely identifies a child node. The first tuple identifies a child directly
606  * underneath the device fwnode, the next tuple identifies a child node
607  * underneath the fwnode identified by the previous tuple, etc. until you
608  * reached the fwnode you need.
609  *
610  * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
611  *
612  *      Scope (\_SB.PCI0.I2C2)
613  *      {
614  *              Device (CAM0)
615  *              {
616  *                      Name (_DSD, Package () {
617  *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
618  *                              Package () {
619  *                                      Package () {
620  *                                              "compatible",
621  *                                              Package () { "nokia,smia" }
622  *                                      },
623  *                              },
624  *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
625  *                              Package () {
626  *                                      Package () { "port0", "PRT0" },
627  *                              }
628  *                      })
629  *                      Name (PRT0, Package() {
630  *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
631  *                              Package () {
632  *                                      Package () { "port", 0 },
633  *                              },
634  *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
635  *                              Package () {
636  *                                      Package () { "endpoint0", "EP00" },
637  *                              }
638  *                      })
639  *                      Name (EP00, Package() {
640  *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
641  *                              Package () {
642  *                                      Package () { "endpoint", 0 },
643  *                                      Package () {
644  *                                              "remote-endpoint",
645  *                                              Package() {
646  *                                                      \_SB.PCI0.ISP, 4, 0
647  *                                              }
648  *                                      },
649  *                              }
650  *                      })
651  *              }
652  *      }
653  *
654  *      Scope (\_SB.PCI0)
655  *      {
656  *              Device (ISP)
657  *              {
658  *                      Name (_DSD, Package () {
659  *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
660  *                              Package () {
661  *                                      Package () { "port4", "PRT4" },
662  *                              }
663  *                      })
664  *
665  *                      Name (PRT4, Package() {
666  *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
667  *                              Package () {
668  *                                      Package () { "port", 4 },
669  *                              },
670  *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
671  *                              Package () {
672  *                                      Package () { "endpoint0", "EP40" },
673  *                              }
674  *                      })
675  *
676  *                      Name (EP40, Package() {
677  *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
678  *                              Package () {
679  *                                      Package () { "endpoint", 0 },
680  *                                      Package () {
681  *                                              "remote-endpoint",
682  *                                              Package () {
683  *                                                      \_SB.PCI0.I2C2.CAM0,
684  *                                                      0, 0
685  *                                              }
686  *                                      },
687  *                              }
688  *                      })
689  *              }
690  *      }
691  *
692  * From the EP40 node under ISP device, you could parse the graph remote
693  * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
694  *
695  *  @fwnode: fwnode referring to EP40 under ISP.
696  *  @prop: "remote-endpoint"
697  *  @index: 0
698  *  @props: "port", "endpoint"
699  *  @nprops: 2
700  *
701  * And you'd get back fwnode referring to EP00 under CAM0.
702  *
703  * The same works the other way around: if you use EP00 under CAM0 as the
704  * fwnode, you'll get fwnode referring to EP40 under ISP.
705  *
706  * The same example in DT syntax would look like this:
707  *
708  * cam: cam0 {
709  *      compatible = "nokia,smia";
710  *
711  *      port {
712  *              port = <0>;
713  *              endpoint {
714  *                      endpoint = <0>;
715  *                      remote-endpoint = <&isp 4 0>;
716  *              };
717  *      };
718  * };
719  *
720  * isp: isp {
721  *      ports {
722  *              port@4 {
723  *                      port = <4>;
724  *                      endpoint {
725  *                              endpoint = <0>;
726  *                              remote-endpoint = <&cam 0 0>;
727  *                      };
728  *              };
729  *      };
730  * };
731  *
732  * Return: 0 on success
733  *         -ENOENT if no entries (or the property itself) were found
734  *         -EINVAL if property parsing otherwise failed
735  *         -ENOMEM if memory allocation failed
736  */
737 static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
738         struct fwnode_handle *fwnode, const char *prop, unsigned int index,
739         const char * const *props, unsigned int nprops)
740 {
741         struct fwnode_reference_args fwnode_args;
742         unsigned int *args = fwnode_args.args;
743         struct fwnode_handle *child;
744         int ret;
745
746         /*
747          * Obtain remote fwnode as well as the integer arguments.
748          *
749          * Note that right now both -ENODATA and -ENOENT may signal
750          * out-of-bounds access. Return -ENOENT in that case.
751          */
752         ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
753                                                  index, &fwnode_args);
754         if (ret)
755                 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
756
757         /*
758          * Find a node in the tree under the referred fwnode corresponding to
759          * the integer arguments.
760          */
761         fwnode = fwnode_args.fwnode;
762         while (nprops--) {
763                 u32 val;
764
765                 /* Loop over all child nodes under fwnode. */
766                 fwnode_for_each_child_node(fwnode, child) {
767                         if (fwnode_property_read_u32(child, *props, &val))
768                                 continue;
769
770                         /* Found property, see if its value matches. */
771                         if (val == *args)
772                                 break;
773                 }
774
775                 fwnode_handle_put(fwnode);
776
777                 /* No property found; return an error here. */
778                 if (!child) {
779                         fwnode = ERR_PTR(-ENOENT);
780                         break;
781                 }
782
783                 props++;
784                 args++;
785                 fwnode = child;
786         }
787
788         return fwnode;
789 }
790
791 /*
792  * v4l2_fwnode_reference_parse_int_props - parse references for async
793  *                                         sub-devices
794  * @dev: struct device pointer
795  * @notifier: notifier for @dev
796  * @prop: the name of the property
797  * @props: the array of integer property names
798  * @nprops: the number of integer properties
799  *
800  * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
801  * property @prop with integer arguments with child nodes matching in properties
802  * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
803  * accordingly.
804  *
805  * While it is technically possible to use this function on DT, it is only
806  * meaningful on ACPI. On Device tree you can refer to any node in the tree but
807  * on ACPI the references are limited to devices.
808  *
809  * Return: 0 on success
810  *         -ENOENT if no entries (or the property itself) were found
811  *         -EINVAL if property parsing otherwisefailed
812  *         -ENOMEM if memory allocation failed
813  */
814 static int v4l2_fwnode_reference_parse_int_props(
815         struct device *dev, struct v4l2_async_notifier *notifier,
816         const char *prop, const char * const *props, unsigned int nprops)
817 {
818         struct fwnode_handle *fwnode;
819         unsigned int index;
820         int ret;
821
822         for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
823                                          dev_fwnode(dev), prop, index, props,
824                                          nprops))); index++)
825                 fwnode_handle_put(fwnode);
826
827         /*
828          * Note that right now both -ENODATA and -ENOENT may signal
829          * out-of-bounds access. Return the error in cases other than that.
830          */
831         if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA)
832                 return PTR_ERR(fwnode);
833
834         ret = v4l2_async_notifier_realloc(notifier,
835                                           notifier->num_subdevs + index);
836         if (ret)
837                 return -ENOMEM;
838
839         for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
840                                          dev_fwnode(dev), prop, index, props,
841                                          nprops))); index++) {
842                 struct v4l2_async_subdev *asd;
843
844                 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
845                         ret = -EINVAL;
846                         goto error;
847                 }
848
849                 asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
850                 if (!asd) {
851                         ret = -ENOMEM;
852                         goto error;
853                 }
854
855                 notifier->subdevs[notifier->num_subdevs] = asd;
856                 asd->match.fwnode.fwnode = fwnode;
857                 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
858                 notifier->num_subdevs++;
859         }
860
861         return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
862
863 error:
864         fwnode_handle_put(fwnode);
865         return ret;
866 }
867
868 int v4l2_async_notifier_parse_fwnode_sensor_common(
869         struct device *dev, struct v4l2_async_notifier *notifier)
870 {
871         static const char * const led_props[] = { "led" };
872         static const struct {
873                 const char *name;
874                 const char * const *props;
875                 unsigned int nprops;
876         } props[] = {
877                 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
878                 { "lens-focus", NULL, 0 },
879         };
880         unsigned int i;
881
882         for (i = 0; i < ARRAY_SIZE(props); i++) {
883                 int ret;
884
885                 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
886                         ret = v4l2_fwnode_reference_parse_int_props(
887                                 dev, notifier, props[i].name,
888                                 props[i].props, props[i].nprops);
889                 else
890                         ret = v4l2_fwnode_reference_parse(
891                                 dev, notifier, props[i].name);
892                 if (ret && ret != -ENOENT) {
893                         dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
894                                  props[i].name, ret);
895                         return ret;
896                 }
897         }
898
899         return 0;
900 }
901 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
902
903 int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
904 {
905         struct v4l2_async_notifier *notifier;
906         int ret;
907
908         if (WARN_ON(!sd->dev))
909                 return -ENODEV;
910
911         notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
912         if (!notifier)
913                 return -ENOMEM;
914
915         ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
916                                                              notifier);
917         if (ret < 0)
918                 goto out_cleanup;
919
920         ret = v4l2_async_subdev_notifier_register(sd, notifier);
921         if (ret < 0)
922                 goto out_cleanup;
923
924         ret = v4l2_async_register_subdev(sd);
925         if (ret < 0)
926                 goto out_unregister;
927
928         sd->subdev_notifier = notifier;
929
930         return 0;
931
932 out_unregister:
933         v4l2_async_notifier_unregister(notifier);
934
935 out_cleanup:
936         v4l2_async_notifier_cleanup(notifier);
937         kfree(notifier);
938
939         return ret;
940 }
941 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
942
943 MODULE_LICENSE("GPL");
944 MODULE_AUTHOR("Sakari Ailus <[email protected]>");
945 MODULE_AUTHOR("Sylwester Nawrocki <[email protected]>");
946 MODULE_AUTHOR("Guennadi Liakhovetski <[email protected]>");
This page took 0.090649 seconds and 4 git commands to generate.