blob: 3b9c6afb49a3478a5cf6525d5efb9b38863c5839 [file] [log] [blame]
Sakari Ailusca50c192016-08-12 08:05:51 -03001/*
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 <sakari.ailus@linux.intel.com>
9 *
10 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
11 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
12 *
13 * Copyright (C) 2012 Renesas Electronics Corp.
14 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
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>
Sakari Ailus9ca46532017-08-17 11:28:21 -040022#include <linux/mm.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030023#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
Sakari Ailus9ca46532017-08-17 11:28:21 -040030#include <media/v4l2-async.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030031#include <media/v4l2-fwnode.h>
Sakari Ailusaef69d52017-09-24 18:47:44 -040032#include <media/v4l2-subdev.h>
Sakari Ailusca50c192016-08-12 08:05:51 -030033
Sakari Ailuse07a41f2015-02-25 14:51:01 -050034enum 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
Sakari Ailusf3112732017-02-20 05:42:09 -050042static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
43 struct v4l2_fwnode_endpoint *vep)
Sakari Ailusca50c192016-08-12 08:05:51 -030044{
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) {
Sakari Ailusad3cdf32017-08-14 06:43:07 -040054 u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
Sakari Ailusca50c192016-08-12 08:05:51 -030055
Sakari Ailusad3cdf32017-08-14 06:43:07 -040056 bus->num_data_lanes =
57 min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
Sakari Ailusca50c192016-08-12 08:05:51 -030058
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 }
Sakari Ailusca50c192016-08-12 08:05:51 -030070
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040071 rval = fwnode_property_read_u32_array(fwnode,
Sakari Ailusb24f0212017-08-14 06:15:21 -040072 "lane-polarities", NULL,
73 0);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040074 if (rval > 0) {
Sakari Ailusb24f0212017-08-14 06:15:21 -040075 if (rval != 1 + bus->num_data_lanes /* clock+data */) {
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040076 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
77 1 + bus->num_data_lanes, rval);
78 return -EINVAL;
79 }
Sakari Ailusca50c192016-08-12 08:05:51 -030080
Sakari Ailusb24f0212017-08-14 06:15:21 -040081 fwnode_property_read_u32_array(fwnode,
82 "lane-polarities", array,
83 1 + bus->num_data_lanes);
Mauro Carvalho Chehab4ee23622017-06-26 14:07:54 -040084
85 for (i = 0; i < 1 + bus->num_data_lanes; i++)
86 bus->lane_polarities[i] = array[i];
Sakari Ailusca50c192016-08-12 08:05:51 -030087 }
Sakari Ailusb24f0212017-08-14 06:15:21 -040088
Sakari Ailusca50c192016-08-12 08:05:51 -030089 }
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
111static 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
Mauro Carvalho Chehababc5b2c2017-07-20 16:27:27 -0400161static void
162v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
163 struct v4l2_fwnode_endpoint *vep,
164 u32 bus_type)
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500165{
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
Sakari Ailusca50c192016-08-12 08:05:51 -0300187int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
188 struct v4l2_fwnode_endpoint *vep)
189{
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500190 u32 bus_type = 0;
Sakari Ailusca50c192016-08-12 08:05:51 -0300191 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
Sakari Ailuse07a41f2015-02-25 14:51:01 -0500199 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
200
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500201 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);
Sakari Ailusca50c192016-08-12 08:05:51 -0300212
Sakari Ailus97bbdf02015-02-25 14:39:11 -0500213 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 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300223}
224EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
225
Sakari Ailusca50c192016-08-12 08:05:51 -0300226void 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}
234EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
235
Sakari Ailusca50c192016-08-12 08:05:51 -0300236struct 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);
Sakari Ailus06f81522017-06-20 09:14:43 -0400252 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 }
Sakari Ailusca50c192016-08-12 08:05:51 -0300260
Sakari Ailus06f81522017-06-20 09:14:43 -0400261 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;
Sakari Ailusca50c192016-08-12 08:05:51 -0300268 }
269
Sakari Ailusca50c192016-08-12 08:05:51 -0300270 return vep;
271
272out_err:
273 v4l2_fwnode_endpoint_free(vep);
274 return ERR_PTR(rval);
275}
276EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
277
Sakari Ailusca50c192016-08-12 08:05:51 -0300278int 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}
310EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
311
Sakari Ailusca50c192016-08-12 08:05:51 -0300312void 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}
317EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
318
Sakari Ailus9ca46532017-08-17 11:28:21 -0400319static 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
346static 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
395out_err:
396 fwnode_handle_put(asd->match.fwnode.fwnode);
397 kfree(asd);
398
399 return ret == -ENOTCONN ? 0 : ret;
400}
401
402static 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
459 if (!fwnode_device_is_available(dev_fwnode))
460 continue;
461
462 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
463 ret = -EINVAL;
464 break;
465 }
466
467 if (has_port) {
468 struct fwnode_endpoint ep;
469
470 ret = fwnode_graph_parse_endpoint(fwnode, &ep);
471 if (ret)
472 break;
473
474 if (ep.port != port)
475 continue;
476 }
477
478 ret = v4l2_async_notifier_fwnode_parse_endpoint(
479 dev, notifier, fwnode, asd_struct_size, parse_endpoint);
480 if (ret < 0)
481 break;
482 }
483
484 fwnode_handle_put(fwnode);
485
486 return ret;
487}
488
489int v4l2_async_notifier_parse_fwnode_endpoints(
490 struct device *dev, struct v4l2_async_notifier *notifier,
491 size_t asd_struct_size,
492 int (*parse_endpoint)(struct device *dev,
493 struct v4l2_fwnode_endpoint *vep,
494 struct v4l2_async_subdev *asd))
495{
496 return __v4l2_async_notifier_parse_fwnode_endpoints(
497 dev, notifier, asd_struct_size, 0, false, parse_endpoint);
498}
499EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
500
501int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
502 struct device *dev, struct v4l2_async_notifier *notifier,
503 size_t asd_struct_size, unsigned int port,
504 int (*parse_endpoint)(struct device *dev,
505 struct v4l2_fwnode_endpoint *vep,
506 struct v4l2_async_subdev *asd))
507{
508 return __v4l2_async_notifier_parse_fwnode_endpoints(
509 dev, notifier, asd_struct_size, port, true, parse_endpoint);
510}
511EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
512
Sakari Ailusd8428532017-06-20 07:47:24 -0400513/*
514 * v4l2_fwnode_reference_parse - parse references for async sub-devices
515 * @dev: the device node the properties of which are parsed for references
516 * @notifier: the async notifier where the async subdevs will be added
517 * @prop: the name of the property
518 *
519 * Return: 0 on success
520 * -ENOENT if no entries were found
521 * -ENOMEM if memory allocation failed
522 * -EINVAL if property parsing failed
523 */
524static int v4l2_fwnode_reference_parse(
525 struct device *dev, struct v4l2_async_notifier *notifier,
526 const char *prop)
527{
528 struct fwnode_reference_args args;
529 unsigned int index;
530 int ret;
531
532 for (index = 0;
533 !(ret = fwnode_property_get_reference_args(
534 dev_fwnode(dev), prop, NULL, 0, index, &args));
535 index++)
536 fwnode_handle_put(args.fwnode);
537
538 if (!index)
539 return -ENOENT;
540
541 /*
542 * Note that right now both -ENODATA and -ENOENT may signal
543 * out-of-bounds access. Return the error in cases other than that.
544 */
545 if (ret != -ENOENT && ret != -ENODATA)
546 return ret;
547
548 ret = v4l2_async_notifier_realloc(notifier,
549 notifier->num_subdevs + index);
550 if (ret)
551 return ret;
552
553 for (index = 0; !fwnode_property_get_reference_args(
554 dev_fwnode(dev), prop, NULL, 0, index, &args);
555 index++) {
556 struct v4l2_async_subdev *asd;
557
558 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
559 ret = -EINVAL;
560 goto error;
561 }
562
563 asd = kzalloc(sizeof(*asd), GFP_KERNEL);
564 if (!asd) {
565 ret = -ENOMEM;
566 goto error;
567 }
568
569 notifier->subdevs[notifier->num_subdevs] = asd;
570 asd->match.fwnode.fwnode = args.fwnode;
571 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
572 notifier->num_subdevs++;
573 }
574
575 return 0;
576
577error:
578 fwnode_handle_put(args.fwnode);
579 return ret;
580}
581
Sakari Ailusa1699a42017-06-22 08:03:28 -0400582/*
583 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
584 * arguments
585 * @fwnode: fwnode to read @prop from
586 * @notifier: notifier for @dev
587 * @prop: the name of the property
588 * @index: the index of the reference to get
589 * @props: the array of integer property names
590 * @nprops: the number of integer property names in @nprops
591 *
592 * First find an fwnode referred to by the reference at @index in @prop.
593 *
594 * Then under that fwnode, @nprops times, for each property in @props,
595 * iteratively follow child nodes starting from fwnode such that they have the
596 * property in @props array at the index of the child node distance from the
597 * root node and the value of that property matching with the integer argument
598 * of the reference, at the same index.
599 *
600 * The child fwnode reched at the end of the iteration is then returned to the
601 * caller.
602 *
603 * The core reason for this is that you cannot refer to just any node in ACPI.
604 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
605 * provide a list of (property name, property value) tuples where each tuple
606 * uniquely identifies a child node. The first tuple identifies a child directly
607 * underneath the device fwnode, the next tuple identifies a child node
608 * underneath the fwnode identified by the previous tuple, etc. until you
609 * reached the fwnode you need.
610 *
611 * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
612 *
613 * Scope (\_SB.PCI0.I2C2)
614 * {
615 * Device (CAM0)
616 * {
617 * Name (_DSD, Package () {
618 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
619 * Package () {
620 * Package () {
621 * "compatible",
622 * Package () { "nokia,smia" }
623 * },
624 * },
625 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
626 * Package () {
627 * Package () { "port0", "PRT0" },
628 * }
629 * })
630 * Name (PRT0, Package() {
631 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
632 * Package () {
633 * Package () { "port", 0 },
634 * },
635 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
636 * Package () {
637 * Package () { "endpoint0", "EP00" },
638 * }
639 * })
640 * Name (EP00, Package() {
641 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
642 * Package () {
643 * Package () { "endpoint", 0 },
644 * Package () {
645 * "remote-endpoint",
646 * Package() {
647 * \_SB.PCI0.ISP, 4, 0
648 * }
649 * },
650 * }
651 * })
652 * }
653 * }
654 *
655 * Scope (\_SB.PCI0)
656 * {
657 * Device (ISP)
658 * {
659 * Name (_DSD, Package () {
660 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
661 * Package () {
662 * Package () { "port4", "PRT4" },
663 * }
664 * })
665 *
666 * Name (PRT4, Package() {
667 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
668 * Package () {
669 * Package () { "port", 4 },
670 * },
671 * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
672 * Package () {
673 * Package () { "endpoint0", "EP40" },
674 * }
675 * })
676 *
677 * Name (EP40, Package() {
678 * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
679 * Package () {
680 * Package () { "endpoint", 0 },
681 * Package () {
682 * "remote-endpoint",
683 * Package () {
684 * \_SB.PCI0.I2C2.CAM0,
685 * 0, 0
686 * }
687 * },
688 * }
689 * })
690 * }
691 * }
692 *
693 * From the EP40 node under ISP device, you could parse the graph remote
694 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
695 *
696 * @fwnode: fwnode referring to EP40 under ISP.
697 * @prop: "remote-endpoint"
698 * @index: 0
699 * @props: "port", "endpoint"
700 * @nprops: 2
701 *
702 * And you'd get back fwnode referring to EP00 under CAM0.
703 *
704 * The same works the other way around: if you use EP00 under CAM0 as the
705 * fwnode, you'll get fwnode referring to EP40 under ISP.
706 *
707 * The same example in DT syntax would look like this:
708 *
709 * cam: cam0 {
710 * compatible = "nokia,smia";
711 *
712 * port {
713 * port = <0>;
714 * endpoint {
715 * endpoint = <0>;
716 * remote-endpoint = <&isp 4 0>;
717 * };
718 * };
719 * };
720 *
721 * isp: isp {
722 * ports {
723 * port@4 {
724 * port = <4>;
725 * endpoint {
726 * endpoint = <0>;
727 * remote-endpoint = <&cam 0 0>;
728 * };
729 * };
730 * };
731 * };
732 *
733 * Return: 0 on success
734 * -ENOENT if no entries (or the property itself) were found
735 * -EINVAL if property parsing otherwise failed
736 * -ENOMEM if memory allocation failed
737 */
738static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
739 struct fwnode_handle *fwnode, const char *prop, unsigned int index,
740 const char * const *props, unsigned int nprops)
741{
742 struct fwnode_reference_args fwnode_args;
743 unsigned int *args = fwnode_args.args;
744 struct fwnode_handle *child;
745 int ret;
746
747 /*
748 * Obtain remote fwnode as well as the integer arguments.
749 *
750 * Note that right now both -ENODATA and -ENOENT may signal
751 * out-of-bounds access. Return -ENOENT in that case.
752 */
753 ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
754 index, &fwnode_args);
755 if (ret)
756 return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
757
758 /*
759 * Find a node in the tree under the referred fwnode corresponding to
760 * the integer arguments.
761 */
762 fwnode = fwnode_args.fwnode;
763 while (nprops--) {
764 u32 val;
765
766 /* Loop over all child nodes under fwnode. */
767 fwnode_for_each_child_node(fwnode, child) {
768 if (fwnode_property_read_u32(child, *props, &val))
769 continue;
770
771 /* Found property, see if its value matches. */
772 if (val == *args)
773 break;
774 }
775
776 fwnode_handle_put(fwnode);
777
778 /* No property found; return an error here. */
779 if (!child) {
780 fwnode = ERR_PTR(-ENOENT);
781 break;
782 }
783
784 props++;
785 args++;
786 fwnode = child;
787 }
788
789 return fwnode;
790}
791
792/*
793 * v4l2_fwnode_reference_parse_int_props - parse references for async
794 * sub-devices
795 * @dev: struct device pointer
796 * @notifier: notifier for @dev
797 * @prop: the name of the property
798 * @props: the array of integer property names
799 * @nprops: the number of integer properties
800 *
801 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
802 * property @prop with integer arguments with child nodes matching in properties
803 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
804 * accordingly.
805 *
806 * While it is technically possible to use this function on DT, it is only
807 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
808 * on ACPI the references are limited to devices.
809 *
810 * Return: 0 on success
811 * -ENOENT if no entries (or the property itself) were found
812 * -EINVAL if property parsing otherwisefailed
813 * -ENOMEM if memory allocation failed
814 */
815static int v4l2_fwnode_reference_parse_int_props(
816 struct device *dev, struct v4l2_async_notifier *notifier,
817 const char *prop, const char * const *props, unsigned int nprops)
818{
819 struct fwnode_handle *fwnode;
820 unsigned int index;
821 int ret;
822
823 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
824 dev_fwnode(dev), prop, index, props,
825 nprops))); index++)
826 fwnode_handle_put(fwnode);
827
828 /*
829 * Note that right now both -ENODATA and -ENOENT may signal
830 * out-of-bounds access. Return the error in cases other than that.
831 */
832 if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA)
833 return PTR_ERR(fwnode);
834
835 ret = v4l2_async_notifier_realloc(notifier,
836 notifier->num_subdevs + index);
837 if (ret)
838 return -ENOMEM;
839
840 for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
841 dev_fwnode(dev), prop, index, props,
842 nprops))); index++) {
843 struct v4l2_async_subdev *asd;
844
845 if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
846 ret = -EINVAL;
847 goto error;
848 }
849
850 asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
851 if (!asd) {
852 ret = -ENOMEM;
853 goto error;
854 }
855
856 notifier->subdevs[notifier->num_subdevs] = asd;
857 asd->match.fwnode.fwnode = fwnode;
858 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
859 notifier->num_subdevs++;
860 }
861
862 return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
863
864error:
865 fwnode_handle_put(fwnode);
866 return ret;
867}
868
Sakari Ailus7a9ec802017-09-06 08:35:42 -0400869int v4l2_async_notifier_parse_fwnode_sensor_common(
870 struct device *dev, struct v4l2_async_notifier *notifier)
871{
872 static const char * const led_props[] = { "led" };
873 static const struct {
874 const char *name;
875 const char * const *props;
876 unsigned int nprops;
877 } props[] = {
878 { "flash-leds", led_props, ARRAY_SIZE(led_props) },
879 { "lens-focus", NULL, 0 },
880 };
881 unsigned int i;
882
883 for (i = 0; i < ARRAY_SIZE(props); i++) {
884 int ret;
885
886 if (props[i].props && is_acpi_node(dev_fwnode(dev)))
887 ret = v4l2_fwnode_reference_parse_int_props(
888 dev, notifier, props[i].name,
889 props[i].props, props[i].nprops);
890 else
891 ret = v4l2_fwnode_reference_parse(
892 dev, notifier, props[i].name);
893 if (ret && ret != -ENOENT) {
894 dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
895 props[i].name, ret);
896 return ret;
897 }
898 }
899
900 return 0;
901}
902EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
903
Sakari Ailusaef69d52017-09-24 18:47:44 -0400904int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
905{
906 struct v4l2_async_notifier *notifier;
907 int ret;
908
909 if (WARN_ON(!sd->dev))
910 return -ENODEV;
911
912 notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
913 if (!notifier)
914 return -ENOMEM;
915
916 ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
917 notifier);
918 if (ret < 0)
919 goto out_cleanup;
920
921 ret = v4l2_async_subdev_notifier_register(sd, notifier);
922 if (ret < 0)
923 goto out_cleanup;
924
925 ret = v4l2_async_register_subdev(sd);
926 if (ret < 0)
927 goto out_unregister;
928
929 sd->subdev_notifier = notifier;
930
931 return 0;
932
933out_unregister:
934 v4l2_async_notifier_unregister(notifier);
935
936out_cleanup:
937 v4l2_async_notifier_cleanup(notifier);
938 kfree(notifier);
939
940 return ret;
941}
942EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
943
Sakari Ailusca50c192016-08-12 08:05:51 -0300944MODULE_LICENSE("GPL");
945MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
946MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
947MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");