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