media: ipu3-cio2: Parse sensor orientation and rotation
authorFabian Wüthrich <me@fabwu.ch>
Mon, 12 Jul 2021 09:03:26 +0000 (11:03 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Fri, 8 Oct 2021 11:17:37 +0000 (13:17 +0200)
The sensor orientation is read from the _PLC ACPI buffer and converted to a v4l2
format.

The sensor rotation is read from the SSDB ACPI buffer and converted into
degrees.

Signed-off-by: Fabian Wüthrich <me@fabwu.ch>
Reviewed-by: Daniel Scally <djrscally@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/pci/intel/ipu3/cio2-bridge.c
drivers/media/pci/intel/ipu3/cio2-bridge.h

index 30d29b9..67c467d 100644 (file)
@@ -29,6 +29,7 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = {
 static const struct cio2_property_names prop_names = {
        .clock_frequency = "clock-frequency",
        .rotation = "rotation",
+       .orientation = "orientation",
        .bus_type = "bus-type",
        .data_lanes = "data-lanes",
        .remote_endpoint = "remote-endpoint",
@@ -72,11 +73,51 @@ out_free_buff:
        return ret;
 }
 
+static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor)
+{
+       switch (sensor->ssdb.degree) {
+       case CIO2_SENSOR_ROTATION_NORMAL:
+               return 0;
+       case CIO2_SENSOR_ROTATION_INVERTED:
+               return 180;
+       default:
+               dev_warn(&sensor->adev->dev,
+                        "Unknown rotation %d. Assume 0 degree rotation\n",
+                        sensor->ssdb.degree);
+               return 0;
+       }
+}
+
+static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_sensor *sensor)
+{
+       switch (sensor->pld->panel) {
+       case ACPI_PLD_PANEL_FRONT:
+               return V4L2_FWNODE_ORIENTATION_FRONT;
+       case ACPI_PLD_PANEL_BACK:
+               return V4L2_FWNODE_ORIENTATION_BACK;
+       case ACPI_PLD_PANEL_TOP:
+       case ACPI_PLD_PANEL_LEFT:
+       case ACPI_PLD_PANEL_RIGHT:
+       case ACPI_PLD_PANEL_UNKNOWN:
+               return V4L2_FWNODE_ORIENTATION_EXTERNAL;
+       default:
+               dev_warn(&sensor->adev->dev, "Unknown _PLD panel value %d\n",
+                        sensor->pld->panel);
+               return V4L2_FWNODE_ORIENTATION_EXTERNAL;
+       }
+}
+
 static void cio2_bridge_create_fwnode_properties(
        struct cio2_sensor *sensor,
        struct cio2_bridge *bridge,
        const struct cio2_sensor_config *cfg)
 {
+       u32 rotation;
+       enum v4l2_fwnode_orientation orientation;
+
+       rotation = cio2_bridge_parse_rotation(sensor);
+       orientation = cio2_bridge_parse_orientation(sensor);
+
        sensor->prop_names = prop_names;
 
        sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]);
@@ -85,9 +126,12 @@ static void cio2_bridge_create_fwnode_properties(
        sensor->dev_properties[0] = PROPERTY_ENTRY_U32(
                                        sensor->prop_names.clock_frequency,
                                        sensor->ssdb.mclkspeed);
-       sensor->dev_properties[1] = PROPERTY_ENTRY_U8(
+       sensor->dev_properties[1] = PROPERTY_ENTRY_U32(
                                        sensor->prop_names.rotation,
-                                       sensor->ssdb.degree);
+                                       rotation);
+       sensor->dev_properties[2] = PROPERTY_ENTRY_U32(
+                                       sensor->prop_names.orientation,
+                                       orientation);
 
        sensor->ep_properties[0] = PROPERTY_ENTRY_U32(
                                        sensor->prop_names.bus_type,
@@ -159,6 +203,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
        for (i = 0; i < bridge->n_sensors; i++) {
                sensor = &bridge->sensors[i];
                software_node_unregister_nodes(sensor->swnodes);
+               ACPI_FREE(sensor->pld);
                acpi_dev_put(sensor->adev);
        }
 }
@@ -170,6 +215,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
        struct fwnode_handle *fwnode;
        struct cio2_sensor *sensor;
        struct acpi_device *adev;
+       acpi_status status;
        int ret;
 
        for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
@@ -191,11 +237,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
                if (ret)
                        goto err_put_adev;
 
+               status = acpi_get_physical_device_location(adev->handle, &sensor->pld);
+               if (ACPI_FAILURE(status))
+                       goto err_put_adev;
+
                if (sensor->ssdb.lanes > CIO2_MAX_LANES) {
                        dev_err(&adev->dev,
                                "Number of lanes in SSDB is invalid\n");
                        ret = -EINVAL;
-                       goto err_put_adev;
+                       goto err_free_pld;
                }
 
                cio2_bridge_create_fwnode_properties(sensor, bridge, cfg);
@@ -203,7 +253,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
 
                ret = software_node_register_nodes(sensor->swnodes);
                if (ret)
-                       goto err_put_adev;
+                       goto err_free_pld;
 
                fwnode = software_node_fwnode(&sensor->swnodes[
                                                      SWNODE_SENSOR_HID]);
@@ -225,6 +275,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
 
 err_free_swnodes:
        software_node_unregister_nodes(sensor->swnodes);
+err_free_pld:
+       ACPI_FREE(sensor->pld);
 err_put_adev:
        acpi_dev_put(adev);
        return ret;
index dd0ffca..202c7d4 100644 (file)
 #define CIO2_MAX_LANES                         4
 #define MAX_NUM_LINK_FREQS                     3
 
+/* Values are educated guesses as we don't have a spec */
+#define CIO2_SENSOR_ROTATION_NORMAL            0
+#define CIO2_SENSOR_ROTATION_INVERTED          1
+
 #define CIO2_SENSOR_CONFIG(_HID, _NR, ...)     \
        (const struct cio2_sensor_config) {     \
                .hid = _HID,                    \
@@ -80,6 +84,7 @@ struct cio2_sensor_ssdb {
 struct cio2_property_names {
        char clock_frequency[16];
        char rotation[9];
+       char orientation[12];
        char bus_type[9];
        char data_lanes[11];
        char remote_endpoint[16];
@@ -106,9 +111,11 @@ struct cio2_sensor {
        struct cio2_node_names node_names;
 
        struct cio2_sensor_ssdb ssdb;
+       struct acpi_pld_info *pld;
+
        struct cio2_property_names prop_names;
        struct property_entry ep_properties[5];
-       struct property_entry dev_properties[3];
+       struct property_entry dev_properties[4];
        struct property_entry cio2_properties[3];
        struct software_node_ref_args local_ref[1];
        struct software_node_ref_args remote_ref[1];