0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include <linux/acpi.h>
0018 #include <linux/kernel.h>
0019 #include <linux/mm.h>
0020 #include <linux/module.h>
0021 #include <linux/of.h>
0022 #include <linux/property.h>
0023 #include <linux/slab.h>
0024 #include <linux/string.h>
0025 #include <linux/types.h>
0026
0027 #include <media/v4l2-async.h>
0028 #include <media/v4l2-fwnode.h>
0029 #include <media/v4l2-subdev.h>
0030
0031 static const struct v4l2_fwnode_bus_conv {
0032 enum v4l2_fwnode_bus_type fwnode_bus_type;
0033 enum v4l2_mbus_type mbus_type;
0034 const char *name;
0035 } buses[] = {
0036 {
0037 V4L2_FWNODE_BUS_TYPE_GUESS,
0038 V4L2_MBUS_UNKNOWN,
0039 "not specified",
0040 }, {
0041 V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
0042 V4L2_MBUS_CSI2_CPHY,
0043 "MIPI CSI-2 C-PHY",
0044 }, {
0045 V4L2_FWNODE_BUS_TYPE_CSI1,
0046 V4L2_MBUS_CSI1,
0047 "MIPI CSI-1",
0048 }, {
0049 V4L2_FWNODE_BUS_TYPE_CCP2,
0050 V4L2_MBUS_CCP2,
0051 "compact camera port 2",
0052 }, {
0053 V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
0054 V4L2_MBUS_CSI2_DPHY,
0055 "MIPI CSI-2 D-PHY",
0056 }, {
0057 V4L2_FWNODE_BUS_TYPE_PARALLEL,
0058 V4L2_MBUS_PARALLEL,
0059 "parallel",
0060 }, {
0061 V4L2_FWNODE_BUS_TYPE_BT656,
0062 V4L2_MBUS_BT656,
0063 "Bt.656",
0064 }, {
0065 V4L2_FWNODE_BUS_TYPE_DPI,
0066 V4L2_MBUS_DPI,
0067 "DPI",
0068 }
0069 };
0070
0071 static const struct v4l2_fwnode_bus_conv *
0072 get_v4l2_fwnode_bus_conv_by_fwnode_bus(enum v4l2_fwnode_bus_type type)
0073 {
0074 unsigned int i;
0075
0076 for (i = 0; i < ARRAY_SIZE(buses); i++)
0077 if (buses[i].fwnode_bus_type == type)
0078 return &buses[i];
0079
0080 return NULL;
0081 }
0082
0083 static enum v4l2_mbus_type
0084 v4l2_fwnode_bus_type_to_mbus(enum v4l2_fwnode_bus_type type)
0085 {
0086 const struct v4l2_fwnode_bus_conv *conv =
0087 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
0088
0089 return conv ? conv->mbus_type : V4L2_MBUS_INVALID;
0090 }
0091
0092 static const char *
0093 v4l2_fwnode_bus_type_to_string(enum v4l2_fwnode_bus_type type)
0094 {
0095 const struct v4l2_fwnode_bus_conv *conv =
0096 get_v4l2_fwnode_bus_conv_by_fwnode_bus(type);
0097
0098 return conv ? conv->name : "not found";
0099 }
0100
0101 static const struct v4l2_fwnode_bus_conv *
0102 get_v4l2_fwnode_bus_conv_by_mbus(enum v4l2_mbus_type type)
0103 {
0104 unsigned int i;
0105
0106 for (i = 0; i < ARRAY_SIZE(buses); i++)
0107 if (buses[i].mbus_type == type)
0108 return &buses[i];
0109
0110 return NULL;
0111 }
0112
0113 static const char *
0114 v4l2_fwnode_mbus_type_to_string(enum v4l2_mbus_type type)
0115 {
0116 const struct v4l2_fwnode_bus_conv *conv =
0117 get_v4l2_fwnode_bus_conv_by_mbus(type);
0118
0119 return conv ? conv->name : "not found";
0120 }
0121
0122 static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode,
0123 struct v4l2_fwnode_endpoint *vep,
0124 enum v4l2_mbus_type bus_type)
0125 {
0126 struct v4l2_mbus_config_mipi_csi2 *bus = &vep->bus.mipi_csi2;
0127 bool have_clk_lane = false, have_data_lanes = false,
0128 have_lane_polarities = false;
0129 unsigned int flags = 0, lanes_used = 0;
0130 u32 array[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES];
0131 u32 clock_lane = 0;
0132 unsigned int num_data_lanes = 0;
0133 bool use_default_lane_mapping = false;
0134 unsigned int i;
0135 u32 v;
0136 int rval;
0137
0138 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
0139 bus_type == V4L2_MBUS_CSI2_CPHY) {
0140 use_default_lane_mapping = true;
0141
0142 num_data_lanes = min_t(u32, bus->num_data_lanes,
0143 V4L2_MBUS_CSI2_MAX_DATA_LANES);
0144
0145 clock_lane = bus->clock_lane;
0146 if (clock_lane)
0147 use_default_lane_mapping = false;
0148
0149 for (i = 0; i < num_data_lanes; i++) {
0150 array[i] = bus->data_lanes[i];
0151 if (array[i])
0152 use_default_lane_mapping = false;
0153 }
0154
0155 if (use_default_lane_mapping)
0156 pr_debug("no lane mapping given, using defaults\n");
0157 }
0158
0159 rval = fwnode_property_count_u32(fwnode, "data-lanes");
0160 if (rval > 0) {
0161 num_data_lanes =
0162 min_t(int, V4L2_MBUS_CSI2_MAX_DATA_LANES, rval);
0163
0164 fwnode_property_read_u32_array(fwnode, "data-lanes", array,
0165 num_data_lanes);
0166
0167 have_data_lanes = true;
0168 if (use_default_lane_mapping) {
0169 pr_debug("data-lanes property exists; disabling default mapping\n");
0170 use_default_lane_mapping = false;
0171 }
0172 }
0173
0174 for (i = 0; i < num_data_lanes; i++) {
0175 if (lanes_used & BIT(array[i])) {
0176 if (have_data_lanes || !use_default_lane_mapping)
0177 pr_warn("duplicated lane %u in data-lanes, using defaults\n",
0178 array[i]);
0179 use_default_lane_mapping = true;
0180 }
0181 lanes_used |= BIT(array[i]);
0182
0183 if (have_data_lanes)
0184 pr_debug("lane %u position %u\n", i, array[i]);
0185 }
0186
0187 rval = fwnode_property_count_u32(fwnode, "lane-polarities");
0188 if (rval > 0) {
0189 if (rval != 1 + num_data_lanes ) {
0190 pr_warn("invalid number of lane-polarities entries (need %u, got %u)\n",
0191 1 + num_data_lanes, rval);
0192 return -EINVAL;
0193 }
0194
0195 have_lane_polarities = true;
0196 }
0197
0198 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
0199 clock_lane = v;
0200 pr_debug("clock lane position %u\n", v);
0201 have_clk_lane = true;
0202 }
0203
0204 if (have_clk_lane && lanes_used & BIT(clock_lane) &&
0205 !use_default_lane_mapping) {
0206 pr_warn("duplicated lane %u in clock-lanes, using defaults\n",
0207 v);
0208 use_default_lane_mapping = true;
0209 }
0210
0211 if (fwnode_property_present(fwnode, "clock-noncontinuous")) {
0212 flags |= V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
0213 pr_debug("non-continuous clock\n");
0214 }
0215
0216 if (bus_type == V4L2_MBUS_CSI2_DPHY ||
0217 bus_type == V4L2_MBUS_CSI2_CPHY ||
0218 lanes_used || have_clk_lane || flags) {
0219
0220 unsigned int dfl_data_lane_index =
0221 bus_type == V4L2_MBUS_CSI2_DPHY;
0222
0223 bus->flags = flags;
0224 if (bus_type == V4L2_MBUS_UNKNOWN)
0225 vep->bus_type = V4L2_MBUS_CSI2_DPHY;
0226 bus->num_data_lanes = num_data_lanes;
0227
0228 if (use_default_lane_mapping) {
0229 bus->clock_lane = 0;
0230 for (i = 0; i < num_data_lanes; i++)
0231 bus->data_lanes[i] = dfl_data_lane_index + i;
0232 } else {
0233 bus->clock_lane = clock_lane;
0234 for (i = 0; i < num_data_lanes; i++)
0235 bus->data_lanes[i] = array[i];
0236 }
0237
0238 if (have_lane_polarities) {
0239 fwnode_property_read_u32_array(fwnode,
0240 "lane-polarities", array,
0241 1 + num_data_lanes);
0242
0243 for (i = 0; i < 1 + num_data_lanes; i++) {
0244 bus->lane_polarities[i] = array[i];
0245 pr_debug("lane %u polarity %sinverted",
0246 i, array[i] ? "" : "not ");
0247 }
0248 } else {
0249 pr_debug("no lane polarities defined, assuming not inverted\n");
0250 }
0251 }
0252
0253 return 0;
0254 }
0255
0256 #define PARALLEL_MBUS_FLAGS (V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
0257 V4L2_MBUS_HSYNC_ACTIVE_LOW | \
0258 V4L2_MBUS_VSYNC_ACTIVE_HIGH | \
0259 V4L2_MBUS_VSYNC_ACTIVE_LOW | \
0260 V4L2_MBUS_FIELD_EVEN_HIGH | \
0261 V4L2_MBUS_FIELD_EVEN_LOW)
0262
0263 static void
0264 v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode,
0265 struct v4l2_fwnode_endpoint *vep,
0266 enum v4l2_mbus_type bus_type)
0267 {
0268 struct v4l2_mbus_config_parallel *bus = &vep->bus.parallel;
0269 unsigned int flags = 0;
0270 u32 v;
0271
0272 if (bus_type == V4L2_MBUS_PARALLEL || bus_type == V4L2_MBUS_BT656)
0273 flags = bus->flags;
0274
0275 if (!fwnode_property_read_u32(fwnode, "hsync-active", &v)) {
0276 flags &= ~(V4L2_MBUS_HSYNC_ACTIVE_HIGH |
0277 V4L2_MBUS_HSYNC_ACTIVE_LOW);
0278 flags |= v ? V4L2_MBUS_HSYNC_ACTIVE_HIGH :
0279 V4L2_MBUS_HSYNC_ACTIVE_LOW;
0280 pr_debug("hsync-active %s\n", v ? "high" : "low");
0281 }
0282
0283 if (!fwnode_property_read_u32(fwnode, "vsync-active", &v)) {
0284 flags &= ~(V4L2_MBUS_VSYNC_ACTIVE_HIGH |
0285 V4L2_MBUS_VSYNC_ACTIVE_LOW);
0286 flags |= v ? V4L2_MBUS_VSYNC_ACTIVE_HIGH :
0287 V4L2_MBUS_VSYNC_ACTIVE_LOW;
0288 pr_debug("vsync-active %s\n", v ? "high" : "low");
0289 }
0290
0291 if (!fwnode_property_read_u32(fwnode, "field-even-active", &v)) {
0292 flags &= ~(V4L2_MBUS_FIELD_EVEN_HIGH |
0293 V4L2_MBUS_FIELD_EVEN_LOW);
0294 flags |= v ? V4L2_MBUS_FIELD_EVEN_HIGH :
0295 V4L2_MBUS_FIELD_EVEN_LOW;
0296 pr_debug("field-even-active %s\n", v ? "high" : "low");
0297 }
0298
0299 if (!fwnode_property_read_u32(fwnode, "pclk-sample", &v)) {
0300 flags &= ~(V4L2_MBUS_PCLK_SAMPLE_RISING |
0301 V4L2_MBUS_PCLK_SAMPLE_FALLING);
0302 flags |= v ? V4L2_MBUS_PCLK_SAMPLE_RISING :
0303 V4L2_MBUS_PCLK_SAMPLE_FALLING;
0304 pr_debug("pclk-sample %s\n", v ? "high" : "low");
0305 }
0306
0307 if (!fwnode_property_read_u32(fwnode, "data-active", &v)) {
0308 flags &= ~(V4L2_MBUS_DATA_ACTIVE_HIGH |
0309 V4L2_MBUS_DATA_ACTIVE_LOW);
0310 flags |= v ? V4L2_MBUS_DATA_ACTIVE_HIGH :
0311 V4L2_MBUS_DATA_ACTIVE_LOW;
0312 pr_debug("data-active %s\n", v ? "high" : "low");
0313 }
0314
0315 if (fwnode_property_present(fwnode, "slave-mode")) {
0316 pr_debug("slave mode\n");
0317 flags &= ~V4L2_MBUS_MASTER;
0318 flags |= V4L2_MBUS_SLAVE;
0319 } else {
0320 flags &= ~V4L2_MBUS_SLAVE;
0321 flags |= V4L2_MBUS_MASTER;
0322 }
0323
0324 if (!fwnode_property_read_u32(fwnode, "bus-width", &v)) {
0325 bus->bus_width = v;
0326 pr_debug("bus-width %u\n", v);
0327 }
0328
0329 if (!fwnode_property_read_u32(fwnode, "data-shift", &v)) {
0330 bus->data_shift = v;
0331 pr_debug("data-shift %u\n", v);
0332 }
0333
0334 if (!fwnode_property_read_u32(fwnode, "sync-on-green-active", &v)) {
0335 flags &= ~(V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH |
0336 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW);
0337 flags |= v ? V4L2_MBUS_VIDEO_SOG_ACTIVE_HIGH :
0338 V4L2_MBUS_VIDEO_SOG_ACTIVE_LOW;
0339 pr_debug("sync-on-green-active %s\n", v ? "high" : "low");
0340 }
0341
0342 if (!fwnode_property_read_u32(fwnode, "data-enable-active", &v)) {
0343 flags &= ~(V4L2_MBUS_DATA_ENABLE_HIGH |
0344 V4L2_MBUS_DATA_ENABLE_LOW);
0345 flags |= v ? V4L2_MBUS_DATA_ENABLE_HIGH :
0346 V4L2_MBUS_DATA_ENABLE_LOW;
0347 pr_debug("data-enable-active %s\n", v ? "high" : "low");
0348 }
0349
0350 switch (bus_type) {
0351 default:
0352 bus->flags = flags;
0353 if (flags & PARALLEL_MBUS_FLAGS)
0354 vep->bus_type = V4L2_MBUS_PARALLEL;
0355 else
0356 vep->bus_type = V4L2_MBUS_BT656;
0357 break;
0358 case V4L2_MBUS_PARALLEL:
0359 vep->bus_type = V4L2_MBUS_PARALLEL;
0360 bus->flags = flags;
0361 break;
0362 case V4L2_MBUS_BT656:
0363 vep->bus_type = V4L2_MBUS_BT656;
0364 bus->flags = flags & ~PARALLEL_MBUS_FLAGS;
0365 break;
0366 }
0367 }
0368
0369 static void
0370 v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
0371 struct v4l2_fwnode_endpoint *vep,
0372 enum v4l2_mbus_type bus_type)
0373 {
0374 struct v4l2_mbus_config_mipi_csi1 *bus = &vep->bus.mipi_csi1;
0375 u32 v;
0376
0377 if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) {
0378 bus->clock_inv = v;
0379 pr_debug("clock-inv %u\n", v);
0380 }
0381
0382 if (!fwnode_property_read_u32(fwnode, "strobe", &v)) {
0383 bus->strobe = v;
0384 pr_debug("strobe %u\n", v);
0385 }
0386
0387 if (!fwnode_property_read_u32(fwnode, "data-lanes", &v)) {
0388 bus->data_lane = v;
0389 pr_debug("data-lanes %u\n", v);
0390 }
0391
0392 if (!fwnode_property_read_u32(fwnode, "clock-lanes", &v)) {
0393 bus->clock_lane = v;
0394 pr_debug("clock-lanes %u\n", v);
0395 }
0396
0397 if (bus_type == V4L2_MBUS_CCP2)
0398 vep->bus_type = V4L2_MBUS_CCP2;
0399 else
0400 vep->bus_type = V4L2_MBUS_CSI1;
0401 }
0402
0403 static int __v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
0404 struct v4l2_fwnode_endpoint *vep)
0405 {
0406 u32 bus_type = V4L2_FWNODE_BUS_TYPE_GUESS;
0407 enum v4l2_mbus_type mbus_type;
0408 int rval;
0409
0410 pr_debug("===== begin parsing endpoint %pfw\n", fwnode);
0411
0412 fwnode_property_read_u32(fwnode, "bus-type", &bus_type);
0413 pr_debug("fwnode video bus type %s (%u), mbus type %s (%u)\n",
0414 v4l2_fwnode_bus_type_to_string(bus_type), bus_type,
0415 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
0416 vep->bus_type);
0417 mbus_type = v4l2_fwnode_bus_type_to_mbus(bus_type);
0418 if (mbus_type == V4L2_MBUS_INVALID) {
0419 pr_debug("unsupported bus type %u\n", bus_type);
0420 return -EINVAL;
0421 }
0422
0423 if (vep->bus_type != V4L2_MBUS_UNKNOWN) {
0424 if (mbus_type != V4L2_MBUS_UNKNOWN &&
0425 vep->bus_type != mbus_type) {
0426 pr_debug("expecting bus type %s\n",
0427 v4l2_fwnode_mbus_type_to_string(vep->bus_type));
0428 return -ENXIO;
0429 }
0430 } else {
0431 vep->bus_type = mbus_type;
0432 }
0433
0434 switch (vep->bus_type) {
0435 case V4L2_MBUS_UNKNOWN:
0436 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
0437 V4L2_MBUS_UNKNOWN);
0438 if (rval)
0439 return rval;
0440
0441 if (vep->bus_type == V4L2_MBUS_UNKNOWN)
0442 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
0443 V4L2_MBUS_UNKNOWN);
0444
0445 pr_debug("assuming media bus type %s (%u)\n",
0446 v4l2_fwnode_mbus_type_to_string(vep->bus_type),
0447 vep->bus_type);
0448
0449 break;
0450 case V4L2_MBUS_CCP2:
0451 case V4L2_MBUS_CSI1:
0452 v4l2_fwnode_endpoint_parse_csi1_bus(fwnode, vep, vep->bus_type);
0453
0454 break;
0455 case V4L2_MBUS_CSI2_DPHY:
0456 case V4L2_MBUS_CSI2_CPHY:
0457 rval = v4l2_fwnode_endpoint_parse_csi2_bus(fwnode, vep,
0458 vep->bus_type);
0459 if (rval)
0460 return rval;
0461
0462 break;
0463 case V4L2_MBUS_PARALLEL:
0464 case V4L2_MBUS_BT656:
0465 v4l2_fwnode_endpoint_parse_parallel_bus(fwnode, vep,
0466 vep->bus_type);
0467
0468 break;
0469 default:
0470 pr_warn("unsupported bus type %u\n", mbus_type);
0471 return -EINVAL;
0472 }
0473
0474 fwnode_graph_parse_endpoint(fwnode, &vep->base);
0475
0476 return 0;
0477 }
0478
0479 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
0480 struct v4l2_fwnode_endpoint *vep)
0481 {
0482 int ret;
0483
0484 ret = __v4l2_fwnode_endpoint_parse(fwnode, vep);
0485
0486 pr_debug("===== end parsing endpoint %pfw\n", fwnode);
0487
0488 return ret;
0489 }
0490 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
0491
0492 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
0493 {
0494 if (IS_ERR_OR_NULL(vep))
0495 return;
0496
0497 kfree(vep->link_frequencies);
0498 vep->link_frequencies = NULL;
0499 }
0500 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
0501
0502 int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
0503 struct v4l2_fwnode_endpoint *vep)
0504 {
0505 int rval;
0506
0507 rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
0508 if (rval < 0)
0509 return rval;
0510
0511 rval = fwnode_property_count_u64(fwnode, "link-frequencies");
0512 if (rval > 0) {
0513 unsigned int i;
0514
0515 vep->link_frequencies =
0516 kmalloc_array(rval, sizeof(*vep->link_frequencies),
0517 GFP_KERNEL);
0518 if (!vep->link_frequencies)
0519 return -ENOMEM;
0520
0521 vep->nr_of_link_frequencies = rval;
0522
0523 rval = fwnode_property_read_u64_array(fwnode,
0524 "link-frequencies",
0525 vep->link_frequencies,
0526 vep->nr_of_link_frequencies);
0527 if (rval < 0) {
0528 v4l2_fwnode_endpoint_free(vep);
0529 return rval;
0530 }
0531
0532 for (i = 0; i < vep->nr_of_link_frequencies; i++)
0533 pr_debug("link-frequencies %u value %llu\n", i,
0534 vep->link_frequencies[i]);
0535 }
0536
0537 pr_debug("===== end parsing endpoint %pfw\n", fwnode);
0538
0539 return 0;
0540 }
0541 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
0542
0543 int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
0544 struct v4l2_fwnode_link *link)
0545 {
0546 struct fwnode_endpoint fwep;
0547
0548 memset(link, 0, sizeof(*link));
0549
0550 fwnode_graph_parse_endpoint(fwnode, &fwep);
0551 link->local_id = fwep.id;
0552 link->local_port = fwep.port;
0553 link->local_node = fwnode_graph_get_port_parent(fwnode);
0554
0555 fwnode = fwnode_graph_get_remote_endpoint(fwnode);
0556 if (!fwnode) {
0557 fwnode_handle_put(fwnode);
0558 return -ENOLINK;
0559 }
0560
0561 fwnode_graph_parse_endpoint(fwnode, &fwep);
0562 link->remote_id = fwep.id;
0563 link->remote_port = fwep.port;
0564 link->remote_node = fwnode_graph_get_port_parent(fwnode);
0565
0566 return 0;
0567 }
0568 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
0569
0570 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
0571 {
0572 fwnode_handle_put(link->local_node);
0573 fwnode_handle_put(link->remote_node);
0574 }
0575 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
0576
0577 static const struct v4l2_fwnode_connector_conv {
0578 enum v4l2_connector_type type;
0579 const char *compatible;
0580 } connectors[] = {
0581 {
0582 .type = V4L2_CONN_COMPOSITE,
0583 .compatible = "composite-video-connector",
0584 }, {
0585 .type = V4L2_CONN_SVIDEO,
0586 .compatible = "svideo-connector",
0587 },
0588 };
0589
0590 static enum v4l2_connector_type
0591 v4l2_fwnode_string_to_connector_type(const char *con_str)
0592 {
0593 unsigned int i;
0594
0595 for (i = 0; i < ARRAY_SIZE(connectors); i++)
0596 if (!strcmp(con_str, connectors[i].compatible))
0597 return connectors[i].type;
0598
0599 return V4L2_CONN_UNKNOWN;
0600 }
0601
0602 static void
0603 v4l2_fwnode_connector_parse_analog(struct fwnode_handle *fwnode,
0604 struct v4l2_fwnode_connector *vc)
0605 {
0606 u32 stds;
0607 int ret;
0608
0609 ret = fwnode_property_read_u32(fwnode, "sdtv-standards", &stds);
0610
0611
0612 vc->connector.analog.sdtv_stds = ret ? V4L2_STD_ALL : stds;
0613 }
0614
0615 void v4l2_fwnode_connector_free(struct v4l2_fwnode_connector *connector)
0616 {
0617 struct v4l2_connector_link *link, *tmp;
0618
0619 if (IS_ERR_OR_NULL(connector) || connector->type == V4L2_CONN_UNKNOWN)
0620 return;
0621
0622 list_for_each_entry_safe(link, tmp, &connector->links, head) {
0623 v4l2_fwnode_put_link(&link->fwnode_link);
0624 list_del(&link->head);
0625 kfree(link);
0626 }
0627
0628 kfree(connector->label);
0629 connector->label = NULL;
0630 connector->type = V4L2_CONN_UNKNOWN;
0631 }
0632 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_free);
0633
0634 static enum v4l2_connector_type
0635 v4l2_fwnode_get_connector_type(struct fwnode_handle *fwnode)
0636 {
0637 const char *type_name;
0638 int err;
0639
0640 if (!fwnode)
0641 return V4L2_CONN_UNKNOWN;
0642
0643
0644 err = fwnode_property_read_string(fwnode, "compatible", &type_name);
0645 if (err)
0646 return V4L2_CONN_UNKNOWN;
0647
0648 return v4l2_fwnode_string_to_connector_type(type_name);
0649 }
0650
0651 int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode,
0652 struct v4l2_fwnode_connector *connector)
0653 {
0654 struct fwnode_handle *connector_node;
0655 enum v4l2_connector_type connector_type;
0656 const char *label;
0657 int err;
0658
0659 if (!fwnode)
0660 return -EINVAL;
0661
0662 memset(connector, 0, sizeof(*connector));
0663
0664 INIT_LIST_HEAD(&connector->links);
0665
0666 connector_node = fwnode_graph_get_port_parent(fwnode);
0667 connector_type = v4l2_fwnode_get_connector_type(connector_node);
0668 if (connector_type == V4L2_CONN_UNKNOWN) {
0669 fwnode_handle_put(connector_node);
0670 connector_node = fwnode_graph_get_remote_port_parent(fwnode);
0671 connector_type = v4l2_fwnode_get_connector_type(connector_node);
0672 }
0673
0674 if (connector_type == V4L2_CONN_UNKNOWN) {
0675 pr_err("Unknown connector type\n");
0676 err = -ENOTCONN;
0677 goto out;
0678 }
0679
0680 connector->type = connector_type;
0681 connector->name = fwnode_get_name(connector_node);
0682 err = fwnode_property_read_string(connector_node, "label", &label);
0683 connector->label = err ? NULL : kstrdup_const(label, GFP_KERNEL);
0684
0685
0686 switch (connector->type) {
0687 case V4L2_CONN_COMPOSITE:
0688 case V4L2_CONN_SVIDEO:
0689 v4l2_fwnode_connector_parse_analog(connector_node, connector);
0690 break;
0691
0692 case V4L2_CONN_UNKNOWN:
0693 break;
0694 }
0695
0696 out:
0697 fwnode_handle_put(connector_node);
0698
0699 return err;
0700 }
0701 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_parse);
0702
0703 int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode,
0704 struct v4l2_fwnode_connector *connector)
0705 {
0706 struct fwnode_handle *connector_ep;
0707 struct v4l2_connector_link *link;
0708 int err;
0709
0710 if (!fwnode || !connector || connector->type == V4L2_CONN_UNKNOWN)
0711 return -EINVAL;
0712
0713 connector_ep = fwnode_graph_get_remote_endpoint(fwnode);
0714 if (!connector_ep)
0715 return -ENOTCONN;
0716
0717 link = kzalloc(sizeof(*link), GFP_KERNEL);
0718 if (!link) {
0719 err = -ENOMEM;
0720 goto err;
0721 }
0722
0723 err = v4l2_fwnode_parse_link(connector_ep, &link->fwnode_link);
0724 if (err)
0725 goto err;
0726
0727 fwnode_handle_put(connector_ep);
0728
0729 list_add(&link->head, &connector->links);
0730 connector->nr_of_links++;
0731
0732 return 0;
0733
0734 err:
0735 kfree(link);
0736 fwnode_handle_put(connector_ep);
0737
0738 return err;
0739 }
0740 EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link);
0741
0742 int v4l2_fwnode_device_parse(struct device *dev,
0743 struct v4l2_fwnode_device_properties *props)
0744 {
0745 struct fwnode_handle *fwnode = dev_fwnode(dev);
0746 u32 val;
0747 int ret;
0748
0749 memset(props, 0, sizeof(*props));
0750
0751 props->orientation = V4L2_FWNODE_PROPERTY_UNSET;
0752 ret = fwnode_property_read_u32(fwnode, "orientation", &val);
0753 if (!ret) {
0754 switch (val) {
0755 case V4L2_FWNODE_ORIENTATION_FRONT:
0756 case V4L2_FWNODE_ORIENTATION_BACK:
0757 case V4L2_FWNODE_ORIENTATION_EXTERNAL:
0758 break;
0759 default:
0760 dev_warn(dev, "Unsupported device orientation: %u\n", val);
0761 return -EINVAL;
0762 }
0763
0764 props->orientation = val;
0765 dev_dbg(dev, "device orientation: %u\n", val);
0766 }
0767
0768 props->rotation = V4L2_FWNODE_PROPERTY_UNSET;
0769 ret = fwnode_property_read_u32(fwnode, "rotation", &val);
0770 if (!ret) {
0771 if (val >= 360) {
0772 dev_warn(dev, "Unsupported device rotation: %u\n", val);
0773 return -EINVAL;
0774 }
0775
0776 props->rotation = val;
0777 dev_dbg(dev, "device rotation: %u\n", val);
0778 }
0779
0780 return 0;
0781 }
0782 EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse);
0783
0784 static int
0785 v4l2_async_nf_fwnode_parse_endpoint(struct device *dev,
0786 struct v4l2_async_notifier *notifier,
0787 struct fwnode_handle *endpoint,
0788 unsigned int asd_struct_size,
0789 parse_endpoint_func parse_endpoint)
0790 {
0791 struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
0792 struct v4l2_async_subdev *asd;
0793 int ret;
0794
0795 asd = kzalloc(asd_struct_size, GFP_KERNEL);
0796 if (!asd)
0797 return -ENOMEM;
0798
0799 asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
0800 asd->match.fwnode =
0801 fwnode_graph_get_remote_port_parent(endpoint);
0802 if (!asd->match.fwnode) {
0803 dev_dbg(dev, "no remote endpoint found\n");
0804 ret = -ENOTCONN;
0805 goto out_err;
0806 }
0807
0808 ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
0809 if (ret) {
0810 dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
0811 ret);
0812 goto out_err;
0813 }
0814
0815 ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
0816 if (ret == -ENOTCONN)
0817 dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
0818 vep.base.id);
0819 else if (ret < 0)
0820 dev_warn(dev,
0821 "driver could not parse port@%u/endpoint@%u (%d)\n",
0822 vep.base.port, vep.base.id, ret);
0823 v4l2_fwnode_endpoint_free(&vep);
0824 if (ret < 0)
0825 goto out_err;
0826
0827 ret = __v4l2_async_nf_add_subdev(notifier, asd);
0828 if (ret < 0) {
0829
0830 if (ret == -EEXIST)
0831 ret = 0;
0832 goto out_err;
0833 }
0834
0835 return 0;
0836
0837 out_err:
0838 fwnode_handle_put(asd->match.fwnode);
0839 kfree(asd);
0840
0841 return ret == -ENOTCONN ? 0 : ret;
0842 }
0843
0844 int
0845 v4l2_async_nf_parse_fwnode_endpoints(struct device *dev,
0846 struct v4l2_async_notifier *notifier,
0847 size_t asd_struct_size,
0848 parse_endpoint_func parse_endpoint)
0849 {
0850 struct fwnode_handle *fwnode;
0851 int ret = 0;
0852
0853 if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
0854 return -EINVAL;
0855
0856 fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) {
0857 struct fwnode_handle *dev_fwnode;
0858 bool is_available;
0859
0860 dev_fwnode = fwnode_graph_get_port_parent(fwnode);
0861 is_available = fwnode_device_is_available(dev_fwnode);
0862 fwnode_handle_put(dev_fwnode);
0863 if (!is_available)
0864 continue;
0865
0866
0867 ret = v4l2_async_nf_fwnode_parse_endpoint(dev, notifier,
0868 fwnode,
0869 asd_struct_size,
0870 parse_endpoint);
0871 if (ret < 0)
0872 break;
0873 }
0874
0875 fwnode_handle_put(fwnode);
0876
0877 return ret;
0878 }
0879 EXPORT_SYMBOL_GPL(v4l2_async_nf_parse_fwnode_endpoints);
0880
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890
0891
0892 static int v4l2_fwnode_reference_parse(struct device *dev,
0893 struct v4l2_async_notifier *notifier,
0894 const char *prop)
0895 {
0896 struct fwnode_reference_args args;
0897 unsigned int index;
0898 int ret;
0899
0900 for (index = 0;
0901 !(ret = fwnode_property_get_reference_args(dev_fwnode(dev), prop,
0902 NULL, 0, index, &args));
0903 index++) {
0904 struct v4l2_async_subdev *asd;
0905
0906 asd = v4l2_async_nf_add_fwnode(notifier, args.fwnode,
0907 struct v4l2_async_subdev);
0908 fwnode_handle_put(args.fwnode);
0909 if (IS_ERR(asd)) {
0910
0911 if (PTR_ERR(asd) == -EEXIST)
0912 continue;
0913
0914 return PTR_ERR(asd);
0915 }
0916 }
0917
0918
0919 if (ret != -ENOENT)
0920 return ret;
0921
0922
0923 return index ? 0 : -ENOENT;
0924 }
0925
0926
0927
0928
0929
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968
0969
0970
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994
0995
0996
0997
0998
0999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 static struct fwnode_handle *
1086 v4l2_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
1099
1100
1101
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
1110
1111
1112 fwnode = fwnode_args.fwnode;
1113 while (nprops--) {
1114 u32 val;
1115
1116
1117 fwnode_for_each_child_node(fwnode, child) {
1118 if (fwnode_property_read_u32(child, *props, &val))
1119 continue;
1120
1121
1122 if (val == *args)
1123 break;
1124 }
1125
1126 fwnode_handle_put(fwnode);
1127
1128
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
1142 struct v4l2_fwnode_int_props {
1143 const char *name;
1144 const char * const *props;
1145 unsigned int nprops;
1146 };
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171 static int
1172 v4l2_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
1191
1192
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
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
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 static int
1246 v4l2_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
1276 int 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
1306 out_unregister:
1307 v4l2_async_nf_unregister(notifier);
1308
1309 out_cleanup:
1310 v4l2_async_nf_cleanup(notifier);
1311 kfree(notifier);
1312
1313 return ret;
1314 }
1315 EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor);
1316
1317 MODULE_LICENSE("GPL");
1318 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
1319 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
1320 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");