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