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