From 392c11c81f3a6525e7c6c2e1af100a8e650aa146 Mon Sep 17 00:00:00 2001 From: jimlai Date: Tue, 12 Sep 2023 13:50:44 +0800 Subject: [PATCH] media: i2c: rotate 180 for some OV02C10 modules Change Description: OV02C10 with module names CJFME32 and 2BG203N3 are rotated 180 degrees from others, so we will need to manaully do a rotation within sensor driver Test Platform: MTL-P Signed-off-by: Jim Lai --- drivers/media/i2c/ov02c10.c | 104 ++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/media/i2c/ov02c10.c b/drivers/media/i2c/ov02c10.c index e807a7098adc..aa6f48bcb2fd 100644 --- a/drivers/media/i2c/ov02c10.c +++ b/drivers/media/i2c/ov02c10.c @@ -52,6 +52,12 @@ #define OV02C10_DGTL_GAIN_STEP 1 #define OV02C10_DGTL_GAIN_DEFAULT 0x0400 +/* Rotate */ +#define OV02C10_ROTATE_CONTROL 0x3820 +#define OV02C10_ISP_X_WIN_CONTROL 0x3811 +#define OV02C10_ISP_Y_WIN_CONTROL 0x3813 +#define OV02C10_CONFIG_ROTATE 0x18 + /* Test Pattern Control */ #define OV02C10_REG_TEST_PATTERN 0x4503 #define OV02C10_TEST_PATTERN_ENABLE BIT(7) @@ -61,6 +67,14 @@ enum { OV02C10_LINK_FREQ_400MHZ_INDEX, }; +enum module_names { + MODULE_EMPTY = 0, + MODULE_2BG203N3, + MODULE_CJFME32, + /* etc. */ + MODULE_MAX +}; + struct ov02c10_reg { u16 address; u8 val; @@ -130,6 +144,15 @@ struct mipi_camera_link_ssdb { u8 reserved2[13]; } __packed; +/* + * 822ace8f-2814-4174-a56b-5f029fe079ee + * This _DSM GUID returns a string from the sensor device, which acts as a + * module identifier. + */ +static const guid_t cio2_sensor_module_guid = + GUID_INIT(0x822ace8f, 0x2814, 0x4174, + 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee); + static const struct ov02c10_reg mipi_data_rate_960mbps[] = { }; @@ -598,6 +621,12 @@ static const char * const ov02c10_test_pattern_menu[] = { "Color Bar type 4", }; +static const char * const ov02c10_module_names[] = { + [MODULE_EMPTY] = "", + [MODULE_CJFME32] = "CJFME32", + [MODULE_2BG203N3] = "2BG203N3", +}; + static const s64 link_freq_menu_items[] = { OV02C10_LINK_FREQ_400MHZ, }; @@ -667,6 +696,9 @@ struct ov02c10 { /* Streaming on/off */ bool streaming; + + /* Module name index */ + u8 module_name_index; }; static inline struct ov02c10 *to_ov02c10(struct v4l2_subdev *subdev) @@ -936,6 +968,51 @@ static int ov02c10_start_streaming(struct ov02c10 *ov02c10) if (ret) return ret; + if ((ov02c10->module_name_index == MODULE_CJFME32) || + (ov02c10->module_name_index == MODULE_2BG203N3)) { + u32 rotateReg, shiftXReg, shiftYReg; + + ret = ov02c10_read_reg(ov02c10, OV02C10_ROTATE_CONTROL, 1, + &rotateReg); + if (ret) + dev_err(&client->dev, "OV02C10_ROTATE_CONTROL read Fail = 0x%x", + rotateReg); + + ret = ov02c10_read_reg(ov02c10, OV02C10_ISP_X_WIN_CONTROL, 1, + &shiftXReg); + if (ret) + dev_err(&client->dev, "OV02C10_ISP_X_WIN_CONTROL read Fail = 0x%x", + shiftXReg); + + ret = ov02c10_read_reg(ov02c10, OV02C10_ISP_Y_WIN_CONTROL, 1, + &shiftYReg); + if (ret) + dev_err(&client->dev, "OV02C10_ISP_Y_WIN_CONTROL read Fail = 0x%x", + shiftYReg); + + rotateReg ^= OV02C10_CONFIG_ROTATE; + shiftXReg = shiftXReg - 1; + shiftYReg = shiftYReg - 1; + + ret = ov02c10_write_reg(ov02c10, OV02C10_ROTATE_CONTROL, 1, + rotateReg); + if (ret) + dev_err(&client->dev, "OV02C10_ROTATE_CONTROL write Fail = 0x%x", + rotateReg); + + ret = ov02c10_write_reg(ov02c10, OV02C10_ISP_X_WIN_CONTROL, 1, + shiftXReg); + if (ret) + dev_err(&client->dev, "OV02C10_ISP_X_WIN_CONTROL write Fail = 0x%x", + shiftXReg); + + ret = ov02c10_write_reg(ov02c10, OV02C10_ISP_Y_WIN_CONTROL, 1, + shiftYReg); + if (ret) + dev_err(&client->dev, "OV02C10_ISP_Y_WIN_CONTROL write Fail = 0x%x", + shiftYReg); + } + ret = ov02c10_write_reg(ov02c10, OV02C10_REG_MODE_SELECT, 1, OV02C10_MODE_STREAMING); if (ret) @@ -1309,6 +1386,31 @@ static void ov02c10_remove(struct i2c_client *client) #endif } +static int ov02c10_read_module_name(struct ov02c10 *ov02c10) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); + struct device *dev = &client->dev; + int i = 0; + union acpi_object *obj; + + obj = acpi_evaluate_dsm_typed(ACPI_COMPANION(dev)->handle, + &cio2_sensor_module_guid, 0x00, + 0x01, NULL, ACPI_TYPE_STRING); + + ov02c10->module_name_index = 0; + if (obj && obj->string.type == ACPI_TYPE_STRING) { + for (i = 1; i < ARRAY_SIZE(ov02c10_module_names); i++) { + if (!strcmp(ov02c10_module_names[i], obj->string.pointer)) { + ov02c10->module_name_index = i; + break; + } + } + } + ACPI_FREE(obj); + + return 0; +} + static int ov02c10_probe(struct i2c_client *client) { struct ov02c10 *ov02c10; @@ -1319,6 +1421,8 @@ static int ov02c10_probe(struct i2c_client *client) return -ENOMEM; v4l2_i2c_subdev_init(&ov02c10->sd, client, &ov02c10_subdev_ops); + ov02c10_read_module_name(ov02c10); + #if IS_ENABLED(CONFIG_INTEL_VSC) ov02c10->mipi_lanes = OV02C10_DATA_LANES; ov02c10->conf.lane_num = ov02c10->mipi_lanes;