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