linux/drivers/media/v4l2-core/v4l2-fwnode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * V4L2 fwnode binding parsing library
   4 *
   5 * The origins of the V4L2 fwnode library are in V4L2 OF library that
   6 * formerly was located in v4l2-of.c.
   7 *
   8 * Copyright (c) 2016 Intel Corporation.
   9 * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
  10 *
  11 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
  12 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
  13 *
  14 * Copyright (C) 2012 Renesas Electronics Corp.
  15 * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  16 */
  17#include <linux/acpi.h>
  18#include <linux/kernel.h>
  19#include <linux/mm.h>
  20#include <linux/module.h>
  21#include <linux/of.h>
  22#include <linux/property.h>
  23#include <linux/slab.h>
  24#include <linux/string.h>
  25#include <linux/types.h>
  26
  27#include <media/v4l2-async.h>
  28#include <media/v4l2-fwnode.h>
  29#include <media/v4l2-subdev.h>
  30
  31static const struct v4l2_fwnode_bus_conv {
  32        enum v4l2_fwnode_bus_type fwnode_bus_type;
  33        enum v4l2_mbus_type mbus_type;
  34        const char *name;
  35} buses[] = {
  36        {
  37                V4L2_FWNODE_BUS_TYPE_GUESS,
  38                V4L2_MBUS_UNKNOWN,
  39                "not specified",
  40        }, {
  41                V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
  42                V4L2_MBUS_CSI2_CPHY,
  43                "MIPI CSI-2 C-PHY",
  44        }, {
  45                V4L2_FWNODE_BUS_TYPE_CSI1,
  46                V4L2_MBUS_CSI1,
  47                "MIPI CSI-1",
  48        }, {
  49                V4L2_FWNODE_BUS_TYPE_CCP2,
  50                V4L2_MBUS_CCP2,
  51                "compact camera port 2",
  52        }, {
  53                V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
  54                V4L2_MBUS_CSI2_DPHY,
  55                "MIPI CSI-2 D-PHY",
  56        }, {
  57                V4L2_FWNODE_BUS_TYPE_PARALLEL,
  58                V4L2_MBUS_PARALLEL,
  59                "parallel",
  60        }, {
  61                V4L2_FWNODE_BUS_TYPE_BT656,
  62                V4L2_MBUS_BT656,
  63                "Bt.656",
  64        }
  65};
  66
  67static const struct v4l2_fwnode_bus_conv *
  68get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
  69{
  70        unsigned int i;
  71
  72        for (i = 0; i < ARRAY_SIZE(buses); i++)
  73                if (buses[i].fwnode_bus_type == type)
  74                        return &buses[i];
  75
  76        return NULL;
  77}
  78
  79static enum v4l2_mbus_type
  80v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
  81{
  82        const struct v4l2_fwnode_bus_conv *conv =
  83                get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
  84
  85        return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
  86}
  87
  88static const char *
  89v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
  90{
  91        const struct v4l2_fwnode_bus_conv *conv =
  92                get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
  93
  94        return conv ? conv->name : "not found";
  95}
  96
  97static const struct v4l2_fwnode_bus_conv *
  98get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
  99{
 100        unsigned int i;
 101
 102        for (i = 0; i < ARRAY_SIZE(buses); i++)
 103                if (buses[i].mbus_type == type)
 104                        return &buses[i];
 105
 106        return NULL;
 107}
 108
 109static const char *
 110v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
 111{
 112        const struct v4l2_fwnode_bus_conv *conv =
 113                get_v4l2_fwnode_bus_conv_by_mbus(type);
 114
 115        return conv ? conv->name : "not found";
 116}
 117
 118static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
 119                                               struct v4l2_fwnode_endpoint *vep,
 120                                               enum v4l2_mbus_type bus_type)
 121{
 122        struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2;
 123        bool have_clk_lane = false, have_data_lanes = false,
 124                have_lane_polarities = false;
 125        unsigned int flags = 0, lanes_used = 0;
 126        u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES];
 127        u32 clock_lane = 0;
 128        unsigned int num_data_lanes = 0;
 129        bool use_default_lane_mapping = false;
 130        unsigned int i;
 131        u32 v;
 132        int rval;
 133
 134        if (bus_type == V4L2_MBUS_CSI2_DPHY ||
 135            bus_type == V4L2_MBUS_CSI2_CPHY) {
 136                use_default_lane_mapping = true;
 137
 138                num_data_lanes = min_t(u32, bus->num_data_lanes,
 139                                       V4L2_FWNODE_CSI2_MAX_DATA_LANES);
 140
 141                clock_lane = bus->clock_lane;
 142                if (clock_lane)
 143                        use_default_lane_mapping = false;
 144
 145                for (i = 0; i < num_data_lanes; i++) {
 146                        array[i] = bus->data_lanes[i];
 147                        if (array[i])
 148                                use_default_lane_mapping = false;
 149                }
 150
 151                if (use_default_lane_mapping)
 152                        pr_debug("no lane mapping given, using defaults\n");
 153        }
 154
 155        rval = fwnode_property_count_u32(fwnode, "data-lanes");
 156        if (rval > 0) {
 157                num_data_lanes =
 158                        min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval);
 159
 160                fwnode_property_read_u32_array(fwnode, "data-lanes", array,
 161                                               num_data_lanes);
 162
 163                have_data_lanes = true;
 164                if (use_default_lane_mapping) {
 165                        pr_debug("data-lanes property exists; disabling default mapping\n");
 166                        use_default_lane_mapping = false;
 167                }
 168        }
 169
 170        for (i = 0; i < num_data_lanes; i++) {
 171                if (lanes_used & BIT(array[i])) {
 172                        if (have_data_lanes || !use_default_lane_mapping)
 173                                pr_warn("duplicated lane %u in data-lanes, using defaults\n",
 174                                        array[i]);
 175                        use_default_lane_mapping = true;
 176                }
 177                lanes_used |= BIT(array[i]);
 178
 179                if (have_data_lanes)
 180                        pr_debug("lane %u position %u\n", i, array[i]);
 181        }
 182
 183        rval = fwnode_property_count_u32(fwnode, "lane-polarities");
 184        if (rval > 0) {
 185                if (rval != 1 + num_data_lanes /* clock+data */) {
 186                        pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
 187                                1 + num_data_lanes, rval);
 188                        return -EINVAL;
 189                }
 190
 191                have_lane_polarities = true;
 192        }
 193
 194        if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
 195                clock_lane = v;
 196                pr_debug("clock lane position %u\n", v);
 197                have_clk_lane = true;
 198        }
 199
 200        if (have_clk_lane && lanes_used & BIT(clock_lane) &&
 201            !use_default_lane_mapping) {
 202                pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
 203                        v);
 204                use_default_lane_mapping = true;
 205        }
 206
 207        if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
 208                flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
 209                pr_debug("non-continuous clock\n");
 210        } else {
 211                flags |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
 212        }
 213
 214        if (bus_type == V4L2_MBUS_CSI2_DPHY ||
 215            bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used ||
 216            have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) {
 217                /* Only D-PHY has a clock lane. */
 218                unsigned int dfl_data_lane_index =
 219                        bus_type == V4L2_MBUS_CSI2_DPHY;
 220
 221                bus->flags = flags;
 222                if (bus_type == V4L2_MBUS_UNKNOWN)
 223                        vep->bus_type = V4L2_MBUS_CSI2_DPHY;
 224                bus->num_data_lanes = num_data_lanes;
 225
 226                if (use_default_lane_mapping) {
 227                        bus->clock_lane = 0;
 228                        for (i = 0; i < num_data_lanes; i++)
 229                                bus->data_lanes[i] = dfl_data_lane_index + i;
 230                } else {
 231                        bus->clock_lane = clock_lane;
 232                        for (i = 0; i < num_data_lanes; i++)
 233                                bus->data_lanes[i] = array[i];
 234                }
 235
 236                if (have_lane_polarities) {
 237                        fwnode_property_read_u32_array(fwnode,
 238                                                       "lane-polarities", array,
 239                                                       1 + num_data_lanes);
 240
 241                        for (i = 0; i < 1 + num_data_lanes; i++) {
 242                                bus->lane_polarities[i] = array[i];
 243                                pr_debug("lane %u polarity %sinverted",
 244                                         i, array[i] ? "" : "not ");
 245                        }
 246                } else {
 247                        pr_debug("no lane polarities defined, assuming not inverted\n");
 248                }
 249        }
 250
 251        return 0;
 252}
 253
 254#define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH |      \
 255                             V4L2_MBUS_HSYNC_ACTIVE_LOW |       \
 256                             V4L2_MBUS_VSYNC_ACTIVE_HIGH |      \
 257                             V4L2_MBUS_VSYNC_ACTIVE_LOW |       \
 258                             V4L2_MBUS_FIELD_EVEN_HIGH |        \
 259                             V4L2_MBUS_FIELD_EVEN_LOW)
 260
 261static void
 262v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
 263                                        struct v4l2_fwnode_endpoint *vep,
 264                                        enum v4l2_mbus_type bus_type)
 265{
 266        struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel;
 267        unsigned int flags = 0;
 268        u32 v;
 269
 270        if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
 271                flags = bus->flags;
 272
 273        if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
 274                flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
 275                           V4L2_MBUS_HSYNC_ACTIVE_LOW);
 276                flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
 277                        V4L2_MBUS_HSYNC_ACTIVE_LOW;
 278                pr_debug("hsync-active %s\n", v ? "high" : "low");
 279        }
 280
 281        if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
 282                flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
 283                           V4L2_MBUS_VSYNC_ACTIVE_LOW);
 284                flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
 285                        V4L2_MBUS_VSYNC_ACTIVE_LOW;
 286                pr_debug("vsync-active %s\n", v ? "high" : "low");
 287        }
 288
 289        if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
 290                flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
 291                           V4L2_MBUS_FIELD_EVEN_LOW);
 292                flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
 293                        V4L2_MBUS_FIELD_EVEN_LOW;
 294                pr_debug("field-even-active %s\n", v ? "high" : "low");
 295        }
 296
 297        if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
 298                flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
 299                           V4L2_MBUS_PCLK_SAMPLE_FALLING);
 300                flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
 301                        V4L2_MBUS_PCLK_SAMPLE_FALLING;
 302                pr_debug("pclk-sample %s\n", v ? "high" : "low");
 303        }
 304
 305        if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
 306                flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
 307                           V4L2_MBUS_DATA_ACTIVE_LOW);
 308                flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
 309                        V4L2_MBUS_DATA_ACTIVE_LOW;
 310                pr_debug("data-active %s\n", v ? "high" : "low");
 311        }
 312
 313        if (fwnode_property_present(fwnode, "slave-mode")) {
 314                pr_debug("slave mode\n");
 315                flags &= ~V4L2_MBUS_MASTER;
 316                flags |= V4L2_MBUS_SLAVE;
 317        } else {
 318                flags &= ~V4L2_MBUS_SLAVE;
 319                flags |= V4L2_MBUS_MASTER;
 320        }
 321
 322        if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
 323                bus->bus_width = v;
 324                pr_debug("bus-width %u\n", v);
 325        }
 326
 327        if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
 328                bus->data_shift = v;
 329                pr_debug("data-shift %u\n", v);
 330        }
 331
 332        if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
 333                flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
 334                           V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
 335                flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
 336                        V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
 337                pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
 338        }
 339
 340        if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
 341                flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
 342                           V4L2_MBUS_DATA_ENABLE_LOW);
 343                flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
 344                        V4L2_MBUS_DATA_ENABLE_LOW;
 345                pr_debug("data-enable-active %s\n", v ? "high" : "low");
 346        }
 347
 348        switch (bus_type) {
 349        default:
 350                bus->flags = flags;
 351                if (flags & PARALLEL_MBUS_FLAGS)
 352                        vep->bus_type = V4L2_MBUS_PARALLEL;
 353                else
 354                        vep->bus_type = V4L2_MBUS_BT656;
 355                break;
 356        case V4L2_MBUS_PARALLEL:
 357                vep->bus_type = V4L2_MBUS_PARALLEL;
 358                bus->flags = flags;
 359                break;
 360        case V4L2_MBUS_BT656:
 361                vep->bus_type = V4L2_MBUS_BT656;
 362                bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
 363                break;
 364        }
 365}
 366
 367static void
 368v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
 369                                    struct v4l2_fwnode_endpoint *vep,
 370                                    enum v4l2_mbus_type bus_type)
 371{
 372        struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1;
 373        u32 v;
 374
 375        if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
 376                bus->clock_inv = v;
 377                pr_debug("clock-inv %u\n", v);
 378        }
 379
 380        if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
 381                bus->strobe = v;
 382                pr_debug("strobe %u\n", v);
 383        }
 384
 385        if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
 386                bus->data_lane = v;
 387                pr_debug("data-lanes %u\n", v);
 388        }
 389
 390        if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
 391                bus->clock_lane = v;
 392                pr_debug("clock-lanes %u\n", v);
 393        }
 394
 395        if (bus_type == V4L2_MBUS_CCP2)
 396                vep->bus_type = V4L2_MBUS_CCP2;
 397        else
 398                vep->bus_type = V4L2_MBUS_CSI1;
 399}
 400
 401static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
 402                                        struct v4l2_fwnode_endpoint *vep)
 403{
 404        u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
 405        enum v4l2_mbus_type mbus_type;
 406        int rval;
 407
 408        pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
 409
 410        fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
 411        pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
 412                 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
 413                 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
 414                 vep->bus_type);
 415        mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
 416        if (mbus_type == V4L2_MBUS_INVALID) {
 417                pr_debug("unsupported bus type %u\n", bus_type);
 418                return -EINVAL;
 419        }
 420
 421        if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
 422                if (mbus_type != V4L2_MBUS_UNKNOWN &&
 423                    vep->bus_type != mbus_type) {
 424                        pr_debug("expecting bus type %s\n",
 425                                 v4l2_fwnode_mbus_type_to_string(vep->bus_type));
 426                        return -ENXIO;
 427                }
 428        } else {
 429                vep->bus_type = mbus_type;
 430        }
 431
 432        switch (vep->bus_type) {
 433        case V4L2_MBUS_UNKNOWN:
 434                rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
 435                                                           V4L2_MBUS_UNKNOWN);
 436                if (rval)
 437                        return rval;
 438
 439                if (vep->bus_type == V4L2_MBUS_UNKNOWN)
 440                        v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
 441                                                                V4L2_MBUS_UNKNOWN);
 442
 443                pr_debug("assuming media bus type %s (%u)\n",
 444                         v4l2_fwnode_mbus_type_to_string(vep->bus_type),
 445                         vep->bus_type);
 446
 447                break;
 448        case V4L2_MBUS_CCP2:
 449        case V4L2_MBUS_CSI1:
 450                v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
 451
 452                break;
 453        case V4L2_MBUS_CSI2_DPHY:
 454        case V4L2_MBUS_CSI2_CPHY:
 455                rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
 456                                                           vep->bus_type);
 457                if (rval)
 458                        return rval;
 459
 460                break;
 461        case V4L2_MBUS_PARALLEL:
 462        case V4L2_MBUS_BT656:
 463                v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
 464                                                        vep->bus_type);
 465
 466                break;
 467        default:
 468                pr_warn("unsupported bus type %u\n", mbus_type);
 469                return -EINVAL;
 470        }
 471
 472        fwnode_graph_parse_endpoint(fwnode, &vep->base);
 473
 474        return 0;
 475}
 476
 477int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
 478                               struct v4l2_fwnode_endpoint *vep)
 479{
 480        int ret;
 481
 482        ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
 483
 484        pr_debug("===== end parsing endpoint %pfw\n", fwnode);
 485
 486        return ret;
 487}
 488EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
 489
 490void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
 491{
 492        if (IS_ERR_OR_NULL(vep))
 493                return;
 494
 495        kfree(vep->link_frequencies);
 496        vep->link_frequencies = NULL;
 497}
 498EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
 499
 500int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
 501                                     struct v4l2_fwnode_endpoint *vep)
 502{
 503        int rval;
 504
 505        rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
 506        if (rval < 0)
 507                return rval;
 508
 509        rval = fwnode_property_count_u64(fwnode, "link-frequencies");
 510        if (rval > 0) {
 511                unsigned int i;
 512
 513                vep->link_frequencies =
 514                        kmalloc_array(rval, sizeof(*vep->link_frequencies),
 515                                      GFP_KERNEL);
 516                if (!vep->link_frequencies)
 517                        return -ENOMEM;
 518
 519                vep->nr_of_link_frequencies = rval;
 520
 521                rval = fwnode_property_read_u64_array(fwnode,
 522                                                      "link-frequencies",
 523                                                      vep->link_frequencies,
 524                                                      vep->nr_of_link_frequencies);
 525                if (rval < 0) {
 526                        v4l2_fwnode_endpoint_free(vep);
 527                        return rval;
 528                }
 529
 530                for (i = 0; i < vep->nr_of_link_frequencies; i++)
 531                        pr_debug("link-frequencies %u value %llu\n", i,
 532                                 vep->link_frequencies[i]);
 533        }
 534
 535        pr_debug("===== end parsing endpoint %pfw\n", fwnode);
 536
 537        return 0;
 538}
 539EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
 540
 541int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
 542                           struct v4l2_fwnode_link *link)
 543{
 544        struct fwnode_endpoint fwep;
 545
 546        memset(link, 0, sizeof(*link));
 547
 548        fwnode_graph_parse_endpoint(fwnode, &fwep);
 549        link->local_id = fwep.id;
 550        link->local_port = fwep.port;
 551        link->local_node = fwnode_graph_get_port_parent(fwnode);
 552
 553        fwnode = fwnode_graph_get_remote_endpoint(fwnode);
 554        if (!fwnode) {
 555                fwnode_handle_put(fwnode);
 556                return -ENOLINK;
 557        }
 558
 559        fwnode_graph_parse_endpoint(fwnode, &fwep);
 560        link->remote_id = fwep.id;
 561        link->remote_port = fwep.port;
 562        link->remote_node = fwnode_graph_get_port_parent(fwnode);
 563
 564        return 0;
 565}
 566EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
 567
 568void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 569{
 570        fwnode_handle_put(link->local_node);
 571        fwnode_handle_put(link->remote_node);
 572}
 573EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 574
 575static const struct v4l2_fwnode_connector_conv {
 576        enum v4l2_connector_type type;
 577        const char *compatible;
 578} connectors[] = {
 579        {
 580                .type = V4L2_CONN_COMPOSITE,
 581                .compatible = "composite-video-connector",
 582        }, {
 583                .type = V4L2_CONN_SVIDEO,
 584                .compatible = "svideo-connector",
 585        },
 586};
 587
 588static enum v4l2_connector_type
 589v4l2_fwnode_string_to_connector_type(const char *con_str)
 590{
 591        unsigned int i;
 592
 593        for (i = 0; i < ARRAY_SIZE(connectors); i++)
 594                if (!strcmp(con_str, connectors[i].compatible))
 595                        return connectors[i].type;
 596
 597        return V4L2_CONN_UNKNOWN;
 598}
 599
 600static void
 601v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
 602                                   struct v4l2_fwnode_connector *vc)
 603{
 604        u32 stds;
 605        int ret;
 606
 607        ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
 608
 609        /* The property is optional. */
 610        vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
 611}
 612
 613void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
 614{
 615        struct v4l2_connector_link *link, *tmp;
 616
 617        if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
 618                return;
 619
 620        list_for_each_entry_safe(link, tmp, &connector->links, head) {
 621                v4l2_fwnode_put_link(&link->fwnode_link);
 622                list_del(&link->head);
 623                kfree(link);
 624        }
 625
 626        kfree(connector->label);
 627        connector->label = NULL;
 628        connector->type = V4L2_CONN_UNKNOWN;
 629}
 630EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
 631
 632static enum v4l2_connector_type
 633v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
 634{
 635        const char *type_name;
 636        int err;
 637
 638        if (!fwnode)
 639                return V4L2_CONN_UNKNOWN;
 640
 641        /* The connector-type is stored within the compatible string. */
 642        err = fwnode_property_read_string(fwnode, "compatible", &type_name);
 643        if (err)
 644                return V4L2_CONN_UNKNOWN;
 645
 646        return v4l2_fwnode_string_to_connector_type(type_name);
 647}
 648
 649int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
 650                                struct v4l2_fwnode_connector *connector)
 651{
 652        struct fwnode_handle *connector_node;
 653        enum v4l2_connector_type connector_type;
 654        const char *label;
 655        int err;
 656
 657        if (!fwnode)
 658                return -EINVAL;
 659
 660        memset(connector, 0, sizeof(*connector));
 661
 662        INIT_LIST_HEAD(&connector->links);
 663
 664        connector_node = fwnode_graph_get_port_parent(fwnode);
 665        connector_type = v4l2_fwnode_get_connector_type(connector_node);
 666        if (connector_type == V4L2_CONN_UNKNOWN) {
 667                fwnode_handle_put(connector_node);
 668                connector_node = fwnode_graph_get_remote_port_parent(fwnode);
 669                connector_type = v4l2_fwnode_get_connector_type(connector_node);
 670        }
 671
 672        if (connector_type == V4L2_CONN_UNKNOWN) {
 673                pr_err("Unknown connector type\n");
 674                err = -ENOTCONN;
 675                goto out;
 676        }
 677
 678        connector->type = connector_type;
 679        connector->name = fwnode_get_name(connector_node);
 680        err = fwnode_property_read_string(connector_node, "label", &label);
 681        connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
 682
 683        /* Parse the connector specific properties. */
 684        switch (connector->type) {
 685        case V4L2_CONN_COMPOSITE:
 686        case V4L2_CONN_SVIDEO:
 687                v4l2_fwnode_connector_parse_analog(connector_node, connector);
 688                break;
 689        /* Avoid compiler warnings */
 690        case V4L2_CONN_UNKNOWN:
 691                break;
 692        }
 693
 694out:
 695        fwnode_handle_put(connector_node);
 696
 697        return err;
 698}
 699EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
 700
 701int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
 702                                   struct v4l2_fwnode_connector *connector)
 703{
 704        struct fwnode_handle *connector_ep;
 705        struct v4l2_connector_link *link;
 706        int err;
 707
 708        if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
 709                return -EINVAL;
 710
 711        connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
 712        if (!connector_ep)
 713                return -ENOTCONN;
 714
 715        link = kzalloc(sizeof(*link), GFP_KERNEL);
 716        if (!link) {
 717                err = -ENOMEM;
 718                goto err;
 719        }
 720
 721        err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
 722        if (err)
 723                goto err;
 724
 725        fwnode_handle_put(connector_ep);
 726
 727        list_add(&link->head, &connector->links);
 728        connector->nr_of_links++;
 729
 730        return 0;
 731
 732err:
 733        kfree(link);
 734        fwnode_handle_put(connector_ep);
 735
 736        return err;
 737}
 738EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
 739
 740int v4l2_fwnode_device_parse(struct device *dev,
 741                             struct v4l2_fwnode_device_properties *props)
 742{
 743        struct fwnode_handle *fwnode = dev_fwnode(dev);
 744        u32 val;
 745        int ret;
 746
 747        memset(props, 0, sizeof(*props));
 748
 749        props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
 750        ret = fwnode_property_read_u32(fwnode, "orientation", &val);
 751        if (!ret) {
 752                switch (val) {
 753                case V4L2_FWNODE_ORIENTATION_FRONT:
 754                case V4L2_FWNODE_ORIENTATION_BACK:
 755                case V4L2_FWNODE_ORIENTATION_EXTERNAL:
 756                        break;
 757                default:
 758                        dev_warn(dev, "Unsupported device orientation: %u\n", val);
 759                        return -EINVAL;
 760                }
 761
 762                props->orientation = val;
 763                dev_dbg(dev, "device orientation: %u\n", val);
 764        }
 765
 766        props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
 767        ret = fwnode_property_read_u32(fwnode, "rotation", &val);
 768        if (!ret) {
 769                if (val >= 360) {
 770                        dev_warn(dev, "Unsupported device rotation: %u\n", val);
 771                        return -EINVAL;
 772                }
 773
 774                props->rotation = val;
 775                dev_dbg(dev, "device rotation: %u\n", val);
 776        }
 777
 778        return 0;
 779}
 780EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
 781
 782static int
 783v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev,
 784                                          struct v4l2_async_notifier *notifier,
 785                                          struct fwnode_handle *endpoint,
 786                                          unsigned int asd_struct_size,
 787                                          parse_endpoint_func parse_endpoint)
 788{
 789        struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
 790        struct v4l2_async_subdev *asd;
 791        int ret;
 792
 793        asd = kzalloc(asd_struct_size, GFP_KERNEL);
 794        if (!asd)
 795                return -ENOMEM;
 796
 797        asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
 798        asd->match.fwnode =
 799                fwnode_graph_get_remote_port_parent(endpoint);
 800        if (!asd->match.fwnode) {
 801                dev_dbg(dev, "no remote endpoint found\n");
 802                ret = -ENOTCONN;
 803                goto out_err;
 804        }
 805
 806        ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
 807        if (ret) {
 808                dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
 809                         ret);
 810                goto out_err;
 811        }
 812
 813        ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
 814        if (ret == -ENOTCONN)
 815                dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
 816                        vep.base.id);
 817        else if (ret < 0)
 818                dev_warn(dev,
 819                         "driver could not parse port@%u/endpoint@%u (%d)\n",
 820                         vep.base.port, vep.base.id, ret);
 821        v4l2_fwnode_endpoint_free(&vep);
 822        if (ret < 0)
 823                goto out_err;
 824
 825        ret = __v4l2_async_notifier_add_subdev(notifier, asd);
 826        if (ret < 0) {
 827                /* not an error if asd already exists */
 828                if (ret == -EEXIST)
 829                        ret = 0;
 830                goto out_err;
 831        }
 832
 833        return 0;
 834
 835out_err:
 836        fwnode_handle_put(asd->match.fwnode);
 837        kfree(asd);
 838
 839        return ret == -ENOTCONN ? 0 : ret;
 840}
 841
 842static int
 843__v4l2_async_notifier_parse_fwnode_ep(struct device *dev,
 844                                      struct v4l2_async_notifier *notifier,
 845                                      size_t asd_struct_size,
 846                                      unsigned int port,
 847                                      bool has_port,
 848                                      parse_endpoint_func parse_endpoint)
 849{
 850        struct fwnode_handle *fwnode;
 851        int ret = 0;
 852
 853        if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
 854                return -EINVAL;
 855
 856        fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
 857                struct fwnode_handle *dev_fwnode;
 858                bool is_available;
 859
 860                dev_fwnode = fwnode_graph_get_port_parent(fwnode);
 861                is_available = fwnode_device_is_available(dev_fwnode);
 862                fwnode_handle_put(dev_fwnode);
 863                if (!is_available)
 864                        continue;
 865
 866                if (has_port) {
 867                        struct fwnode_endpoint ep;
 868
 869                        ret = fwnode_graph_parse_endpoint(fwnode, &ep);
 870                        if (ret)
 871                                break;
 872
 873                        if (ep.port != port)
 874                                continue;
 875                }
 876
 877                ret = v4l2_async_notifier_fwnode_parse_endpoint(dev,
 878                                                                notifier,
 879                                                                fwnode,
 880                                                                asd_struct_size,
 881                                                                parse_endpoint);
 882                if (ret < 0)
 883                        break;
 884        }
 885
 886        fwnode_handle_put(fwnode);
 887
 888        return ret;
 889}
 890
 891int
 892v4l2_async_notifier_parse_fwnode_endpoints(struct device *dev,
 893                                           struct v4l2_async_notifier *notifier,
 894                                           size_t asd_struct_size,
 895                                           parse_endpoint_func parse_endpoint)
 896{
 897        return __v4l2_async_notifier_parse_fwnode_ep(dev, notifier,
 898                                                     asd_struct_size, 0,
 899                                                     false, parse_endpoint);
 900}
 901EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
 902
 903/*
 904 * v4l2_fwnode_reference_parse - parse references for async sub-devices
 905 * @dev: the device node the properties of which are parsed for references
 906 * @notifier: the async notifier where the async subdevs will be added
 907 * @prop: the name of the property
 908 *
 909 * Return: 0 on success
 910 *         -ENOENT if no entries were found
 911 *         -ENOMEM if memory allocation failed
 912 *         -EINVAL if property parsing failed
 913 */
 914static int v4l2_fwnode_reference_parse(struct device *dev,
 915                                       struct v4l2_async_notifier *notifier,
 916                                       const char *prop)
 917{
 918        struct fwnode_reference_args args;
 919        unsigned int index;
 920        int ret;
 921
 922        for (index = 0;
 923             !(ret = fwnode_property_get_reference_args(dev_fwnode(dev),
 924                                                        prop, NULL, 0,
 925                                                        index, &args));
 926             index++)
 927                fwnode_handle_put(args.fwnode);
 928
 929        if (!index)
 930                return -ENOENT;
 931
 932        /*
 933         * Note that right now both -ENODATA and -ENOENT may signal
 934         * out-of-bounds access. Return the error in cases other than that.
 935         */
 936        if (ret != -ENOENT && ret != -ENODATA)
 937                return ret;
 938
 939        for (index = 0;
 940             !fwnode_property_get_reference_args(dev_fwnode(dev), prop, NULL,
 941                                                 0, index, &args);
 942             index++) {
 943                struct v4l2_async_subdev *asd;
 944
 945                asd = v4l2_async_notifier_add_fwnode_subdev(notifier,
 946                                                            args.fwnode,
 947                                                            struct v4l2_async_subdev);
 948                fwnode_handle_put(args.fwnode);
 949                if (IS_ERR(asd)) {
 950                        /* not an error if asd already exists */
 951                        if (PTR_ERR(asd) == -EEXIST)
 952                                continue;
 953
 954                        return PTR_ERR(asd);
 955                }
 956        }
 957
 958        return 0;
 959}
 960
 961/*
 962 * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
 963 *                                      arguments
 964 * @fwnode: fwnode to read @prop from
 965 * @notifier: notifier for @dev
 966 * @prop: the name of the property
 967 * @index: the index of the reference to get
 968 * @props: the array of integer property names
 969 * @nprops: the number of integer property names in @nprops
 970 *
 971 * First find an fwnode referred to by the reference at @index in @prop.
 972 *
 973 * Then under that fwnode, @nprops times, for each property in @props,
 974 * iteratively follow child nodes starting from fwnode such that they have the
 975 * property in @props array at the index of the child node distance from the
 976 * root node and the value of that property matching with the integer argument
 977 * of the reference, at the same index.
 978 *
 979 * The child fwnode reached at the end of the iteration is then returned to the
 980 * caller.
 981 *
 982 * The core reason for this is that you cannot refer to just any node in ACPI.
 983 * So to refer to an endpoint (easy in DT) you need to refer to a device, then
 984 * provide a list of (property name, property value) tuples where each tuple
 985 * uniquely identifies a child node. The first tuple identifies a child directly
 986 * underneath the device fwnode, the next tuple identifies a child node
 987 * underneath the fwnode identified by the previous tuple, etc. until you
 988 * reached the fwnode you need.
 989 *
 990 * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A
 991 * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under
 992 * Documentation/firmware-guide/acpi/dsd/ instead and especially graph.txt,
 993 * data-node-references.txt and leds.txt .
 994 *
 995 *      Scope (\_SB.PCI0.I2C2)
 996 *      {
 997 *              Device (CAM0)
 998 *              {
 999 *                      Name (_DSD, Package () {
1000 *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1001 *                              Package () {
1002 *                                      Package () {
1003 *                                              "compatible",
1004 *                                              Package () { "nokia,smia" }
1005 *                                      },
1006 *                              },
1007 *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1008 *                              Package () {
1009 *                                      Package () { "port0", "PRT0" },
1010 *                              }
1011 *                      })
1012 *                      Name (PRT0, Package() {
1013 *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1014 *                              Package () {
1015 *                                      Package () { "port", 0 },
1016 *                              },
1017 *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1018 *                              Package () {
1019 *                                      Package () { "endpoint0", "EP00" },
1020 *                              }
1021 *                      })
1022 *                      Name (EP00, Package() {
1023 *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1024 *                              Package () {
1025 *                                      Package () { "endpoint", 0 },
1026 *                                      Package () {
1027 *                                              "remote-endpoint",
1028 *                                              Package() {
1029 *                                                      \_SB.PCI0.ISP, 4, 0
1030 *                                              }
1031 *                                      },
1032 *                              }
1033 *                      })
1034 *              }
1035 *      }
1036 *
1037 *      Scope (\_SB.PCI0)
1038 *      {
1039 *              Device (ISP)
1040 *              {
1041 *                      Name (_DSD, Package () {
1042 *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1043 *                              Package () {
1044 *                                      Package () { "port4", "PRT4" },
1045 *                              }
1046 *                      })
1047 *
1048 *                      Name (PRT4, Package() {
1049 *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1050 *                              Package () {
1051 *                                      Package () { "port", 4 },
1052 *                              },
1053 *                              ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
1054 *                              Package () {
1055 *                                      Package () { "endpoint0", "EP40" },
1056 *                              }
1057 *                      })
1058 *
1059 *                      Name (EP40, Package() {
1060 *                              ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
1061 *                              Package () {
1062 *                                      Package () { "endpoint", 0 },
1063 *                                      Package () {
1064 *                                              "remote-endpoint",
1065 *                                              Package () {
1066 *                                                      \_SB.PCI0.I2C2.CAM0,
1067 *                                                      0, 0
1068 *                                              }
1069 *                                      },
1070 *                              }
1071 *                      })
1072 *              }
1073 *      }
1074 *
1075 * From the EP40 node under ISP device, you could parse the graph remote
1076 * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
1077 *
1078 *  @fwnode: fwnode referring to EP40 under ISP.
1079 *  @prop: "remote-endpoint"
1080 *  @index: 0
1081 *  @props: "port", "endpoint"
1082 *  @nprops: 2
1083 *
1084 * And you'd get back fwnode referring to EP00 under CAM0.
1085 *
1086 * The same works the other way around: if you use EP00 under CAM0 as the
1087 * fwnode, you'll get fwnode referring to EP40 under ISP.
1088 *
1089 * The same example in DT syntax would look like this:
1090 *
1091 * cam: cam0 {
1092 *      compatible = "nokia,smia";
1093 *
1094 *      port {
1095 *              port = <0>;
1096 *              endpoint {
1097 *                      endpoint = <0>;
1098 *                      remote-endpoint = <&isp 4 0>;
1099 *              };
1100 *      };
1101 * };
1102 *
1103 * isp: isp {
1104 *      ports {
1105 *              port@4 {
1106 *                      port = <4>;
1107 *                      endpoint {
1108 *                              endpoint = <0>;
1109 *                              remote-endpoint = <&cam 0 0>;
1110 *                      };
1111 *              };
1112 *      };
1113 * };
1114 *
1115 * Return: 0 on success
1116 *         -ENOENT if no entries (or the property itself) were found
1117 *         -EINVAL if property parsing otherwise failed
1118 *         -ENOMEM if memory allocation failed
1119 */
1120static struct fwnode_handle *
1121v4l2_fwnode_reference_get_int_prop(struct fwnode_handle *fwnode,
1122                                   const char *prop,
1123                                   unsigned int index,
1124                                   const char * const *props,
1125                                   unsigned int nprops)
1126{
1127        struct fwnode_reference_args fwnode_args;
1128        u64 *args = fwnode_args.args;
1129        struct fwnode_handle *child;
1130        int ret;
1131
1132        /*
1133         * Obtain remote fwnode as well as the integer arguments.
1134         *
1135         * Note that right now both -ENODATA and -ENOENT may signal
1136         * out-of-bounds access. Return -ENOENT in that case.
1137         */
1138        ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
1139                                                 index, &fwnode_args);
1140        if (ret)
1141                return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
1142
1143        /*
1144         * Find a node in the tree under the referred fwnode corresponding to
1145         * the integer arguments.
1146         */
1147        fwnode = fwnode_args.fwnode;
1148        while (nprops--) {
1149                u32 val;
1150
1151                /* Loop over all child nodes under fwnode. */
1152                fwnode_for_each_child_node(fwnode, child) {
1153                        if (fwnode_property_read_u32(child, *props, &val))
1154                                continue;
1155
1156                        /* Found property, see if its value matches. */
1157                        if (val == *args)
1158                                break;
1159                }
1160
1161                fwnode_handle_put(fwnode);
1162
1163                /* No property found; return an error here. */
1164                if (!child) {
1165                        fwnode = ERR_PTR(-ENOENT);
1166                        break;
1167                }
1168
1169                props++;
1170                args++;
1171                fwnode = child;
1172        }
1173
1174        return fwnode;
1175}
1176
1177struct v4l2_fwnode_int_props {
1178        const char *name;
1179        const char * const *props;
1180        unsigned int nprops;
1181};
1182
1183/*
1184 * v4l2_fwnode_reference_parse_int_props - parse references for async
1185 *                                         sub-devices
1186 * @dev: struct device pointer
1187 * @notifier: notifier for @dev
1188 * @prop: the name of the property
1189 * @props: the array of integer property names
1190 * @nprops: the number of integer properties
1191 *
1192 * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
1193 * property @prop with integer arguments with child nodes matching in properties
1194 * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
1195 * accordingly.
1196 *
1197 * While it is technically possible to use this function on DT, it is only
1198 * meaningful on ACPI. On Device tree you can refer to any node in the tree but
1199 * on ACPI the references are limited to devices.
1200 *
1201 * Return: 0 on success
1202 *         -ENOENT if no entries (or the property itself) were found
1203 *         -EINVAL if property parsing otherwisefailed
1204 *         -ENOMEM if memory allocation failed
1205 */
1206static int
1207v4l2_fwnode_reference_parse_int_props(struct device *dev,
1208                                      struct v4l2_async_notifier *notifier,
1209                                      const struct v4l2_fwnode_int_props *p)
1210{
1211        struct fwnode_handle *fwnode;
1212        unsigned int index;
1213        int ret;
1214        const char *prop = p->name;
1215        const char * const *props = p->props;
1216        unsigned int nprops = p->nprops;
1217
1218        index = 0;
1219        do {
1220                fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1221                                                            prop, index,
1222                                                            props, nprops);
1223                if (IS_ERR(fwnode)) {
1224                        /*
1225                         * Note that right now both -ENODATA and -ENOENT may
1226                         * signal out-of-bounds access. Return the error in
1227                         * cases other than that.
1228                         */
1229                        if (PTR_ERR(fwnode) != -ENOENT &&
1230                            PTR_ERR(fwnode) != -ENODATA)
1231                                return PTR_ERR(fwnode);
1232                        break;
1233                }
1234                fwnode_handle_put(fwnode);
1235                index++;
1236        } while (1);
1237
1238        for (index = 0;
1239             !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(dev_fwnode(dev),
1240                                                                  prop, index,
1241                                                                  props,
1242                                                                  nprops)));
1243             index++) {
1244                struct v4l2_async_subdev *asd;
1245
1246                asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
1247                                                            struct v4l2_async_subdev);
1248                fwnode_handle_put(fwnode);
1249                if (IS_ERR(asd)) {
1250                        ret = PTR_ERR(asd);
1251                        /* not an error if asd already exists */
1252                        if (ret == -EEXIST)
1253                                continue;
1254
1255                        return PTR_ERR(asd);
1256                }
1257        }
1258
1259        return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
1260}
1261
1262/**
1263 * v4l2_async_notifier_parse_fwnode_sensor - parse common references on
1264 *                                           sensors for async sub-devices
1265 * @dev: the device node the properties of which are parsed for references
1266 * @notifier: the async notifier where the async subdevs will be added
1267 *
1268 * Parse common sensor properties for remote devices related to the
1269 * sensor and set up async sub-devices for them.
1270 *
1271 * Any notifier populated using this function must be released with a call to
1272 * v4l2_async_notifier_release() after it has been unregistered and the async
1273 * sub-devices are no longer in use, even in the case the function returned an
1274 * error.
1275 *
1276 * Return: 0 on success
1277 *         -ENOMEM if memory allocation failed
1278 *         -EINVAL if property parsing failed
1279 */
1280static int
1281v4l2_async_notifier_parse_fwnode_sensor(struct device *dev,
1282                                        struct v4l2_async_notifier *notifier)
1283{
1284        static const char * const led_props[] = { "led" };
1285        static const struct v4l2_fwnode_int_props props[] = {
1286                { "flash-leds", led_props, ARRAY_SIZE(led_props) },
1287                { "lens-focus", NULL, 0 },
1288        };
1289        unsigned int i;
1290
1291        for (i = 0; i < ARRAY_SIZE(props); i++) {
1292                int ret;
1293
1294                if (props[i].props && is_acpi_node(dev_fwnode(dev)))
1295                        ret = v4l2_fwnode_reference_parse_int_props(dev,
1296                                                                    notifier,
1297                                                                    &props[i]);
1298                else
1299                        ret = v4l2_fwnode_reference_parse(dev, notifier,
1300                                                          props[i].name);
1301                if (ret && ret != -ENOENT) {
1302                        dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
1303                                 props[i].name, ret);
1304                        return ret;
1305                }
1306        }
1307
1308        return 0;
1309}
1310
1311int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd)
1312{
1313        struct v4l2_async_notifier *notifier;
1314        int ret;
1315
1316        if (WARN_ON(!sd->dev))
1317                return -ENODEV;
1318
1319        notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
1320        if (!notifier)
1321                return -ENOMEM;
1322
1323        v4l2_async_notifier_init(notifier);
1324
1325        ret = v4l2_async_notifier_parse_fwnode_sensor(sd->dev, notifier);
1326        if (ret < 0)
1327                goto out_cleanup;
1328
1329        ret = v4l2_async_subdev_notifier_register(sd, notifier);
1330        if (ret < 0)
1331                goto out_cleanup;
1332
1333        ret = v4l2_async_register_subdev(sd);
1334        if (ret < 0)
1335                goto out_unregister;
1336
1337        sd->subdev_notifier = notifier;
1338
1339        return 0;
1340
1341out_unregister:
1342        v4l2_async_notifier_unregister(notifier);
1343
1344out_cleanup:
1345        v4l2_async_notifier_cleanup(notifier);
1346        kfree(notifier);
1347
1348        return ret;
1349}
1350EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor);
1351
1352MODULE_LICENSE("GPL");
1353MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1354MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1355MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
1356