Lines Matching +full:orientation +full:- +full:switch
1 // SPDX-License-Identifier: GPL-2.0
14 #include <media/ipu-bridge.h>
15 #include <media/v4l2-fwnode.h>
18 * 92335fcf-3203-4472-af93-7b4453ac29da
36 * plus the number of link-frequencies expected by their drivers, along with
66 .clock_frequency = "clock-frequency",
68 .orientation = "orientation",
69 .bus_type = "bus-type",
70 .data_lanes = "data-lanes",
71 .remote_endpoint = "remote-endpoint",
72 .link_frequencies = "link-frequencies",
107 for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1) in ipu_bridge_get_ivsc_acpi_dev()
110 if (consumer->handle == handle) { in ipu_bridge_get_ivsc_acpi_dev()
140 snprintf(name, sizeof(name), "%s-%pUl", dev_name(dev), &uuid); in ipu_bridge_get_ivsc_csi_dev()
163 dev_err(&adev->dev, "Failed to find MEI CSI dev\n"); in ipu_bridge_check_ivsc_dev()
164 return -ENODEV; in ipu_bridge_check_ivsc_dev()
167 sensor->csi_dev = csi_dev; in ipu_bridge_check_ivsc_dev()
168 sensor->ivsc_adev = adev; in ipu_bridge_check_ivsc_dev()
182 status = acpi_evaluate_object(adev->handle, id, NULL, &buffer); in ipu_bridge_read_acpi_buffer()
184 return -ENODEV; in ipu_bridge_read_acpi_buffer()
188 dev_err(&adev->dev, "Couldn't locate ACPI buffer\n"); in ipu_bridge_read_acpi_buffer()
189 return -ENODEV; in ipu_bridge_read_acpi_buffer()
192 if (obj->type != ACPI_TYPE_BUFFER) { in ipu_bridge_read_acpi_buffer()
193 dev_err(&adev->dev, "Not an ACPI buffer\n"); in ipu_bridge_read_acpi_buffer()
194 ret = -ENODEV; in ipu_bridge_read_acpi_buffer()
198 if (obj->buffer.length > size) { in ipu_bridge_read_acpi_buffer()
199 dev_err(&adev->dev, "Given buffer is too small\n"); in ipu_bridge_read_acpi_buffer()
200 ret = -EINVAL; in ipu_bridge_read_acpi_buffer()
204 memcpy(data, obj->buffer.pointer, obj->buffer.length); in ipu_bridge_read_acpi_buffer()
214 switch (ssdb->degree) { in ipu_bridge_parse_rotation()
220 dev_warn(&adev->dev, in ipu_bridge_parse_rotation()
222 ssdb->degree); in ipu_bridge_parse_rotation()
229 enum v4l2_fwnode_orientation orientation; in ipu_bridge_parse_orientation() local
233 status = acpi_get_physical_device_location(adev->handle, &pld); in ipu_bridge_parse_orientation()
235 dev_warn(&adev->dev, "_PLD call failed, using default orientation\n"); in ipu_bridge_parse_orientation()
239 switch (pld->panel) { in ipu_bridge_parse_orientation()
241 orientation = V4L2_FWNODE_ORIENTATION_FRONT; in ipu_bridge_parse_orientation()
244 orientation = V4L2_FWNODE_ORIENTATION_BACK; in ipu_bridge_parse_orientation()
250 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL; in ipu_bridge_parse_orientation()
253 dev_warn(&adev->dev, "Unknown _PLD panel val %d\n", pld->panel); in ipu_bridge_parse_orientation()
254 orientation = V4L2_FWNODE_ORIENTATION_EXTERNAL; in ipu_bridge_parse_orientation()
259 return orientation; in ipu_bridge_parse_orientation()
272 dev_warn(&adev->dev, "Unknown VCM type %d\n", ssdb.vcmtype); in ipu_bridge_parse_ssdb()
277 dev_err(&adev->dev, "Number of lanes in SSDB is invalid\n"); in ipu_bridge_parse_ssdb()
278 return -EINVAL; in ipu_bridge_parse_ssdb()
281 sensor->link = ssdb.link; in ipu_bridge_parse_ssdb()
282 sensor->lanes = ssdb.lanes; in ipu_bridge_parse_ssdb()
283 sensor->mclkspeed = ssdb.mclkspeed; in ipu_bridge_parse_ssdb()
284 sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb); in ipu_bridge_parse_ssdb()
285 sensor->orientation = ipu_bridge_parse_orientation(adev); in ipu_bridge_parse_ssdb()
288 sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1]; in ipu_bridge_parse_ssdb()
299 struct ipu_property_names *names = &sensor->prop_names; in ipu_bridge_create_fwnode_properties()
300 struct software_node *nodes = sensor->swnodes; in ipu_bridge_create_fwnode_properties()
302 sensor->prop_names = prop_names; in ipu_bridge_create_fwnode_properties()
304 if (sensor->csi_dev) { in ipu_bridge_create_fwnode_properties()
305 sensor->local_ref[0] = in ipu_bridge_create_fwnode_properties()
307 sensor->remote_ref[0] = in ipu_bridge_create_fwnode_properties()
309 sensor->ivsc_sensor_ref[0] = in ipu_bridge_create_fwnode_properties()
311 sensor->ivsc_ipu_ref[0] = in ipu_bridge_create_fwnode_properties()
314 sensor->ivsc_sensor_ep_properties[0] = in ipu_bridge_create_fwnode_properties()
315 PROPERTY_ENTRY_U32(names->bus_type, in ipu_bridge_create_fwnode_properties()
317 sensor->ivsc_sensor_ep_properties[1] = in ipu_bridge_create_fwnode_properties()
318 PROPERTY_ENTRY_U32_ARRAY_LEN(names->data_lanes, in ipu_bridge_create_fwnode_properties()
319 bridge->data_lanes, in ipu_bridge_create_fwnode_properties()
320 sensor->lanes); in ipu_bridge_create_fwnode_properties()
321 sensor->ivsc_sensor_ep_properties[2] = in ipu_bridge_create_fwnode_properties()
322 PROPERTY_ENTRY_REF_ARRAY(names->remote_endpoint, in ipu_bridge_create_fwnode_properties()
323 sensor->ivsc_sensor_ref); in ipu_bridge_create_fwnode_properties()
325 sensor->ivsc_ipu_ep_properties[0] = in ipu_bridge_create_fwnode_properties()
326 PROPERTY_ENTRY_U32(names->bus_type, in ipu_bridge_create_fwnode_properties()
328 sensor->ivsc_ipu_ep_properties[1] = in ipu_bridge_create_fwnode_properties()
329 PROPERTY_ENTRY_U32_ARRAY_LEN(names->data_lanes, in ipu_bridge_create_fwnode_properties()
330 bridge->data_lanes, in ipu_bridge_create_fwnode_properties()
331 sensor->lanes); in ipu_bridge_create_fwnode_properties()
332 sensor->ivsc_ipu_ep_properties[2] = in ipu_bridge_create_fwnode_properties()
333 PROPERTY_ENTRY_REF_ARRAY(names->remote_endpoint, in ipu_bridge_create_fwnode_properties()
334 sensor->ivsc_ipu_ref); in ipu_bridge_create_fwnode_properties()
336 sensor->local_ref[0] = in ipu_bridge_create_fwnode_properties()
338 sensor->remote_ref[0] = in ipu_bridge_create_fwnode_properties()
342 sensor->dev_properties[0] = PROPERTY_ENTRY_U32( in ipu_bridge_create_fwnode_properties()
343 sensor->prop_names.clock_frequency, in ipu_bridge_create_fwnode_properties()
344 sensor->mclkspeed); in ipu_bridge_create_fwnode_properties()
345 sensor->dev_properties[1] = PROPERTY_ENTRY_U32( in ipu_bridge_create_fwnode_properties()
346 sensor->prop_names.rotation, in ipu_bridge_create_fwnode_properties()
347 sensor->rotation); in ipu_bridge_create_fwnode_properties()
348 sensor->dev_properties[2] = PROPERTY_ENTRY_U32( in ipu_bridge_create_fwnode_properties()
349 sensor->prop_names.orientation, in ipu_bridge_create_fwnode_properties()
350 sensor->orientation); in ipu_bridge_create_fwnode_properties()
351 if (sensor->vcm_type) { in ipu_bridge_create_fwnode_properties()
352 sensor->vcm_ref[0] = in ipu_bridge_create_fwnode_properties()
353 SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_VCM]); in ipu_bridge_create_fwnode_properties()
354 sensor->dev_properties[3] = in ipu_bridge_create_fwnode_properties()
355 PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref); in ipu_bridge_create_fwnode_properties()
358 sensor->ep_properties[0] = PROPERTY_ENTRY_U32( in ipu_bridge_create_fwnode_properties()
359 sensor->prop_names.bus_type, in ipu_bridge_create_fwnode_properties()
361 sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN( in ipu_bridge_create_fwnode_properties()
362 sensor->prop_names.data_lanes, in ipu_bridge_create_fwnode_properties()
363 bridge->data_lanes, sensor->lanes); in ipu_bridge_create_fwnode_properties()
364 sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY( in ipu_bridge_create_fwnode_properties()
365 sensor->prop_names.remote_endpoint, in ipu_bridge_create_fwnode_properties()
366 sensor->local_ref); in ipu_bridge_create_fwnode_properties()
368 if (cfg->nr_link_freqs > 0) in ipu_bridge_create_fwnode_properties()
369 sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN( in ipu_bridge_create_fwnode_properties()
370 sensor->prop_names.link_frequencies, in ipu_bridge_create_fwnode_properties()
371 cfg->link_freqs, in ipu_bridge_create_fwnode_properties()
372 cfg->nr_link_freqs); in ipu_bridge_create_fwnode_properties()
374 sensor->ipu_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN( in ipu_bridge_create_fwnode_properties()
375 sensor->prop_names.data_lanes, in ipu_bridge_create_fwnode_properties()
376 bridge->data_lanes, sensor->lanes); in ipu_bridge_create_fwnode_properties()
377 sensor->ipu_properties[1] = PROPERTY_ENTRY_REF_ARRAY( in ipu_bridge_create_fwnode_properties()
378 sensor->prop_names.remote_endpoint, in ipu_bridge_create_fwnode_properties()
379 sensor->remote_ref); in ipu_bridge_create_fwnode_properties()
384 snprintf(sensor->node_names.remote_port, in ipu_bridge_init_swnode_names()
385 sizeof(sensor->node_names.remote_port), in ipu_bridge_init_swnode_names()
386 SWNODE_GRAPH_PORT_NAME_FMT, sensor->link); in ipu_bridge_init_swnode_names()
387 snprintf(sensor->node_names.port, in ipu_bridge_init_swnode_names()
388 sizeof(sensor->node_names.port), in ipu_bridge_init_swnode_names()
390 snprintf(sensor->node_names.endpoint, in ipu_bridge_init_swnode_names()
391 sizeof(sensor->node_names.endpoint), in ipu_bridge_init_swnode_names()
393 if (sensor->vcm_type) { in ipu_bridge_init_swnode_names()
395 snprintf(sensor->node_names.vcm, sizeof(sensor->node_names.vcm), in ipu_bridge_init_swnode_names()
396 "%s-%u", sensor->vcm_type, sensor->link); in ipu_bridge_init_swnode_names()
399 if (sensor->csi_dev) { in ipu_bridge_init_swnode_names()
400 snprintf(sensor->node_names.ivsc_sensor_port, in ipu_bridge_init_swnode_names()
401 sizeof(sensor->node_names.ivsc_sensor_port), in ipu_bridge_init_swnode_names()
403 snprintf(sensor->node_names.ivsc_ipu_port, in ipu_bridge_init_swnode_names()
404 sizeof(sensor->node_names.ivsc_ipu_port), in ipu_bridge_init_swnode_names()
411 struct software_node *nodes = sensor->swnodes; in ipu_bridge_init_swnode_group()
413 sensor->group[SWNODE_SENSOR_HID] = &nodes[SWNODE_SENSOR_HID]; in ipu_bridge_init_swnode_group()
414 sensor->group[SWNODE_SENSOR_PORT] = &nodes[SWNODE_SENSOR_PORT]; in ipu_bridge_init_swnode_group()
415 sensor->group[SWNODE_SENSOR_ENDPOINT] = &nodes[SWNODE_SENSOR_ENDPOINT]; in ipu_bridge_init_swnode_group()
416 sensor->group[SWNODE_IPU_PORT] = &nodes[SWNODE_IPU_PORT]; in ipu_bridge_init_swnode_group()
417 sensor->group[SWNODE_IPU_ENDPOINT] = &nodes[SWNODE_IPU_ENDPOINT]; in ipu_bridge_init_swnode_group()
418 if (sensor->vcm_type) in ipu_bridge_init_swnode_group()
419 sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; in ipu_bridge_init_swnode_group()
421 if (sensor->csi_dev) { in ipu_bridge_init_swnode_group()
422 sensor->group[SWNODE_IVSC_HID] = in ipu_bridge_init_swnode_group()
424 sensor->group[SWNODE_IVSC_SENSOR_PORT] = in ipu_bridge_init_swnode_group()
426 sensor->group[SWNODE_IVSC_SENSOR_ENDPOINT] = in ipu_bridge_init_swnode_group()
428 sensor->group[SWNODE_IVSC_IPU_PORT] = in ipu_bridge_init_swnode_group()
430 sensor->group[SWNODE_IVSC_IPU_ENDPOINT] = in ipu_bridge_init_swnode_group()
433 if (sensor->vcm_type) in ipu_bridge_init_swnode_group()
434 sensor->group[SWNODE_VCM] = &nodes[SWNODE_VCM]; in ipu_bridge_init_swnode_group()
436 if (sensor->vcm_type) in ipu_bridge_init_swnode_group()
437 sensor->group[SWNODE_IVSC_HID] = &nodes[SWNODE_VCM]; in ipu_bridge_init_swnode_group()
444 struct ipu_node_names *names = &sensor->node_names; in ipu_bridge_create_connection_swnodes()
445 struct software_node *nodes = sensor->swnodes; in ipu_bridge_create_connection_swnodes()
449 nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name, in ipu_bridge_create_connection_swnodes()
450 sensor->dev_properties); in ipu_bridge_create_connection_swnodes()
451 nodes[SWNODE_SENSOR_PORT] = NODE_PORT(sensor->node_names.port, in ipu_bridge_create_connection_swnodes()
454 sensor->node_names.endpoint, in ipu_bridge_create_connection_swnodes()
456 sensor->ep_properties); in ipu_bridge_create_connection_swnodes()
457 nodes[SWNODE_IPU_PORT] = NODE_PORT(sensor->node_names.remote_port, in ipu_bridge_create_connection_swnodes()
458 &bridge->ipu_hid_node); in ipu_bridge_create_connection_swnodes()
460 sensor->node_names.endpoint, in ipu_bridge_create_connection_swnodes()
462 sensor->ipu_properties); in ipu_bridge_create_connection_swnodes()
464 if (sensor->csi_dev) { in ipu_bridge_create_connection_swnodes()
465 snprintf(sensor->ivsc_name, sizeof(sensor->ivsc_name), "%s-%u", in ipu_bridge_create_connection_swnodes()
466 acpi_device_hid(sensor->ivsc_adev), sensor->link); in ipu_bridge_create_connection_swnodes()
468 nodes[SWNODE_IVSC_HID] = NODE_SENSOR(sensor->ivsc_name, in ipu_bridge_create_connection_swnodes()
469 sensor->ivsc_properties); in ipu_bridge_create_connection_swnodes()
471 NODE_PORT(names->ivsc_sensor_port, in ipu_bridge_create_connection_swnodes()
474 NODE_ENDPOINT(names->endpoint, in ipu_bridge_create_connection_swnodes()
476 sensor->ivsc_sensor_ep_properties); in ipu_bridge_create_connection_swnodes()
478 NODE_PORT(names->ivsc_ipu_port, in ipu_bridge_create_connection_swnodes()
481 NODE_ENDPOINT(names->endpoint, in ipu_bridge_create_connection_swnodes()
483 sensor->ivsc_ipu_ep_properties); in ipu_bridge_create_connection_swnodes()
486 nodes[SWNODE_VCM] = NODE_VCM(sensor->node_names.vcm); in ipu_bridge_create_connection_swnodes()
493 * a deadlock on taking list_lock from v4l2-async twice.
507 struct acpi_device *adev = ACPI_COMPANION(data->sensor); in ipu_bridge_instantiate_vcm_work()
514 * make sure the sensor is powered-up during probe. in ipu_bridge_instantiate_vcm_work()
516 ret = pm_runtime_get_sync(data->sensor); in ipu_bridge_instantiate_vcm_work()
518 dev_err(data->sensor, "Error %d runtime-resuming sensor, cannot instantiate VCM\n", in ipu_bridge_instantiate_vcm_work()
525 * even after a rmmod, just like the software-nodes. in ipu_bridge_instantiate_vcm_work()
528 1, &data->board_info); in ipu_bridge_instantiate_vcm_work()
530 dev_err(data->sensor, "Error instantiating VCM client: %ld\n", in ipu_bridge_instantiate_vcm_work()
535 device_link_add(&vcm_client->dev, data->sensor, DL_FLAG_PM_RUNTIME); in ipu_bridge_instantiate_vcm_work()
537 dev_info(data->sensor, "Instantiated %s VCM\n", data->board_info.type); in ipu_bridge_instantiate_vcm_work()
538 put_fwnode = false; /* Ownership has passed to the i2c-client */ in ipu_bridge_instantiate_vcm_work()
541 pm_runtime_put(data->sensor); in ipu_bridge_instantiate_vcm_work()
542 put_device(data->sensor); in ipu_bridge_instantiate_vcm_work()
544 fwnode_handle_put(data->board_info.fwnode); in ipu_bridge_instantiate_vcm_work()
560 vcm_fwnode = fwnode_find_reference(dev_fwnode(sensor), "lens-focus", 0); in ipu_bridge_instantiate_vcm()
568 put_device(&vcm_client->dev); in ipu_bridge_instantiate_vcm()
575 return -ENOMEM; in ipu_bridge_instantiate_vcm()
578 INIT_WORK(&data->work, ipu_bridge_instantiate_vcm_work); in ipu_bridge_instantiate_vcm()
579 data->sensor = get_device(sensor); in ipu_bridge_instantiate_vcm()
580 snprintf(data->name, sizeof(data->name), "%s-VCM", in ipu_bridge_instantiate_vcm()
582 data->board_info.dev_name = data->name; in ipu_bridge_instantiate_vcm()
583 data->board_info.fwnode = vcm_fwnode; in ipu_bridge_instantiate_vcm()
584 snprintf(data->board_info.type, sizeof(data->board_info.type), in ipu_bridge_instantiate_vcm()
586 /* Strip "-<link>" postfix */ in ipu_bridge_instantiate_vcm()
587 sep = strchrnul(data->board_info.type, '-'); in ipu_bridge_instantiate_vcm()
590 queue_work(system_long_wq, &data->work); in ipu_bridge_instantiate_vcm()
600 if (!sensor->csi_dev) in ipu_bridge_instantiate_ivsc()
603 fwnode = software_node_fwnode(&sensor->swnodes[SWNODE_IVSC_HID]); in ipu_bridge_instantiate_ivsc()
605 return -ENODEV; in ipu_bridge_instantiate_ivsc()
607 set_secondary_fwnode(sensor->csi_dev, fwnode); in ipu_bridge_instantiate_ivsc()
617 for (i = 0; i < bridge->n_sensors; i++) { in ipu_bridge_unregister_sensors()
618 sensor = &bridge->sensors[i]; in ipu_bridge_unregister_sensors()
619 software_node_unregister_node_group(sensor->group); in ipu_bridge_unregister_sensors()
620 acpi_dev_put(sensor->adev); in ipu_bridge_unregister_sensors()
621 put_device(sensor->csi_dev); in ipu_bridge_unregister_sensors()
622 acpi_dev_put(sensor->ivsc_adev); in ipu_bridge_unregister_sensors()
634 for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) { in ipu_bridge_connect_sensor()
635 if (!adev->status.enabled) in ipu_bridge_connect_sensor()
638 if (bridge->n_sensors >= IPU_MAX_PORTS) { in ipu_bridge_connect_sensor()
640 dev_err(bridge->dev, "Exceeded available IPU ports\n"); in ipu_bridge_connect_sensor()
641 return -EINVAL; in ipu_bridge_connect_sensor()
644 sensor = &bridge->sensors[bridge->n_sensors]; in ipu_bridge_connect_sensor()
646 ret = bridge->parse_sensor_fwnode(adev, sensor); in ipu_bridge_connect_sensor()
650 snprintf(sensor->name, sizeof(sensor->name), "%s-%u", in ipu_bridge_connect_sensor()
651 cfg->hid, sensor->link); in ipu_bridge_connect_sensor()
660 ret = software_node_register_node_group(sensor->group); in ipu_bridge_connect_sensor()
664 fwnode = software_node_fwnode(&sensor->swnodes[ in ipu_bridge_connect_sensor()
667 ret = -ENODEV; in ipu_bridge_connect_sensor()
671 sensor->adev = acpi_dev_get(adev); in ipu_bridge_connect_sensor()
674 primary->secondary = fwnode; in ipu_bridge_connect_sensor()
680 dev_info(bridge->dev, "Found supported sensor %s\n", in ipu_bridge_connect_sensor()
683 bridge->n_sensors++; in ipu_bridge_connect_sensor()
689 software_node_unregister_node_group(sensor->group); in ipu_bridge_connect_sensor()
691 put_device(sensor->csi_dev); in ipu_bridge_connect_sensor()
692 acpi_dev_put(sensor->ivsc_adev); in ipu_bridge_connect_sensor()
730 for_each_acpi_dev_match(sensor_adev, cfg->hid, NULL, -1) { in ipu_bridge_ivsc_is_ready()
731 if (!sensor_adev->status.enabled) in ipu_bridge_ivsc_is_ready()
759 return -EPROBE_DEFER; in ipu_bridge_init()
763 return -ENOMEM; in ipu_bridge_init()
765 strscpy(bridge->ipu_node_name, IPU_HID, in ipu_bridge_init()
766 sizeof(bridge->ipu_node_name)); in ipu_bridge_init()
767 bridge->ipu_hid_node.name = bridge->ipu_node_name; in ipu_bridge_init()
768 bridge->dev = dev; in ipu_bridge_init()
769 bridge->parse_sensor_fwnode = parse_sensor_fwnode; in ipu_bridge_init()
771 ret = software_node_register(&bridge->ipu_hid_node); in ipu_bridge_init()
785 bridge->data_lanes[i] = i + 1; in ipu_bridge_init()
788 if (ret || bridge->n_sensors == 0) in ipu_bridge_init()
791 dev_info(dev, "Connected %d cameras\n", bridge->n_sensors); in ipu_bridge_init()
793 fwnode = software_node_fwnode(&bridge->ipu_hid_node); in ipu_bridge_init()
796 ret = -ENODEV; in ipu_bridge_init()
807 software_node_unregister(&bridge->ipu_hid_node); in ipu_bridge_init()