* [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements
@ 2024-09-02 21:54 André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 01/13] media: i2c: imx214: Use subdev active state André Apitzsch via B4 Relay
` (12 more replies)
0 siblings, 13 replies; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
This patch series is a collection of miscellaneous cleanups and
improvements to the imx214 driver.
The series converts the driver to the CCI helpers and adds controls
needed to make the driver work with libcamera.
The changes are inspired by the imx219 driver.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
André Apitzsch (13):
media: i2c: imx214: Use subdev active state
media: i2c: imx214: Remove unneeded goto
media: i2c: imx214: Simplify with dev_err_probe()
media: i2c: imx214: Convert to CCI register access helpers
media: i2c: imx214: Replace register addresses with macros
media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays
media: i2c: imx214: Use number of lanes from device tree
media: i2c: imx214: Add vblank and hblank controls
media: i2c: imx214: Extract format and crop settings
media: i2c: imx214: Implement vflip/hflip controls
media: i2c: imx214: Add analogue/digital gain control
media: i2c: imx214: Verify chip ID
media: i2c: imx214: Add test pattern control
drivers/media/i2c/Kconfig | 1 +
drivers/media/i2c/imx214.c | 1313 +++++++++++++++++++++++++++-----------------
2 files changed, 803 insertions(+), 511 deletions(-)
---
base-commit: b891f84dd1f93ef4a716f10a70da80db443db431
change-id: 20240818-imx214-8324784c7bee
Best regards,
--
André Apitzsch <git@apitzsch.eu>
^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH 01/13] media: i2c: imx214: Use subdev active state
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 02/13] media: i2c: imx214: Remove unneeded goto André Apitzsch via B4 Relay
` (11 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Port the imx214 sensor driver to use the subdev active state.
Move all the format configuration to the subdevice state and simplify
the format handling, locking and initialization.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 129 +++++++++++++--------------------------------
1 file changed, 38 insertions(+), 91 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 4962cfe7c83d..58f3c3f67e0d 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -71,12 +71,6 @@ struct imx214 {
struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
struct gpio_desc *enable_gpio;
-
- /*
- * Serialize control access, get/set format, get selection
- * and start streaming.
- */
- struct mutex mutex;
};
struct reg_8 {
@@ -490,6 +484,22 @@ static int __maybe_unused imx214_power_off(struct device *dev)
return 0;
}
+static void imx214_update_pad_format(struct imx214 *imx214,
+ const struct imx214_mode *mode,
+ struct v4l2_mbus_framefmt *fmt, u32 code)
+{
+ fmt->code = IMX214_MBUS_CODE;
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
+ fmt->colorspace,
+ fmt->ycbcr_enc);
+ fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
+}
+
static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -549,52 +559,6 @@ static const struct v4l2_subdev_core_ops imx214_core_ops = {
#endif
};
-static struct v4l2_mbus_framefmt *
-__imx214_get_pad_format(struct imx214 *imx214,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad,
- enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_state_get_format(sd_state, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &imx214->fmt;
- default:
- return NULL;
- }
-}
-
-static int imx214_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct imx214 *imx214 = to_imx214(sd);
-
- mutex_lock(&imx214->mutex);
- format->format = *__imx214_get_pad_format(imx214, sd_state,
- format->pad,
- format->which);
- mutex_unlock(&imx214->mutex);
-
- return 0;
-}
-
-static struct v4l2_rect *
-__imx214_get_pad_crop(struct imx214 *imx214,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, enum v4l2_subdev_format_whence which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_state_get_crop(sd_state, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &imx214->crop;
- default:
- return NULL;
- }
-}
-
static int imx214_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -604,34 +568,19 @@ static int imx214_set_format(struct v4l2_subdev *sd,
struct v4l2_rect *__crop;
const struct imx214_mode *mode;
- mutex_lock(&imx214->mutex);
-
- __crop = __imx214_get_pad_crop(imx214, sd_state, format->pad,
- format->which);
-
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
format->format.width,
format->format.height);
- __crop->width = mode->width;
- __crop->height = mode->height;
+ imx214_update_pad_format(imx214, mode, &format->format, format->format.code);
- __format = __imx214_get_pad_format(imx214, sd_state, format->pad,
- format->which);
- __format->width = __crop->width;
- __format->height = __crop->height;
- __format->code = IMX214_MBUS_CODE;
- __format->field = V4L2_FIELD_NONE;
- __format->colorspace = V4L2_COLORSPACE_SRGB;
- __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace);
- __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
- __format->colorspace, __format->ycbcr_enc);
- __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace);
+ __format = v4l2_subdev_state_get_format(sd_state, 0);
+ *__format = format->format;
- format->format = *__format;
-
- mutex_unlock(&imx214->mutex);
+ __crop = v4l2_subdev_state_get_crop(sd_state, 0);
+ __crop->width = mode->width;
+ __crop->height = mode->height;
return 0;
}
@@ -640,14 +589,9 @@ static int imx214_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct imx214 *imx214 = to_imx214(sd);
-
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- mutex_lock(&imx214->mutex);
- sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
- sel->which);
- mutex_unlock(&imx214->mutex);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
return 0;
case V4L2_SEL_TGT_NATIVE_SIZE:
@@ -829,7 +773,6 @@ static int imx214_start_streaming(struct imx214 *imx214)
const struct imx214_mode *mode;
int ret;
- mutex_lock(&imx214->mutex);
ret = imx214_write_table(imx214, mode_table_common);
if (ret < 0) {
dev_err(imx214->dev, "could not sent common table %d\n", ret);
@@ -855,11 +798,9 @@ static int imx214_start_streaming(struct imx214 *imx214)
goto error;
}
- mutex_unlock(&imx214->mutex);
return 0;
error:
- mutex_unlock(&imx214->mutex);
return ret;
}
@@ -877,6 +818,7 @@ static int imx214_stop_streaming(struct imx214 *imx214)
static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
{
struct imx214 *imx214 = to_imx214(subdev);
+ struct v4l2_subdev_state *state;
int ret;
if (enable) {
@@ -884,7 +826,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
if (ret < 0)
return ret;
+ state = v4l2_subdev_lock_and_get_active_state(subdev);
ret = imx214_start_streaming(imx214);
+ v4l2_subdev_unlock_state(state);
if (ret < 0)
goto err_rpm_put;
} else {
@@ -948,7 +892,7 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
.enum_mbus_code = imx214_enum_mbus_code,
.enum_frame_size = imx214_enum_frame_size,
.enum_frame_interval = imx214_enum_frame_interval,
- .get_fmt = imx214_get_format,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = imx214_set_format,
.get_selection = imx214_get_selection,
.get_frame_interval = imx214_get_frame_interval,
@@ -1083,9 +1027,6 @@ static int imx214_probe(struct i2c_client *client)
if (ret < 0)
goto error_power_off;
- mutex_init(&imx214->mutex);
- imx214->ctrls.lock = &imx214->mutex;
-
imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx214->pad.flags = MEDIA_PAD_FL_SOURCE;
imx214->sd.dev = &client->dev;
@@ -1097,20 +1038,27 @@ static int imx214_probe(struct i2c_client *client)
goto free_ctrl;
}
- imx214_entity_init_state(&imx214->sd, NULL);
+ imx214->sd.state_lock = imx214->ctrls.lock;
+ ret = v4l2_subdev_init_finalize(&imx214->sd);
+ if (ret < 0) {
+ dev_err(dev, "subdev init error: %d\n", ret);
+ goto free_entity;
+ }
ret = v4l2_async_register_subdev_sensor(&imx214->sd);
if (ret < 0) {
dev_err(dev, "could not register v4l2 device\n");
- goto free_entity;
+ goto error_subdev_cleanup;
}
return 0;
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&imx214->sd);
+
free_entity:
media_entity_cleanup(&imx214->sd.entity);
free_ctrl:
- mutex_destroy(&imx214->mutex);
v4l2_ctrl_handler_free(&imx214->ctrls);
error_power_off:
pm_runtime_disable(imx214->dev);
@@ -1125,13 +1073,12 @@ static void imx214_remove(struct i2c_client *client)
struct imx214 *imx214 = to_imx214(sd);
v4l2_async_unregister_subdev(&imx214->sd);
+ v4l2_subdev_cleanup(sd);
media_entity_cleanup(&imx214->sd.entity);
v4l2_ctrl_handler_free(&imx214->ctrls);
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
-
- mutex_destroy(&imx214->mutex);
}
static const struct of_device_id imx214_of_match[] = {
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 02/13] media: i2c: imx214: Remove unneeded goto
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 01/13] media: i2c: imx214: Use subdev active state André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe() André Apitzsch via B4 Relay
` (10 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Simplify the imx214_start_streaming() by removing unneeded goto
statements, and the corresponding error label.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 58f3c3f67e0d..283d4783c22e 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -776,7 +776,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
ret = imx214_write_table(imx214, mode_table_common);
if (ret < 0) {
dev_err(imx214->dev, "could not sent common table %d\n", ret);
- goto error;
+ return ret;
}
mode = v4l2_find_nearest_size(imx214_modes,
@@ -785,22 +785,17 @@ static int imx214_start_streaming(struct imx214 *imx214)
ret = imx214_write_table(imx214, mode->reg_table);
if (ret < 0) {
dev_err(imx214->dev, "could not sent mode table %d\n", ret);
- goto error;
+ return ret;
}
ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
if (ret < 0) {
dev_err(imx214->dev, "could not sync v4l2 controls\n");
- goto error;
+ return ret;
}
ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STREAMING);
- if (ret < 0) {
+ if (ret < 0)
dev_err(imx214->dev, "could not sent start table %d\n", ret);
- goto error;
- }
-
- return 0;
-error:
return ret;
}
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe()
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 01/13] media: i2c: imx214: Use subdev active state André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 02/13] media: i2c: imx214: Remove unneeded goto André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers André Apitzsch via B4 Relay
` (9 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Error handling in probe() can be a bit simpler with dev_err_probe().
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 52 ++++++++++++++++++++--------------------------
1 file changed, 22 insertions(+), 30 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 283d4783c22e..ad2f1db6baeb 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -931,14 +931,12 @@ static int imx214_parse_fwnode(struct device *dev)
int ret;
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
- if (!endpoint) {
- dev_err(dev, "endpoint node not found\n");
- return -EINVAL;
- }
+ if (!endpoint)
+ return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
if (ret) {
- dev_err(dev, "parsing endpoint node failed\n");
+ dev_err_probe(dev, ret, "parsing endpoint node failed\n");
goto done;
}
@@ -947,8 +945,9 @@ static int imx214_parse_fwnode(struct device *dev)
break;
if (i == bus_cfg.nr_of_link_frequencies) {
- dev_err(dev, "link-frequencies %d not supported, Please review your DT\n",
- IMX214_DEFAULT_LINK_FREQ);
+ dev_err_probe(dev, -EINVAL,
+ "link-frequencies %d not supported, Please review your DT\n",
+ IMX214_DEFAULT_LINK_FREQ);
ret = -EINVAL;
goto done;
}
@@ -976,34 +975,27 @@ static int imx214_probe(struct i2c_client *client)
imx214->dev = dev;
imx214->xclk = devm_clk_get(dev, NULL);
- if (IS_ERR(imx214->xclk)) {
- dev_err(dev, "could not get xclk");
- return PTR_ERR(imx214->xclk);
- }
+ if (IS_ERR(imx214->xclk))
+ return dev_err_probe(dev, PTR_ERR(imx214->xclk),
+ "failed to get xclk\n");
ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ);
- if (ret) {
- dev_err(dev, "could not set xclk frequency\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to set xclk frequency\n");
ret = imx214_get_regulators(dev, imx214);
- if (ret < 0) {
- dev_err(dev, "cannot get regulators\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get regulators\n");
imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
- if (IS_ERR(imx214->enable_gpio)) {
- dev_err(dev, "cannot get enable gpio\n");
- return PTR_ERR(imx214->enable_gpio);
- }
+ if (IS_ERR(imx214->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(imx214->enable_gpio),
+ "failed to get enable gpio\n");
imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
- if (IS_ERR(imx214->regmap)) {
- dev_err(dev, "regmap init failed\n");
- return PTR_ERR(imx214->regmap);
- }
+ if (IS_ERR(imx214->regmap))
+ return dev_err_probe(dev, PTR_ERR(imx214->regmap),
+ "regmap init failed\n");
v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
imx214->sd.internal_ops = &imx214_internal_ops;
@@ -1029,20 +1021,20 @@ static int imx214_probe(struct i2c_client *client)
ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad);
if (ret < 0) {
- dev_err(dev, "could not register media entity\n");
+ dev_err_probe(dev, ret, "failed to init entity pads\n");
goto free_ctrl;
}
imx214->sd.state_lock = imx214->ctrls.lock;
ret = v4l2_subdev_init_finalize(&imx214->sd);
if (ret < 0) {
- dev_err(dev, "subdev init error: %d\n", ret);
+ dev_err_probe(dev, ret, "subdev init error\n");
goto free_entity;
}
ret = v4l2_async_register_subdev_sensor(&imx214->sd);
if (ret < 0) {
- dev_err(dev, "could not register v4l2 device\n");
+ dev_err_probe(dev, ret, "failed to register sensor sub-device\n");
goto error_subdev_cleanup;
}
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (2 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe() André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros André Apitzsch via B4 Relay
` (8 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Use the new common CCI register access helpers to replace the private
register access helpers in the imx214 driver. This simplifies the driver
by reducing the amount of code.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/Kconfig | 1 +
drivers/media/i2c/imx214.c | 672 +++++++++++++++++++++------------------------
2 files changed, 310 insertions(+), 363 deletions(-)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 8ba096b8ebca..85ecb2aeefdb 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -140,6 +140,7 @@ config VIDEO_IMX214
tristate "Sony IMX214 sensor support"
depends on GPIOLIB
select REGMAP_I2C
+ select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the Sony
IMX214 camera.
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index ad2f1db6baeb..780c9b8f88b0 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -15,11 +15,12 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <media/media-entity.h>
+#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-#define IMX214_REG_MODE_SELECT 0x0100
+#define IMX214_REG_MODE_SELECT CCI_REG8(0x0100)
#define IMX214_MODE_STANDBY 0x00
#define IMX214_MODE_STREAMING 0x01
@@ -30,7 +31,7 @@
#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
/* Exposure control */
-#define IMX214_REG_EXPOSURE 0x0202
+#define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
#define IMX214_EXPOSURE_MIN 0
#define IMX214_EXPOSURE_MAX 3184
#define IMX214_EXPOSURE_STEP 1
@@ -73,345 +74,324 @@ struct imx214 {
struct gpio_desc *enable_gpio;
};
-struct reg_8 {
- u16 addr;
- u8 val;
-};
-
-enum {
- IMX214_TABLE_WAIT_MS = 0,
- IMX214_TABLE_END,
- IMX214_MAX_RETRIES,
- IMX214_WAIT_MS
-};
-
/*From imx214_mode_tbls.h*/
-static const struct reg_8 mode_4096x2304[] = {
- {0x0114, 0x03},
- {0x0220, 0x00},
- {0x0221, 0x11},
- {0x0222, 0x01},
- {0x0340, 0x0C},
- {0x0341, 0x7A},
- {0x0342, 0x13},
- {0x0343, 0x90},
- {0x0344, 0x00},
- {0x0345, 0x38},
- {0x0346, 0x01},
- {0x0347, 0x98},
- {0x0348, 0x10},
- {0x0349, 0x37},
- {0x034A, 0x0A},
- {0x034B, 0x97},
- {0x0381, 0x01},
- {0x0383, 0x01},
- {0x0385, 0x01},
- {0x0387, 0x01},
- {0x0900, 0x00},
- {0x0901, 0x00},
- {0x0902, 0x00},
- {0x3000, 0x35},
- {0x3054, 0x01},
- {0x305C, 0x11},
-
- {0x0112, 0x0A},
- {0x0113, 0x0A},
- {0x034C, 0x10},
- {0x034D, 0x00},
- {0x034E, 0x09},
- {0x034F, 0x00},
- {0x0401, 0x00},
- {0x0404, 0x00},
- {0x0405, 0x10},
- {0x0408, 0x00},
- {0x0409, 0x00},
- {0x040A, 0x00},
- {0x040B, 0x00},
- {0x040C, 0x10},
- {0x040D, 0x00},
- {0x040E, 0x09},
- {0x040F, 0x00},
-
- {0x0301, 0x05},
- {0x0303, 0x02},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x96},
- {0x0309, 0x0A},
- {0x030B, 0x01},
- {0x0310, 0x00},
-
- {0x0820, 0x12},
- {0x0821, 0xC0},
- {0x0822, 0x00},
- {0x0823, 0x00},
-
- {0x3A03, 0x09},
- {0x3A04, 0x50},
- {0x3A05, 0x01},
-
- {0x0B06, 0x01},
- {0x30A2, 0x00},
-
- {0x30B4, 0x00},
-
- {0x3A02, 0xFF},
-
- {0x3011, 0x00},
- {0x3013, 0x01},
-
- {0x0202, 0x0C},
- {0x0203, 0x70},
- {0x0224, 0x01},
- {0x0225, 0xF4},
-
- {0x0204, 0x00},
- {0x0205, 0x00},
- {0x020E, 0x01},
- {0x020F, 0x00},
- {0x0210, 0x01},
- {0x0211, 0x00},
- {0x0212, 0x01},
- {0x0213, 0x00},
- {0x0214, 0x01},
- {0x0215, 0x00},
- {0x0216, 0x00},
- {0x0217, 0x00},
-
- {0x4170, 0x00},
- {0x4171, 0x10},
- {0x4176, 0x00},
- {0x4177, 0x3C},
- {0xAE20, 0x04},
- {0xAE21, 0x5C},
-
- {IMX214_TABLE_WAIT_MS, 10},
- {0x0138, 0x01},
- {IMX214_TABLE_END, 0x00}
+static const struct cci_reg_sequence mode_4096x2304[] = {
+ { CCI_REG8(0x0114), 0x03 },
+ { CCI_REG8(0x0220), 0x00 },
+ { CCI_REG8(0x0221), 0x11 },
+ { CCI_REG8(0x0222), 0x01 },
+ { CCI_REG8(0x0340), 0x0C },
+ { CCI_REG8(0x0341), 0x7A },
+ { CCI_REG8(0x0342), 0x13 },
+ { CCI_REG8(0x0343), 0x90 },
+ { CCI_REG8(0x0344), 0x00 },
+ { CCI_REG8(0x0345), 0x38 },
+ { CCI_REG8(0x0346), 0x01 },
+ { CCI_REG8(0x0347), 0x98 },
+ { CCI_REG8(0x0348), 0x10 },
+ { CCI_REG8(0x0349), 0x37 },
+ { CCI_REG8(0x034A), 0x0A },
+ { CCI_REG8(0x034B), 0x97 },
+ { CCI_REG8(0x0381), 0x01 },
+ { CCI_REG8(0x0383), 0x01 },
+ { CCI_REG8(0x0385), 0x01 },
+ { CCI_REG8(0x0387), 0x01 },
+ { CCI_REG8(0x0900), 0x00 },
+ { CCI_REG8(0x0901), 0x00 },
+ { CCI_REG8(0x0902), 0x00 },
+ { CCI_REG8(0x3000), 0x35 },
+ { CCI_REG8(0x3054), 0x01 },
+ { CCI_REG8(0x305C), 0x11 },
+
+ { CCI_REG8(0x0112), 0x0A },
+ { CCI_REG8(0x0113), 0x0A },
+ { CCI_REG8(0x034C), 0x10 },
+ { CCI_REG8(0x034D), 0x00 },
+ { CCI_REG8(0x034E), 0x09 },
+ { CCI_REG8(0x034F), 0x00 },
+ { CCI_REG8(0x0401), 0x00 },
+ { CCI_REG8(0x0404), 0x00 },
+ { CCI_REG8(0x0405), 0x10 },
+ { CCI_REG8(0x0408), 0x00 },
+ { CCI_REG8(0x0409), 0x00 },
+ { CCI_REG8(0x040A), 0x00 },
+ { CCI_REG8(0x040B), 0x00 },
+ { CCI_REG8(0x040C), 0x10 },
+ { CCI_REG8(0x040D), 0x00 },
+ { CCI_REG8(0x040E), 0x09 },
+ { CCI_REG8(0x040F), 0x00 },
+
+ { CCI_REG8(0x0301), 0x05 },
+ { CCI_REG8(0x0303), 0x02 },
+ { CCI_REG8(0x0305), 0x03 },
+ { CCI_REG8(0x0306), 0x00 },
+ { CCI_REG8(0x0307), 0x96 },
+ { CCI_REG8(0x0309), 0x0A },
+ { CCI_REG8(0x030B), 0x01 },
+ { CCI_REG8(0x0310), 0x00 },
+
+ { CCI_REG8(0x0820), 0x12 },
+ { CCI_REG8(0x0821), 0xC0 },
+ { CCI_REG8(0x0822), 0x00 },
+ { CCI_REG8(0x0823), 0x00 },
+
+ { CCI_REG8(0x3A03), 0x09 },
+ { CCI_REG8(0x3A04), 0x50 },
+ { CCI_REG8(0x3A05), 0x01 },
+
+ { CCI_REG8(0x0B06), 0x01 },
+ { CCI_REG8(0x30A2), 0x00 },
+
+ { CCI_REG8(0x30B4), 0x00 },
+
+ { CCI_REG8(0x3A02), 0xFF },
+
+ { CCI_REG8(0x3011), 0x00 },
+ { CCI_REG8(0x3013), 0x01 },
+
+ { CCI_REG8(0x0202), 0x0C },
+ { CCI_REG8(0x0203), 0x70 },
+ { CCI_REG8(0x0224), 0x01 },
+ { CCI_REG8(0x0225), 0xF4 },
+
+ { CCI_REG8(0x0204), 0x00 },
+ { CCI_REG8(0x0205), 0x00 },
+ { CCI_REG8(0x020E), 0x01 },
+ { CCI_REG8(0x020F), 0x00 },
+ { CCI_REG8(0x0210), 0x01 },
+ { CCI_REG8(0x0211), 0x00 },
+ { CCI_REG8(0x0212), 0x01 },
+ { CCI_REG8(0x0213), 0x00 },
+ { CCI_REG8(0x0214), 0x01 },
+ { CCI_REG8(0x0215), 0x00 },
+ { CCI_REG8(0x0216), 0x00 },
+ { CCI_REG8(0x0217), 0x00 },
+
+ { CCI_REG8(0x4170), 0x00 },
+ { CCI_REG8(0x4171), 0x10 },
+ { CCI_REG8(0x4176), 0x00 },
+ { CCI_REG8(0x4177), 0x3C },
+ { CCI_REG8(0xAE20), 0x04 },
+ { CCI_REG8(0xAE21), 0x5C },
};
-static const struct reg_8 mode_1920x1080[] = {
- {0x0114, 0x03},
- {0x0220, 0x00},
- {0x0221, 0x11},
- {0x0222, 0x01},
- {0x0340, 0x0C},
- {0x0341, 0x7A},
- {0x0342, 0x13},
- {0x0343, 0x90},
- {0x0344, 0x04},
- {0x0345, 0x78},
- {0x0346, 0x03},
- {0x0347, 0xFC},
- {0x0348, 0x0B},
- {0x0349, 0xF7},
- {0x034A, 0x08},
- {0x034B, 0x33},
- {0x0381, 0x01},
- {0x0383, 0x01},
- {0x0385, 0x01},
- {0x0387, 0x01},
- {0x0900, 0x00},
- {0x0901, 0x00},
- {0x0902, 0x00},
- {0x3000, 0x35},
- {0x3054, 0x01},
- {0x305C, 0x11},
-
- {0x0112, 0x0A},
- {0x0113, 0x0A},
- {0x034C, 0x07},
- {0x034D, 0x80},
- {0x034E, 0x04},
- {0x034F, 0x38},
- {0x0401, 0x00},
- {0x0404, 0x00},
- {0x0405, 0x10},
- {0x0408, 0x00},
- {0x0409, 0x00},
- {0x040A, 0x00},
- {0x040B, 0x00},
- {0x040C, 0x07},
- {0x040D, 0x80},
- {0x040E, 0x04},
- {0x040F, 0x38},
-
- {0x0301, 0x05},
- {0x0303, 0x02},
- {0x0305, 0x03},
- {0x0306, 0x00},
- {0x0307, 0x96},
- {0x0309, 0x0A},
- {0x030B, 0x01},
- {0x0310, 0x00},
-
- {0x0820, 0x12},
- {0x0821, 0xC0},
- {0x0822, 0x00},
- {0x0823, 0x00},
-
- {0x3A03, 0x04},
- {0x3A04, 0xF8},
- {0x3A05, 0x02},
-
- {0x0B06, 0x01},
- {0x30A2, 0x00},
-
- {0x30B4, 0x00},
-
- {0x3A02, 0xFF},
-
- {0x3011, 0x00},
- {0x3013, 0x01},
-
- {0x0202, 0x0C},
- {0x0203, 0x70},
- {0x0224, 0x01},
- {0x0225, 0xF4},
-
- {0x0204, 0x00},
- {0x0205, 0x00},
- {0x020E, 0x01},
- {0x020F, 0x00},
- {0x0210, 0x01},
- {0x0211, 0x00},
- {0x0212, 0x01},
- {0x0213, 0x00},
- {0x0214, 0x01},
- {0x0215, 0x00},
- {0x0216, 0x00},
- {0x0217, 0x00},
-
- {0x4170, 0x00},
- {0x4171, 0x10},
- {0x4176, 0x00},
- {0x4177, 0x3C},
- {0xAE20, 0x04},
- {0xAE21, 0x5C},
-
- {IMX214_TABLE_WAIT_MS, 10},
- {0x0138, 0x01},
- {IMX214_TABLE_END, 0x00}
+static const struct cci_reg_sequence mode_1920x1080[] = {
+ { CCI_REG8(0x0114), 0x03 },
+ { CCI_REG8(0x0220), 0x00 },
+ { CCI_REG8(0x0221), 0x11 },
+ { CCI_REG8(0x0222), 0x01 },
+ { CCI_REG8(0x0340), 0x0C },
+ { CCI_REG8(0x0341), 0x7A },
+ { CCI_REG8(0x0342), 0x13 },
+ { CCI_REG8(0x0343), 0x90 },
+ { CCI_REG8(0x0344), 0x04 },
+ { CCI_REG8(0x0345), 0x78 },
+ { CCI_REG8(0x0346), 0x03 },
+ { CCI_REG8(0x0347), 0xFC },
+ { CCI_REG8(0x0348), 0x0B },
+ { CCI_REG8(0x0349), 0xF7 },
+ { CCI_REG8(0x034A), 0x08 },
+ { CCI_REG8(0x034B), 0x33 },
+ { CCI_REG8(0x0381), 0x01 },
+ { CCI_REG8(0x0383), 0x01 },
+ { CCI_REG8(0x0385), 0x01 },
+ { CCI_REG8(0x0387), 0x01 },
+ { CCI_REG8(0x0900), 0x00 },
+ { CCI_REG8(0x0901), 0x00 },
+ { CCI_REG8(0x0902), 0x00 },
+ { CCI_REG8(0x3000), 0x35 },
+ { CCI_REG8(0x3054), 0x01 },
+ { CCI_REG8(0x305C), 0x11 },
+
+ { CCI_REG8(0x0112), 0x0A },
+ { CCI_REG8(0x0113), 0x0A },
+ { CCI_REG8(0x034C), 0x07 },
+ { CCI_REG8(0x034D), 0x80 },
+ { CCI_REG8(0x034E), 0x04 },
+ { CCI_REG8(0x034F), 0x38 },
+ { CCI_REG8(0x0401), 0x00 },
+ { CCI_REG8(0x0404), 0x00 },
+ { CCI_REG8(0x0405), 0x10 },
+ { CCI_REG8(0x0408), 0x00 },
+ { CCI_REG8(0x0409), 0x00 },
+ { CCI_REG8(0x040A), 0x00 },
+ { CCI_REG8(0x040B), 0x00 },
+ { CCI_REG8(0x040C), 0x07 },
+ { CCI_REG8(0x040D), 0x80 },
+ { CCI_REG8(0x040E), 0x04 },
+ { CCI_REG8(0x040F), 0x38 },
+
+ { CCI_REG8(0x0301), 0x05 },
+ { CCI_REG8(0x0303), 0x02 },
+ { CCI_REG8(0x0305), 0x03 },
+ { CCI_REG8(0x0306), 0x00 },
+ { CCI_REG8(0x0307), 0x96 },
+ { CCI_REG8(0x0309), 0x0A },
+ { CCI_REG8(0x030B), 0x01 },
+ { CCI_REG8(0x0310), 0x00 },
+
+ { CCI_REG8(0x0820), 0x12 },
+ { CCI_REG8(0x0821), 0xC0 },
+ { CCI_REG8(0x0822), 0x00 },
+ { CCI_REG8(0x0823), 0x00 },
+
+ { CCI_REG8(0x3A03), 0x04 },
+ { CCI_REG8(0x3A04), 0xF8 },
+ { CCI_REG8(0x3A05), 0x02 },
+
+ { CCI_REG8(0x0B06), 0x01 },
+ { CCI_REG8(0x30A2), 0x00 },
+
+ { CCI_REG8(0x30B4), 0x00 },
+
+ { CCI_REG8(0x3A02), 0xFF },
+
+ { CCI_REG8(0x3011), 0x00 },
+ { CCI_REG8(0x3013), 0x01 },
+
+ { CCI_REG8(0x0202), 0x0C },
+ { CCI_REG8(0x0203), 0x70 },
+ { CCI_REG8(0x0224), 0x01 },
+ { CCI_REG8(0x0225), 0xF4 },
+
+ { CCI_REG8(0x0204), 0x00 },
+ { CCI_REG8(0x0205), 0x00 },
+ { CCI_REG8(0x020E), 0x01 },
+ { CCI_REG8(0x020F), 0x00 },
+ { CCI_REG8(0x0210), 0x01 },
+ { CCI_REG8(0x0211), 0x00 },
+ { CCI_REG8(0x0212), 0x01 },
+ { CCI_REG8(0x0213), 0x00 },
+ { CCI_REG8(0x0214), 0x01 },
+ { CCI_REG8(0x0215), 0x00 },
+ { CCI_REG8(0x0216), 0x00 },
+ { CCI_REG8(0x0217), 0x00 },
+
+ { CCI_REG8(0x4170), 0x00 },
+ { CCI_REG8(0x4171), 0x10 },
+ { CCI_REG8(0x4176), 0x00 },
+ { CCI_REG8(0x4177), 0x3C },
+ { CCI_REG8(0xAE20), 0x04 },
+ { CCI_REG8(0xAE21), 0x5C },
};
-static const struct reg_8 mode_table_common[] = {
+static const struct cci_reg_sequence mode_table_common[] = {
/* software reset */
/* software standby settings */
- {0x0100, 0x00},
+ { CCI_REG8(0x0100), 0x00 },
/* ATR setting */
- {0x9300, 0x02},
+ { CCI_REG8(0x9300), 0x02 },
/* external clock setting */
- {0x0136, 0x18},
- {0x0137, 0x00},
+ { CCI_REG8(0x0136), 0x18 },
+ { CCI_REG8(0x0137), 0x00 },
/* global setting */
/* basic config */
- {0x0101, 0x00},
- {0x0105, 0x01},
- {0x0106, 0x01},
- {0x4550, 0x02},
- {0x4601, 0x00},
- {0x4642, 0x05},
- {0x6227, 0x11},
- {0x6276, 0x00},
- {0x900E, 0x06},
- {0xA802, 0x90},
- {0xA803, 0x11},
- {0xA804, 0x62},
- {0xA805, 0x77},
- {0xA806, 0xAE},
- {0xA807, 0x34},
- {0xA808, 0xAE},
- {0xA809, 0x35},
- {0xA80A, 0x62},
- {0xA80B, 0x83},
- {0xAE33, 0x00},
+ { CCI_REG8(0x0101), 0x00 },
+ { CCI_REG8(0x0105), 0x01 },
+ { CCI_REG8(0x0106), 0x01 },
+ { CCI_REG8(0x4550), 0x02 },
+ { CCI_REG8(0x4601), 0x00 },
+ { CCI_REG8(0x4642), 0x05 },
+ { CCI_REG8(0x6227), 0x11 },
+ { CCI_REG8(0x6276), 0x00 },
+ { CCI_REG8(0x900E), 0x06 },
+ { CCI_REG8(0xA802), 0x90 },
+ { CCI_REG8(0xA803), 0x11 },
+ { CCI_REG8(0xA804), 0x62 },
+ { CCI_REG8(0xA805), 0x77 },
+ { CCI_REG8(0xA806), 0xAE },
+ { CCI_REG8(0xA807), 0x34 },
+ { CCI_REG8(0xA808), 0xAE },
+ { CCI_REG8(0xA809), 0x35 },
+ { CCI_REG8(0xA80A), 0x62 },
+ { CCI_REG8(0xA80B), 0x83 },
+ { CCI_REG8(0xAE33), 0x00 },
/* analog setting */
- {0x4174, 0x00},
- {0x4175, 0x11},
- {0x4612, 0x29},
- {0x461B, 0x12},
- {0x461F, 0x06},
- {0x4635, 0x07},
- {0x4637, 0x30},
- {0x463F, 0x18},
- {0x4641, 0x0D},
- {0x465B, 0x12},
- {0x465F, 0x11},
- {0x4663, 0x11},
- {0x4667, 0x0F},
- {0x466F, 0x0F},
- {0x470E, 0x09},
- {0x4909, 0xAB},
- {0x490B, 0x95},
- {0x4915, 0x5D},
- {0x4A5F, 0xFF},
- {0x4A61, 0xFF},
- {0x4A73, 0x62},
- {0x4A85, 0x00},
- {0x4A87, 0xFF},
+ { CCI_REG8(0x4174), 0x00 },
+ { CCI_REG8(0x4175), 0x11 },
+ { CCI_REG8(0x4612), 0x29 },
+ { CCI_REG8(0x461B), 0x12 },
+ { CCI_REG8(0x461F), 0x06 },
+ { CCI_REG8(0x4635), 0x07 },
+ { CCI_REG8(0x4637), 0x30 },
+ { CCI_REG8(0x463F), 0x18 },
+ { CCI_REG8(0x4641), 0x0D },
+ { CCI_REG8(0x465B), 0x12 },
+ { CCI_REG8(0x465F), 0x11 },
+ { CCI_REG8(0x4663), 0x11 },
+ { CCI_REG8(0x4667), 0x0F },
+ { CCI_REG8(0x466F), 0x0F },
+ { CCI_REG8(0x470E), 0x09 },
+ { CCI_REG8(0x4909), 0xAB },
+ { CCI_REG8(0x490B), 0x95 },
+ { CCI_REG8(0x4915), 0x5D },
+ { CCI_REG8(0x4A5F), 0xFF },
+ { CCI_REG8(0x4A61), 0xFF },
+ { CCI_REG8(0x4A73), 0x62 },
+ { CCI_REG8(0x4A85), 0x00 },
+ { CCI_REG8(0x4A87), 0xFF },
/* embedded data */
- {0x5041, 0x04},
- {0x583C, 0x04},
- {0x620E, 0x04},
- {0x6EB2, 0x01},
- {0x6EB3, 0x00},
- {0x9300, 0x02},
+ { CCI_REG8(0x5041), 0x04 },
+ { CCI_REG8(0x583C), 0x04 },
+ { CCI_REG8(0x620E), 0x04 },
+ { CCI_REG8(0x6EB2), 0x01 },
+ { CCI_REG8(0x6EB3), 0x00 },
+ { CCI_REG8(0x9300), 0x02 },
/* imagequality */
/* HDR setting */
- {0x3001, 0x07},
- {0x6D12, 0x3F},
- {0x6D13, 0xFF},
- {0x9344, 0x03},
- {0x9706, 0x10},
- {0x9707, 0x03},
- {0x9708, 0x03},
- {0x9E04, 0x01},
- {0x9E05, 0x00},
- {0x9E0C, 0x01},
- {0x9E0D, 0x02},
- {0x9E24, 0x00},
- {0x9E25, 0x8C},
- {0x9E26, 0x00},
- {0x9E27, 0x94},
- {0x9E28, 0x00},
- {0x9E29, 0x96},
+ { CCI_REG8(0x3001), 0x07 },
+ { CCI_REG8(0x6D12), 0x3F },
+ { CCI_REG8(0x6D13), 0xFF },
+ { CCI_REG8(0x9344), 0x03 },
+ { CCI_REG8(0x9706), 0x10 },
+ { CCI_REG8(0x9707), 0x03 },
+ { CCI_REG8(0x9708), 0x03 },
+ { CCI_REG8(0x9E04), 0x01 },
+ { CCI_REG8(0x9E05), 0x00 },
+ { CCI_REG8(0x9E0C), 0x01 },
+ { CCI_REG8(0x9E0D), 0x02 },
+ { CCI_REG8(0x9E24), 0x00 },
+ { CCI_REG8(0x9E25), 0x8C },
+ { CCI_REG8(0x9E26), 0x00 },
+ { CCI_REG8(0x9E27), 0x94 },
+ { CCI_REG8(0x9E28), 0x00 },
+ { CCI_REG8(0x9E29), 0x96 },
/* CNR parameter setting */
- {0x69DB, 0x01},
+ { CCI_REG8(0x69DB), 0x01 },
/* Moire reduction */
- {0x6957, 0x01},
+ { CCI_REG8(0x6957), 0x01 },
/* image enhancement */
- {0x6987, 0x17},
- {0x698A, 0x03},
- {0x698B, 0x03},
+ { CCI_REG8(0x6987), 0x17 },
+ { CCI_REG8(0x698A), 0x03 },
+ { CCI_REG8(0x698B), 0x03 },
/* white balanace */
- {0x0B8E, 0x01},
- {0x0B8F, 0x00},
- {0x0B90, 0x01},
- {0x0B91, 0x00},
- {0x0B92, 0x01},
- {0x0B93, 0x00},
- {0x0B94, 0x01},
- {0x0B95, 0x00},
+ { CCI_REG8(0x0B8E), 0x01 },
+ { CCI_REG8(0x0B8F), 0x00 },
+ { CCI_REG8(0x0B90), 0x01 },
+ { CCI_REG8(0x0B91), 0x00 },
+ { CCI_REG8(0x0B92), 0x01 },
+ { CCI_REG8(0x0B93), 0x00 },
+ { CCI_REG8(0x0B94), 0x01 },
+ { CCI_REG8(0x0B95), 0x00 },
/* ATR setting */
- {0x6E50, 0x00},
- {0x6E51, 0x32},
- {0x9340, 0x00},
- {0x9341, 0x3C},
- {0x9342, 0x03},
- {0x9343, 0xFF},
- {IMX214_TABLE_END, 0x00}
+ { CCI_REG8(0x6E50), 0x00 },
+ { CCI_REG8(0x6E51), 0x32 },
+ { CCI_REG8(0x9340), 0x00 },
+ { CCI_REG8(0x9341), 0x3C },
+ { CCI_REG8(0x9342), 0x03 },
+ { CCI_REG8(0x9343), 0xFF },
};
/*
@@ -421,16 +401,19 @@ static const struct reg_8 mode_table_common[] = {
static const struct imx214_mode {
u32 width;
u32 height;
- const struct reg_8 *reg_table;
+ unsigned int num_of_regs;
+ const struct cci_reg_sequence *reg_table;
} imx214_modes[] = {
{
.width = 4096,
.height = 2304,
+ .num_of_regs = ARRAY_SIZE(mode_4096x2304),
.reg_table = mode_4096x2304,
},
{
.width = 1920,
.height = 1080,
+ .num_of_regs = ARRAY_SIZE(mode_1920x1080),
.reg_table = mode_1920x1080,
},
};
@@ -631,7 +614,6 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx214 *imx214 = container_of(ctrl->handler,
struct imx214, ctrls);
- u8 vals[2];
int ret;
/*
@@ -643,12 +625,7 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
- vals[1] = ctrl->val;
- vals[0] = ctrl->val >> 8;
- ret = regmap_bulk_write(imx214->regmap, IMX214_REG_EXPOSURE, vals, 2);
- if (ret < 0)
- dev_err(imx214->dev, "Error %d\n", ret);
- ret = 0;
+ cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
break;
default:
@@ -734,46 +711,13 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return 0;
};
-#define MAX_CMD 4
-static int imx214_write_table(struct imx214 *imx214,
- const struct reg_8 table[])
-{
- u8 vals[MAX_CMD];
- int i;
- int ret;
-
- for (; table->addr != IMX214_TABLE_END ; table++) {
- if (table->addr == IMX214_TABLE_WAIT_MS) {
- usleep_range(table->val * 1000,
- table->val * 1000 + 500);
- continue;
- }
-
- for (i = 0; i < MAX_CMD; i++) {
- if (table[i].addr != (table[0].addr + i))
- break;
- vals[i] = table[i].val;
- }
-
- ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i);
-
- if (ret) {
- dev_err(imx214->dev, "write_table error: %d\n", ret);
- return ret;
- }
-
- table += i - 1;
- }
-
- return 0;
-}
-
static int imx214_start_streaming(struct imx214 *imx214)
{
const struct imx214_mode *mode;
int ret;
- ret = imx214_write_table(imx214, mode_table_common);
+ ret = cci_multi_reg_write(imx214->regmap, mode_table_common,
+ ARRAY_SIZE(mode_table_common), NULL);
if (ret < 0) {
dev_err(imx214->dev, "could not sent common table %d\n", ret);
return ret;
@@ -782,17 +726,24 @@ static int imx214_start_streaming(struct imx214 *imx214)
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
imx214->fmt.width, imx214->fmt.height);
- ret = imx214_write_table(imx214, mode->reg_table);
+ ret = cci_multi_reg_write(imx214->regmap, mode->reg_table,
+ mode->num_of_regs, NULL);
if (ret < 0) {
dev_err(imx214->dev, "could not sent mode table %d\n", ret);
return ret;
}
+
+ usleep_range(10000, 10500);
+
+ cci_write(imx214->regmap, CCI_REG8(0x0138), 0x01, NULL);
+
ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
if (ret < 0) {
dev_err(imx214->dev, "could not sync v4l2 controls\n");
return ret;
}
- ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STREAMING);
+ ret = cci_write(imx214->regmap, IMX214_REG_MODE_SELECT,
+ IMX214_MODE_STREAMING, NULL);
if (ret < 0)
dev_err(imx214->dev, "could not sent start table %d\n", ret);
@@ -803,7 +754,8 @@ static int imx214_stop_streaming(struct imx214 *imx214)
{
int ret;
- ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STANDBY);
+ ret = cci_write(imx214->regmap, IMX214_REG_MODE_SELECT,
+ IMX214_MODE_STANDBY, NULL);
if (ret < 0)
dev_err(imx214->dev, "could not sent stop table %d\n", ret);
@@ -904,12 +856,6 @@ static const struct v4l2_subdev_internal_ops imx214_internal_ops = {
.init_state = imx214_entity_init_state,
};
-static const struct regmap_config sensor_regmap_config = {
- .reg_bits = 16,
- .val_bits = 8,
- .cache_type = REGCACHE_MAPLE,
-};
-
static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
{
unsigned int i;
@@ -992,10 +938,10 @@ static int imx214_probe(struct i2c_client *client)
return dev_err_probe(dev, PTR_ERR(imx214->enable_gpio),
"failed to get enable gpio\n");
- imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
+ imx214->regmap = devm_cci_regmap_init_i2c(client, 16);
if (IS_ERR(imx214->regmap))
return dev_err_probe(dev, PTR_ERR(imx214->regmap),
- "regmap init failed\n");
+ "failed to initialize CCI\n");
v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
imx214->sd.internal_ops = &imx214_internal_ops;
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (3 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays André Apitzsch via B4 Relay
` (7 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Define macros for all the known registers used in the register arrays,
and use them to replace the numerical addresses. This improves
readability.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 407 ++++++++++++++++++++++++++-------------------
1 file changed, 236 insertions(+), 171 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 780c9b8f88b0..91664e188fd0 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -24,18 +24,141 @@
#define IMX214_MODE_STANDBY 0x00
#define IMX214_MODE_STREAMING 0x01
+#define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106)
+
#define IMX214_DEFAULT_CLK_FREQ 24000000
#define IMX214_DEFAULT_LINK_FREQ 480000000
#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
#define IMX214_FPS 30
#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
+/* V-TIMING internal */
+#define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
+
/* Exposure control */
#define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
#define IMX214_EXPOSURE_MIN 0
#define IMX214_EXPOSURE_MAX 3184
#define IMX214_EXPOSURE_STEP 1
#define IMX214_EXPOSURE_DEFAULT 3184
+#define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
+#define IMX214_REG_SHORT_EXPOSURE CCI_REG16(0x0224)
+
+/* Analog gain control */
+#define IMX214_REG_ANALOG_GAIN CCI_REG16(0x0204)
+#define IMX214_REG_SHORT_ANALOG_GAIN CCI_REG16(0x0216)
+
+/* Digital gain control */
+#define IMX214_REG_DIG_GAIN_GREENR CCI_REG16(0x020e)
+#define IMX214_REG_DIG_GAIN_RED CCI_REG16(0x0210)
+#define IMX214_REG_DIG_GAIN_BLUE CCI_REG16(0x0212)
+#define IMX214_REG_DIG_GAIN_GREENB CCI_REG16(0x0214)
+
+#define IMX214_REG_ORIENTATION CCI_REG8(0x0101)
+
+#define IMX214_REG_MASK_CORR_FRAMES CCI_REG8(0x0105)
+#define IMX214_CORR_FRAMES_TRANSMIT 0
+#define IMX214_CORR_FRAMES_MASK 1
+
+#define IMX214_REG_CSI_DATA_FORMAT CCI_REG16(0x0112)
+#define IMX214_CSI_DATA_FORMAT_RAW8 0x0808
+#define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A
+#define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06
+#define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08
+
+#define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114)
+#define IMX214_CSI_2_LANE_MODE 1
+#define IMX214_CSI_4_LANE_MODE 3
+
+#define IMX214_REG_EXCK_FREQ CCI_REG16(0x0136)
+#define IMX214_EXCK_FREQ(n) ((n) * 256) /* n expressed in MHz */
+
+#define IMX214_REG_TEMP_SENSOR_CONTROL CCI_REG8(0x0138)
+
+#define IMX214_REG_HDR_MODE CCI_REG8(0x0220)
+#define IMX214_HDR_MODE_OFF 0
+#define IMX214_HDR_MODE_ON 1
+
+#define IMX214_REG_HDR_RES_REDUCTION CCI_REG8(0x0221)
+#define IMX214_HDR_RES_REDU_THROUGH 0x11
+#define IMX214_HDR_RES_REDU_2_BINNING 0x22
+
+/* PLL settings */
+#define IMX214_REG_VTPXCK_DIV CCI_REG8(0x0301)
+#define IMX214_REG_VTSYCK_DIV CCI_REG8(0x0303)
+#define IMX214_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
+#define IMX214_REG_PLL_VT_MPY CCI_REG16(0x0306)
+#define IMX214_REG_OPPXCK_DIV CCI_REG8(0x0309)
+#define IMX214_REG_OPSYCK_DIV CCI_REG8(0x030b)
+#define IMX214_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
+#define IMX214_PLL_SINGLE 0
+#define IMX214_PLL_DUAL 1
+
+#define IMX214_REG_LINE_LENGTH_PCK CCI_REG16(0x0342)
+#define IMX214_REG_X_ADD_STA CCI_REG16(0x0344)
+#define IMX214_REG_Y_ADD_STA CCI_REG16(0x0346)
+#define IMX214_REG_X_ADD_END CCI_REG16(0x0348)
+#define IMX214_REG_Y_ADD_END CCI_REG16(0x034a)
+#define IMX214_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
+#define IMX214_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
+#define IMX214_REG_X_EVEN_INC CCI_REG8(0x0381)
+#define IMX214_REG_X_ODD_INC CCI_REG8(0x0383)
+#define IMX214_REG_Y_EVEN_INC CCI_REG8(0x0385)
+#define IMX214_REG_Y_ODD_INC CCI_REG8(0x0387)
+
+#define IMX214_REG_SCALE_MODE CCI_REG8(0x0401)
+#define IMX214_SCALE_NONE 0
+#define IMX214_SCALE_HORIZONTAL 1
+#define IMX214_SCALE_FULL 2
+#define IMX214_REG_SCALE_M CCI_REG16(0x0404)
+
+#define IMX214_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
+#define IMX214_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define IMX214_REG_DIG_CROP_WIDTH CCI_REG16(0x040c)
+#define IMX214_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e)
+
+#define IMX214_REG_REQ_LINK_BIT_RATE CCI_REG32(0x0820)
+#define IMX214_LINK_BIT_RATE_MBPS(n) ((n) << 16)
+
+/* Binning mode */
+#define IMX214_REG_BINNING_MODE CCI_REG8(0x0900)
+#define IMX214_BINNING_NONE 0
+#define IMX214_BINNING_ENABLE 1
+#define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
+#define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
+#define IMX214_BINNING_AVERAGE 0x00
+#define IMX214_BINNING_SUMMED 0x01
+#define IMX214_BINNING_BAYER 0x02
+
+#define IMX214_REG_SING_DEF_CORR_EN CCI_REG8(0x0b06)
+#define IMX214_SING_DEF_CORR_OFF 0
+#define IMX214_SING_DEF_CORR_ON 1
+
+/* AWB control */
+#define IMX214_REG_ABS_GAIN_GREENR CCI_REG16(0x0b8e)
+#define IMX214_REG_ABS_GAIN_RED CCI_REG16(0x0b90)
+#define IMX214_REG_ABS_GAIN_BLUE CCI_REG16(0x0b92)
+#define IMX214_REG_ABS_GAIN_GREENB CCI_REG16(0x0b94)
+
+#define IMX214_REG_RMSC_NR_MODE CCI_REG8(0x3001)
+#define IMX214_REG_STATS_OUT_EN CCI_REG8(0x3013)
+#define IMX214_STATS_OUT_OFF 0
+#define IMX214_STATS_OUT_ON 1
+
+/* Chroma noise reduction */
+#define IMX214_REG_NML_NR_EN CCI_REG8(0x30a2)
+#define IMX214_NML_NR_OFF 0
+#define IMX214_NML_NR_ON 1
+
+#define IMX214_REG_EBD_SIZE_V CCI_REG8(0x5041)
+#define IMX214_EBD_NO 0
+#define IMX214_EBD_4_LINE 4
+
+#define IMX214_REG_RG_STATS_LMT CCI_REG16(0x6d12)
+#define IMX214_RG_STATS_LMT_10_BIT 0x03FF
+#define IMX214_RG_STATS_LMT_14_BIT 0x3FFF
+
+#define IMX214_REG_ATR_FAST_MOVE CCI_REG8(0x9300)
/* IMX214 native and active pixel array size */
#define IMX214_NATIVE_WIDTH 4224U
@@ -76,96 +199,70 @@ struct imx214 {
/*From imx214_mode_tbls.h*/
static const struct cci_reg_sequence mode_4096x2304[] = {
- { CCI_REG8(0x0114), 0x03 },
- { CCI_REG8(0x0220), 0x00 },
- { CCI_REG8(0x0221), 0x11 },
- { CCI_REG8(0x0222), 0x01 },
- { CCI_REG8(0x0340), 0x0C },
- { CCI_REG8(0x0341), 0x7A },
- { CCI_REG8(0x0342), 0x13 },
- { CCI_REG8(0x0343), 0x90 },
- { CCI_REG8(0x0344), 0x00 },
- { CCI_REG8(0x0345), 0x38 },
- { CCI_REG8(0x0346), 0x01 },
- { CCI_REG8(0x0347), 0x98 },
- { CCI_REG8(0x0348), 0x10 },
- { CCI_REG8(0x0349), 0x37 },
- { CCI_REG8(0x034A), 0x0A },
- { CCI_REG8(0x034B), 0x97 },
- { CCI_REG8(0x0381), 0x01 },
- { CCI_REG8(0x0383), 0x01 },
- { CCI_REG8(0x0385), 0x01 },
- { CCI_REG8(0x0387), 0x01 },
- { CCI_REG8(0x0900), 0x00 },
- { CCI_REG8(0x0901), 0x00 },
- { CCI_REG8(0x0902), 0x00 },
+ { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
+ { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
+ { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
+ { IMX214_REG_EXPOSURE_RATIO, 1 },
+ { IMX214_REG_FRM_LENGTH_LINES, 3194 },
+ { IMX214_REG_LINE_LENGTH_PCK, 5008 },
+ { IMX214_REG_X_ADD_STA, 56 },
+ { IMX214_REG_Y_ADD_STA, 408 },
+ { IMX214_REG_X_ADD_END, 4151 },
+ { IMX214_REG_Y_ADD_END, 2711 },
+ { IMX214_REG_X_EVEN_INC, 1 },
+ { IMX214_REG_X_ODD_INC, 1 },
+ { IMX214_REG_Y_EVEN_INC, 1 },
+ { IMX214_REG_Y_ODD_INC, 1 },
+ { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
+ { IMX214_REG_BINNING_TYPE, 0 },
+ { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
{ CCI_REG8(0x3000), 0x35 },
{ CCI_REG8(0x3054), 0x01 },
{ CCI_REG8(0x305C), 0x11 },
- { CCI_REG8(0x0112), 0x0A },
- { CCI_REG8(0x0113), 0x0A },
- { CCI_REG8(0x034C), 0x10 },
- { CCI_REG8(0x034D), 0x00 },
- { CCI_REG8(0x034E), 0x09 },
- { CCI_REG8(0x034F), 0x00 },
- { CCI_REG8(0x0401), 0x00 },
- { CCI_REG8(0x0404), 0x00 },
- { CCI_REG8(0x0405), 0x10 },
- { CCI_REG8(0x0408), 0x00 },
- { CCI_REG8(0x0409), 0x00 },
- { CCI_REG8(0x040A), 0x00 },
- { CCI_REG8(0x040B), 0x00 },
- { CCI_REG8(0x040C), 0x10 },
- { CCI_REG8(0x040D), 0x00 },
- { CCI_REG8(0x040E), 0x09 },
- { CCI_REG8(0x040F), 0x00 },
-
- { CCI_REG8(0x0301), 0x05 },
- { CCI_REG8(0x0303), 0x02 },
- { CCI_REG8(0x0305), 0x03 },
- { CCI_REG8(0x0306), 0x00 },
- { CCI_REG8(0x0307), 0x96 },
- { CCI_REG8(0x0309), 0x0A },
- { CCI_REG8(0x030B), 0x01 },
- { CCI_REG8(0x0310), 0x00 },
-
- { CCI_REG8(0x0820), 0x12 },
- { CCI_REG8(0x0821), 0xC0 },
- { CCI_REG8(0x0822), 0x00 },
- { CCI_REG8(0x0823), 0x00 },
+ { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
+ { IMX214_REG_X_OUTPUT_SIZE, 4096 },
+ { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
+ { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
+ { IMX214_REG_SCALE_M, 2 },
+ { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
+ { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
+ { IMX214_REG_DIG_CROP_WIDTH, 4096 },
+ { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
+
+ { IMX214_REG_VTPXCK_DIV, 5 },
+ { IMX214_REG_VTSYCK_DIV, 2 },
+ { IMX214_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX214_REG_PLL_VT_MPY, 150 },
+ { IMX214_REG_OPPXCK_DIV, 10 },
+ { IMX214_REG_OPSYCK_DIV, 1 },
+ { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
+
+ { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
{ CCI_REG8(0x3A03), 0x09 },
{ CCI_REG8(0x3A04), 0x50 },
{ CCI_REG8(0x3A05), 0x01 },
- { CCI_REG8(0x0B06), 0x01 },
- { CCI_REG8(0x30A2), 0x00 },
+ { IMX214_REG_SING_DEF_CORR_EN, IMX214_SING_DEF_CORR_ON },
+ { IMX214_REG_NML_NR_EN, IMX214_NML_NR_OFF },
{ CCI_REG8(0x30B4), 0x00 },
{ CCI_REG8(0x3A02), 0xFF },
{ CCI_REG8(0x3011), 0x00 },
- { CCI_REG8(0x3013), 0x01 },
-
- { CCI_REG8(0x0202), 0x0C },
- { CCI_REG8(0x0203), 0x70 },
- { CCI_REG8(0x0224), 0x01 },
- { CCI_REG8(0x0225), 0xF4 },
-
- { CCI_REG8(0x0204), 0x00 },
- { CCI_REG8(0x0205), 0x00 },
- { CCI_REG8(0x020E), 0x01 },
- { CCI_REG8(0x020F), 0x00 },
- { CCI_REG8(0x0210), 0x01 },
- { CCI_REG8(0x0211), 0x00 },
- { CCI_REG8(0x0212), 0x01 },
- { CCI_REG8(0x0213), 0x00 },
- { CCI_REG8(0x0214), 0x01 },
- { CCI_REG8(0x0215), 0x00 },
- { CCI_REG8(0x0216), 0x00 },
- { CCI_REG8(0x0217), 0x00 },
+ { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
+
+ { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
+ { IMX214_REG_SHORT_EXPOSURE, 500 },
+
+ { IMX214_REG_ANALOG_GAIN, 0 },
+ { IMX214_REG_DIG_GAIN_GREENR, 256 },
+ { IMX214_REG_DIG_GAIN_RED, 256 },
+ { IMX214_REG_DIG_GAIN_BLUE, 256 },
+ { IMX214_REG_DIG_GAIN_GREENB, 256 },
+ { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
{ CCI_REG8(0x4170), 0x00 },
{ CCI_REG8(0x4171), 0x10 },
@@ -176,96 +273,70 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
};
static const struct cci_reg_sequence mode_1920x1080[] = {
- { CCI_REG8(0x0114), 0x03 },
- { CCI_REG8(0x0220), 0x00 },
- { CCI_REG8(0x0221), 0x11 },
- { CCI_REG8(0x0222), 0x01 },
- { CCI_REG8(0x0340), 0x0C },
- { CCI_REG8(0x0341), 0x7A },
- { CCI_REG8(0x0342), 0x13 },
- { CCI_REG8(0x0343), 0x90 },
- { CCI_REG8(0x0344), 0x04 },
- { CCI_REG8(0x0345), 0x78 },
- { CCI_REG8(0x0346), 0x03 },
- { CCI_REG8(0x0347), 0xFC },
- { CCI_REG8(0x0348), 0x0B },
- { CCI_REG8(0x0349), 0xF7 },
- { CCI_REG8(0x034A), 0x08 },
- { CCI_REG8(0x034B), 0x33 },
- { CCI_REG8(0x0381), 0x01 },
- { CCI_REG8(0x0383), 0x01 },
- { CCI_REG8(0x0385), 0x01 },
- { CCI_REG8(0x0387), 0x01 },
- { CCI_REG8(0x0900), 0x00 },
- { CCI_REG8(0x0901), 0x00 },
- { CCI_REG8(0x0902), 0x00 },
+ { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
+ { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
+ { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
+ { IMX214_REG_EXPOSURE_RATIO, 1 },
+ { IMX214_REG_FRM_LENGTH_LINES, 3194 },
+ { IMX214_REG_LINE_LENGTH_PCK, 5008 },
+ { IMX214_REG_X_ADD_STA, 1144 },
+ { IMX214_REG_Y_ADD_STA, 1020 },
+ { IMX214_REG_X_ADD_END, 3063 },
+ { IMX214_REG_Y_ADD_END, 2099 },
+ { IMX214_REG_X_EVEN_INC, 1 },
+ { IMX214_REG_X_ODD_INC, 1 },
+ { IMX214_REG_Y_EVEN_INC, 1 },
+ { IMX214_REG_Y_ODD_INC, 1 },
+ { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
+ { IMX214_REG_BINNING_TYPE, 0 },
+ { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
{ CCI_REG8(0x3000), 0x35 },
{ CCI_REG8(0x3054), 0x01 },
{ CCI_REG8(0x305C), 0x11 },
- { CCI_REG8(0x0112), 0x0A },
- { CCI_REG8(0x0113), 0x0A },
- { CCI_REG8(0x034C), 0x07 },
- { CCI_REG8(0x034D), 0x80 },
- { CCI_REG8(0x034E), 0x04 },
- { CCI_REG8(0x034F), 0x38 },
- { CCI_REG8(0x0401), 0x00 },
- { CCI_REG8(0x0404), 0x00 },
- { CCI_REG8(0x0405), 0x10 },
- { CCI_REG8(0x0408), 0x00 },
- { CCI_REG8(0x0409), 0x00 },
- { CCI_REG8(0x040A), 0x00 },
- { CCI_REG8(0x040B), 0x00 },
- { CCI_REG8(0x040C), 0x07 },
- { CCI_REG8(0x040D), 0x80 },
- { CCI_REG8(0x040E), 0x04 },
- { CCI_REG8(0x040F), 0x38 },
-
- { CCI_REG8(0x0301), 0x05 },
- { CCI_REG8(0x0303), 0x02 },
- { CCI_REG8(0x0305), 0x03 },
- { CCI_REG8(0x0306), 0x00 },
- { CCI_REG8(0x0307), 0x96 },
- { CCI_REG8(0x0309), 0x0A },
- { CCI_REG8(0x030B), 0x01 },
- { CCI_REG8(0x0310), 0x00 },
-
- { CCI_REG8(0x0820), 0x12 },
- { CCI_REG8(0x0821), 0xC0 },
- { CCI_REG8(0x0822), 0x00 },
- { CCI_REG8(0x0823), 0x00 },
+ { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
+ { IMX214_REG_X_OUTPUT_SIZE, 1920 },
+ { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
+ { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
+ { IMX214_REG_SCALE_M, 2 },
+ { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
+ { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
+ { IMX214_REG_DIG_CROP_WIDTH, 1920 },
+ { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
+
+ { IMX214_REG_VTPXCK_DIV, 5 },
+ { IMX214_REG_VTSYCK_DIV, 2 },
+ { IMX214_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX214_REG_PLL_VT_MPY, 150 },
+ { IMX214_REG_OPPXCK_DIV, 10 },
+ { IMX214_REG_OPSYCK_DIV, 1 },
+ { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
+
+ { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
{ CCI_REG8(0x3A03), 0x04 },
{ CCI_REG8(0x3A04), 0xF8 },
{ CCI_REG8(0x3A05), 0x02 },
- { CCI_REG8(0x0B06), 0x01 },
- { CCI_REG8(0x30A2), 0x00 },
+ { IMX214_REG_SING_DEF_CORR_EN, IMX214_SING_DEF_CORR_ON },
+ { IMX214_REG_NML_NR_EN, IMX214_NML_NR_OFF },
{ CCI_REG8(0x30B4), 0x00 },
{ CCI_REG8(0x3A02), 0xFF },
{ CCI_REG8(0x3011), 0x00 },
- { CCI_REG8(0x3013), 0x01 },
-
- { CCI_REG8(0x0202), 0x0C },
- { CCI_REG8(0x0203), 0x70 },
- { CCI_REG8(0x0224), 0x01 },
- { CCI_REG8(0x0225), 0xF4 },
-
- { CCI_REG8(0x0204), 0x00 },
- { CCI_REG8(0x0205), 0x00 },
- { CCI_REG8(0x020E), 0x01 },
- { CCI_REG8(0x020F), 0x00 },
- { CCI_REG8(0x0210), 0x01 },
- { CCI_REG8(0x0211), 0x00 },
- { CCI_REG8(0x0212), 0x01 },
- { CCI_REG8(0x0213), 0x00 },
- { CCI_REG8(0x0214), 0x01 },
- { CCI_REG8(0x0215), 0x00 },
- { CCI_REG8(0x0216), 0x00 },
- { CCI_REG8(0x0217), 0x00 },
+ { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
+
+ { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
+ { IMX214_REG_SHORT_EXPOSURE, 500 },
+
+ { IMX214_REG_ANALOG_GAIN, 0 },
+ { IMX214_REG_DIG_GAIN_GREENR, 256 },
+ { IMX214_REG_DIG_GAIN_RED, 256 },
+ { IMX214_REG_DIG_GAIN_BLUE, 256 },
+ { IMX214_REG_DIG_GAIN_GREENB, 256 },
+ { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
{ CCI_REG8(0x4170), 0x00 },
{ CCI_REG8(0x4171), 0x10 },
@@ -279,20 +350,19 @@ static const struct cci_reg_sequence mode_table_common[] = {
/* software reset */
/* software standby settings */
- { CCI_REG8(0x0100), 0x00 },
+ { IMX214_REG_MODE_SELECT, IMX214_MODE_STANDBY },
/* ATR setting */
- { CCI_REG8(0x9300), 0x02 },
+ { IMX214_REG_ATR_FAST_MOVE, 2 },
/* external clock setting */
- { CCI_REG8(0x0136), 0x18 },
- { CCI_REG8(0x0137), 0x00 },
+ { IMX214_REG_EXCK_FREQ, IMX214_EXCK_FREQ(IMX214_DEFAULT_CLK_FREQ / 1000000) },
/* global setting */
/* basic config */
- { CCI_REG8(0x0101), 0x00 },
- { CCI_REG8(0x0105), 0x01 },
- { CCI_REG8(0x0106), 0x01 },
+ { IMX214_REG_ORIENTATION, 0 },
+ { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
+ { IMX214_REG_FAST_STANDBY_CTRL, 1 },
{ CCI_REG8(0x4550), 0x02 },
{ CCI_REG8(0x4601), 0x00 },
{ CCI_REG8(0x4642), 0x05 },
@@ -337,18 +407,17 @@ static const struct cci_reg_sequence mode_table_common[] = {
{ CCI_REG8(0x4A87), 0xFF },
/* embedded data */
- { CCI_REG8(0x5041), 0x04 },
+ { IMX214_REG_EBD_SIZE_V, IMX214_EBD_4_LINE },
{ CCI_REG8(0x583C), 0x04 },
{ CCI_REG8(0x620E), 0x04 },
{ CCI_REG8(0x6EB2), 0x01 },
{ CCI_REG8(0x6EB3), 0x00 },
- { CCI_REG8(0x9300), 0x02 },
+ { IMX214_REG_ATR_FAST_MOVE, 2 },
/* imagequality */
/* HDR setting */
- { CCI_REG8(0x3001), 0x07 },
- { CCI_REG8(0x6D12), 0x3F },
- { CCI_REG8(0x6D13), 0xFF },
+ { IMX214_REG_RMSC_NR_MODE, 0x07 },
+ { IMX214_REG_RG_STATS_LMT, IMX214_RG_STATS_LMT_14_BIT },
{ CCI_REG8(0x9344), 0x03 },
{ CCI_REG8(0x9706), 0x10 },
{ CCI_REG8(0x9707), 0x03 },
@@ -376,14 +445,10 @@ static const struct cci_reg_sequence mode_table_common[] = {
{ CCI_REG8(0x698B), 0x03 },
/* white balanace */
- { CCI_REG8(0x0B8E), 0x01 },
- { CCI_REG8(0x0B8F), 0x00 },
- { CCI_REG8(0x0B90), 0x01 },
- { CCI_REG8(0x0B91), 0x00 },
- { CCI_REG8(0x0B92), 0x01 },
- { CCI_REG8(0x0B93), 0x00 },
- { CCI_REG8(0x0B94), 0x01 },
- { CCI_REG8(0x0B95), 0x00 },
+ { IMX214_REG_ABS_GAIN_GREENR, 0x0100 },
+ { IMX214_REG_ABS_GAIN_RED, 0x0100 },
+ { IMX214_REG_ABS_GAIN_BLUE, 0x0100 },
+ { IMX214_REG_ABS_GAIN_GREENB, 0x0100 },
/* ATR setting */
{ CCI_REG8(0x6E50), 0x00 },
@@ -735,7 +800,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
usleep_range(10000, 10500);
- cci_write(imx214->regmap, CCI_REG8(0x0138), 0x01, NULL);
+ cci_write(imx214->regmap, IMX214_REG_TEMP_SENSOR_CONTROL, 0x01, NULL);
ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
if (ret < 0) {
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (4 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree André Apitzsch via B4 Relay
` (6 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
The IMX214_REG_EXPOSURE is configured twice, once with a hardcoded value
in the mode_<res> registers arrays, and once via v4l2_ctrl_ops. The
latter is enough, drop the former.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 91664e188fd0..4507e12dd4cd 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -254,7 +254,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
{ CCI_REG8(0x3011), 0x00 },
{ IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
- { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
{ IMX214_REG_SHORT_EXPOSURE, 500 },
{ IMX214_REG_ANALOG_GAIN, 0 },
@@ -328,7 +327,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
{ CCI_REG8(0x3011), 0x00 },
{ IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
- { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
{ IMX214_REG_SHORT_EXPOSURE, 500 },
{ IMX214_REG_ANALOG_GAIN, 0 },
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (5 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls André Apitzsch via B4 Relay
` (5 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
The imx214 camera is capable of either two-lane or four-lane operation.
Currently only the four-lane mode is supported, as proper pixel rates
and link frequences for the two-lane mode are unknown.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 37 ++++++++++++++++++++++++++++++-------
1 file changed, 30 insertions(+), 7 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 4507e12dd4cd..3b422cddbdce 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -195,11 +195,13 @@ struct imx214 {
struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
struct gpio_desc *enable_gpio;
+
+ /* Two or Four lanes */
+ u8 lanes;
};
/*From imx214_mode_tbls.h*/
static const struct cci_reg_sequence mode_4096x2304[] = {
- { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
@@ -272,7 +274,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
};
static const struct cci_reg_sequence mode_1920x1080[] = {
- { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
@@ -774,6 +775,13 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return 0;
};
+static int imx214_configure_lanes(struct imx214 *imx214)
+{
+ return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
+ imx214->lanes == 2 ? IMX214_CSI_2_LANE_MODE :
+ IMX214_CSI_4_LANE_MODE, NULL);
+};
+
static int imx214_start_streaming(struct imx214 *imx214)
{
const struct imx214_mode *mode;
@@ -786,6 +794,13 @@ static int imx214_start_streaming(struct imx214 *imx214)
return ret;
}
+ /* Configure two or four Lane mode */
+ ret = imx214_configure_lanes(imx214);
+ if (ret) {
+ dev_err(imx214->dev, "%s failed to configure lanes\n", __func__);
+ return ret;
+ }
+
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
imx214->fmt.width, imx214->fmt.height);
@@ -930,7 +945,7 @@ static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
imx214->supplies);
}
-static int imx214_parse_fwnode(struct device *dev)
+static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214)
{
struct fwnode_handle *endpoint;
struct v4l2_fwnode_endpoint bus_cfg = {
@@ -949,6 +964,14 @@ static int imx214_parse_fwnode(struct device *dev)
goto done;
}
+ /* Check the number of MIPI CSI2 data lanes */
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ dev_err_probe(dev, -EINVAL,
+ "only 4 data lanes are currently supported\n");
+ goto done;
+ }
+ imx214->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+
for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ)
break;
@@ -973,14 +996,14 @@ static int imx214_probe(struct i2c_client *client)
struct imx214 *imx214;
int ret;
- ret = imx214_parse_fwnode(dev);
- if (ret)
- return ret;
-
imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL);
if (!imx214)
return -ENOMEM;
+ ret = imx214_parse_fwnode(dev, imx214);
+ if (ret)
+ return ret;
+
imx214->dev = dev;
imx214->xclk = devm_clk_get(dev, NULL);
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (6 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 09/13] media: i2c: imx214: Extract format and crop settings André Apitzsch via B4 Relay
` (4 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Add vblank control to allow changing the framerate /
higher exposure values.
The vblank and hblank controls are needed for libcamera support.
While at it, fix the minimal exposure time according to the datasheet.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 112 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 91 insertions(+), 21 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 3b422cddbdce..9f5a57aebb86 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -34,11 +34,18 @@
/* V-TIMING internal */
#define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
+#define IMX214_VTS_MAX 0xffff
+
+#define IMX214_VBLANK_MIN 4
+
+/* HBLANK control - read only */
+#define IMX214_PPL_DEFAULT 5008
/* Exposure control */
#define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
-#define IMX214_EXPOSURE_MIN 0
-#define IMX214_EXPOSURE_MAX 3184
+#define IMX214_EXPOSURE_OFFSET 10
+#define IMX214_EXPOSURE_MIN 1
+#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX - IMX214_EXPOSURE_OFFSET)
#define IMX214_EXPOSURE_STEP 1
#define IMX214_EXPOSURE_DEFAULT 3184
#define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
@@ -189,6 +196,8 @@ struct imx214 {
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *pixel_rate;
struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
struct v4l2_ctrl *unit_size;
@@ -205,8 +214,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
- { IMX214_REG_FRM_LENGTH_LINES, 3194 },
- { IMX214_REG_LINE_LENGTH_PCK, 5008 },
{ IMX214_REG_X_ADD_STA, 56 },
{ IMX214_REG_Y_ADD_STA, 408 },
{ IMX214_REG_X_ADD_END, 4151 },
@@ -277,8 +284,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
- { IMX214_REG_FRM_LENGTH_LINES, 3194 },
- { IMX214_REG_LINE_LENGTH_PCK, 5008 },
{ IMX214_REG_X_ADD_STA, 1144 },
{ IMX214_REG_Y_ADD_STA, 1020 },
{ IMX214_REG_X_ADD_END, 3063 },
@@ -362,6 +367,7 @@ static const struct cci_reg_sequence mode_table_common[] = {
{ IMX214_REG_ORIENTATION, 0 },
{ IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
{ IMX214_REG_FAST_STANDBY_CTRL, 1 },
+ { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
{ CCI_REG8(0x4550), 0x02 },
{ CCI_REG8(0x4601), 0x00 },
{ CCI_REG8(0x4642), 0x05 },
@@ -465,18 +471,24 @@ static const struct cci_reg_sequence mode_table_common[] = {
static const struct imx214_mode {
u32 width;
u32 height;
+
+ /* V-timing */
+ unsigned int vts_def;
+
unsigned int num_of_regs;
const struct cci_reg_sequence *reg_table;
} imx214_modes[] = {
{
.width = 4096,
.height = 2304,
+ .vts_def = 3194,
.num_of_regs = ARRAY_SIZE(mode_4096x2304),
.reg_table = mode_4096x2304,
},
{
.width = 1920,
.height = 1080,
+ .vts_def = 3194,
.num_of_regs = ARRAY_SIZE(mode_1920x1080),
.reg_table = mode_1920x1080,
},
@@ -629,6 +641,37 @@ static int imx214_set_format(struct v4l2_subdev *sd,
__crop->width = mode->width;
__crop->height = mode->height;
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ int exposure_max;
+ int exposure_def;
+ int hblank;
+
+ /* Update limits and set FPS to default */
+ __v4l2_ctrl_modify_range(imx214->vblank, IMX214_VBLANK_MIN,
+ IMX214_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+ __v4l2_ctrl_s_ctrl(imx214->vblank,
+ mode->vts_def - mode->height);
+
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
+ exposure_def = (exposure_max < IMX214_EXPOSURE_DEFAULT) ?
+ exposure_max : IMX214_EXPOSURE_DEFAULT;
+ __v4l2_ctrl_modify_range(imx214->exposure,
+ imx214->exposure->minimum,
+ exposure_max, imx214->exposure->step,
+ exposure_def);
+
+ /*
+ * Currently PPL is fixed to IMX214_PPL_DEFAULT, so hblank
+ * depends on mode->width only, and is not changeble in any
+ * way other than changing the mode.
+ */
+ hblank = IMX214_PPL_DEFAULT - mode->width;
+ __v4l2_ctrl_modify_range(imx214->hblank, hblank, hblank, 1,
+ hblank);
+ }
+
return 0;
}
@@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx214 *imx214 = container_of(ctrl->handler,
struct imx214, ctrls);
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
int ret;
+ state = v4l2_subdev_get_locked_active_state(&imx214->sd);
+ format = v4l2_subdev_state_get_format(state, 0);
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exposure_max, exposure_def;
+
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = format->height + ctrl->val - IMX214_EXPOSURE_OFFSET;
+ exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
+ __v4l2_ctrl_modify_range(imx214->exposure,
+ imx214->exposure->minimum,
+ exposure_max, imx214->exposure->step,
+ exposure_def);
+ }
+
/*
* Applying V4L2 control value only happens
* when power is up for streaming
@@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
break;
-
+ case V4L2_CID_VBLANK:
+ cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
+ format->height + ctrl->val, &ret);
+ break;
default:
ret = -EINVAL;
}
@@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214 *imx214)
.width = 1120,
.height = 1120,
};
+ const struct imx214_mode *mode = &imx214_modes[0];
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
+ int exposure_max, exposure_def;
+ int hblank;
int ret;
ret = v4l2_fwnode_device_parse(imx214->dev, &props);
@@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return ret;
ctrl_hdlr = &imx214->ctrls;
- ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
+ ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
if (ret)
return ret;
@@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
if (imx214->link_freq)
imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- /*
- * WARNING!
- * Values obtained reverse engineering blobs and/or devices.
- * Ranges and functionality might be wrong.
- *
- * Sony, please release some register set documentation for the
- * device.
- *
- * Yours sincerely, Ricardo.
- */
+ /* Initial vblank/hblank/exposure parameters based on current mode */
+ imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_VBLANK, IMX214_VBLANK_MIN,
+ IMX214_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+
+ hblank = IMX214_PPL_DEFAULT - mode->width;
+ imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (imx214->hblank)
+ imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
+ exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
V4L2_CID_EXPOSURE,
- IMX214_EXPOSURE_MIN,
- IMX214_EXPOSURE_MAX,
+ IMX214_EXPOSURE_MIN, exposure_max,
IMX214_EXPOSURE_STEP,
- IMX214_EXPOSURE_DEFAULT);
+ exposure_def);
imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
NULL,
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 09/13] media: i2c: imx214: Extract format and crop settings
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (7 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls André Apitzsch via B4 Relay
` (3 subsequent siblings)
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Remove format and crop settings from register sequences and set them
programmatically.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 137 ++++++++++++++++++++++++++++++++++-----------
1 file changed, 105 insertions(+), 32 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 9f5a57aebb86..733f55257585 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -132,6 +132,9 @@
#define IMX214_BINNING_NONE 0
#define IMX214_BINNING_ENABLE 1
#define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
+#define IMX214_BINNING_1X1 0
+#define IMX214_BINNING_2X2 0x22
+#define IMX214_BINNING_4X4 0x44
#define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
#define IMX214_BINNING_AVERAGE 0x00
#define IMX214_BINNING_SUMMED 0x01
@@ -214,36 +217,22 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
- { IMX214_REG_X_ADD_STA, 56 },
- { IMX214_REG_Y_ADD_STA, 408 },
- { IMX214_REG_X_ADD_END, 4151 },
- { IMX214_REG_Y_ADD_END, 2711 },
{ IMX214_REG_X_EVEN_INC, 1 },
{ IMX214_REG_X_ODD_INC, 1 },
{ IMX214_REG_Y_EVEN_INC, 1 },
{ IMX214_REG_Y_ODD_INC, 1 },
- { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
- { IMX214_REG_BINNING_TYPE, 0 },
{ IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
{ CCI_REG8(0x3000), 0x35 },
{ CCI_REG8(0x3054), 0x01 },
{ CCI_REG8(0x305C), 0x11 },
- { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
- { IMX214_REG_X_OUTPUT_SIZE, 4096 },
- { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
{ IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
{ IMX214_REG_SCALE_M, 2 },
- { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
- { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
- { IMX214_REG_DIG_CROP_WIDTH, 4096 },
- { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
{ IMX214_REG_VTPXCK_DIV, 5 },
{ IMX214_REG_VTSYCK_DIV, 2 },
{ IMX214_REG_PREPLLCK_VT_DIV, 3 },
{ IMX214_REG_PLL_VT_MPY, 150 },
- { IMX214_REG_OPPXCK_DIV, 10 },
{ IMX214_REG_OPSYCK_DIV, 1 },
{ IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
@@ -284,36 +273,22 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
{ IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
{ IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
{ IMX214_REG_EXPOSURE_RATIO, 1 },
- { IMX214_REG_X_ADD_STA, 1144 },
- { IMX214_REG_Y_ADD_STA, 1020 },
- { IMX214_REG_X_ADD_END, 3063 },
- { IMX214_REG_Y_ADD_END, 2099 },
{ IMX214_REG_X_EVEN_INC, 1 },
{ IMX214_REG_X_ODD_INC, 1 },
{ IMX214_REG_Y_EVEN_INC, 1 },
{ IMX214_REG_Y_ODD_INC, 1 },
- { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
- { IMX214_REG_BINNING_TYPE, 0 },
{ IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
{ CCI_REG8(0x3000), 0x35 },
{ CCI_REG8(0x3054), 0x01 },
{ CCI_REG8(0x305C), 0x11 },
- { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
- { IMX214_REG_X_OUTPUT_SIZE, 1920 },
- { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
{ IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
{ IMX214_REG_SCALE_M, 2 },
- { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
- { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
- { IMX214_REG_DIG_CROP_WIDTH, 1920 },
- { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
{ IMX214_REG_VTPXCK_DIV, 5 },
{ IMX214_REG_VTSYCK_DIV, 2 },
{ IMX214_REG_PREPLLCK_VT_DIV, 3 },
{ IMX214_REG_PLL_VT_MPY, 150 },
- { IMX214_REG_OPPXCK_DIV, 10 },
{ IMX214_REG_OPSYCK_DIV, 1 },
{ IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
@@ -626,6 +601,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *__format;
struct v4l2_rect *__crop;
const struct imx214_mode *mode;
+ unsigned int bin_h, bin_v, bin;
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
@@ -637,9 +613,32 @@ static int imx214_set_format(struct v4l2_subdev *sd,
__format = v4l2_subdev_state_get_format(sd_state, 0);
*__format = format->format;
+ /*
+ * Use binning to maximize the crop rectangle size, and centre it in the
+ * sensor.
+ */
+ bin_h = IMX214_PIXEL_ARRAY_WIDTH / __format->width;
+ bin_v = IMX214_PIXEL_ARRAY_HEIGHT / __format->height;
+
+ switch (min(bin_h, bin_v)) {
+ case 1:
+ bin = 1;
+ break;
+ case 2:
+ case 3:
+ bin = 2;
+ break;
+ case 4:
+ default:
+ bin = 4;
+ break;
+ }
+
__crop = v4l2_subdev_state_get_crop(sd_state, 0);
- __crop->width = mode->width;
- __crop->height = mode->height;
+ __crop->width = __format->width * bin;
+ __crop->height = __format->height * bin;
+ __crop->left = (IMX214_NATIVE_WIDTH - __crop->width) / 2;
+ __crop->top = (IMX214_NATIVE_HEIGHT - __crop->height) / 2;
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
int exposure_max;
@@ -845,6 +844,71 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return 0;
};
+static int imx214_set_framefmt(struct imx214 *imx214,
+ struct v4l2_subdev_state *state)
+{
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
+ unsigned int bpp;
+ u64 bin_mode;
+ u64 bin_type;
+ int ret = 0;
+
+ format = v4l2_subdev_state_get_format(state, 0);
+ crop = v4l2_subdev_state_get_crop(state, 0);
+
+ switch (format->code) {
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ default:
+ bpp = 10;
+ break;
+ }
+
+ cci_write(imx214->regmap, IMX214_REG_X_ADD_STA,
+ crop->left - IMX214_PIXEL_ARRAY_LEFT, &ret);
+ cci_write(imx214->regmap, IMX214_REG_X_ADD_END,
+ crop->left - IMX214_PIXEL_ARRAY_LEFT + crop->width - 1, &ret);
+ cci_write(imx214->regmap, IMX214_REG_Y_ADD_STA,
+ crop->top - IMX214_PIXEL_ARRAY_TOP, &ret);
+ cci_write(imx214->regmap, IMX214_REG_Y_ADD_END,
+ crop->top - IMX214_PIXEL_ARRAY_TOP + crop->height - 1, &ret);
+
+ /* Proper setting is required even if cropping is not used */
+ cci_write(imx214->regmap, IMX214_REG_DIG_CROP_WIDTH, crop->width, &ret);
+ cci_write(imx214->regmap, IMX214_REG_DIG_CROP_HEIGHT, crop->height, &ret);
+
+ switch (crop->width / format->width) {
+ case 1:
+ default:
+ bin_mode = IMX214_BINNING_NONE;
+ bin_type = IMX214_BINNING_1X1;
+ break;
+ case 2:
+ bin_mode = IMX214_BINNING_ENABLE;
+ bin_type = IMX214_BINNING_2X2;
+ break;
+ case 4:
+ bin_mode = IMX214_BINNING_ENABLE;
+ bin_type = IMX214_BINNING_4X4;
+ break;
+ }
+
+ cci_write(imx214->regmap, IMX214_REG_BINNING_MODE, bin_mode, &ret);
+ cci_write(imx214->regmap, IMX214_REG_BINNING_TYPE, bin_type, &ret);
+
+ cci_write(imx214->regmap, IMX214_REG_X_OUTPUT_SIZE, format->width, &ret);
+ cci_write(imx214->regmap, IMX214_REG_Y_OUTPUT_SIZE, format->height, &ret);
+
+ cci_write(imx214->regmap, IMX214_REG_CSI_DATA_FORMAT,
+ (bpp << 8) | bpp, &ret);
+ cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, bpp, &ret);
+
+ return ret;
+};
+
static int imx214_configure_lanes(struct imx214 *imx214)
{
return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
@@ -852,7 +916,8 @@ static int imx214_configure_lanes(struct imx214 *imx214)
IMX214_CSI_4_LANE_MODE, NULL);
};
-static int imx214_start_streaming(struct imx214 *imx214)
+static int imx214_start_streaming(struct imx214 *imx214,
+ struct v4l2_subdev_state *state)
{
const struct imx214_mode *mode;
int ret;
@@ -871,6 +936,14 @@ static int imx214_start_streaming(struct imx214 *imx214)
return ret;
}
+ /* Apply format and crop settings */
+ ret = imx214_set_framefmt(imx214, state);
+ if (ret) {
+ dev_err(imx214->dev, "%s failed to set frame format: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
mode = v4l2_find_nearest_size(imx214_modes,
ARRAY_SIZE(imx214_modes), width, height,
imx214->fmt.width, imx214->fmt.height);
@@ -922,7 +995,7 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
return ret;
state = v4l2_subdev_lock_and_get_active_state(subdev);
- ret = imx214_start_streaming(imx214);
+ ret = imx214_start_streaming(imx214, state);
v4l2_subdev_unlock_state(state);
if (ret < 0)
goto err_rpm_put;
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (8 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 09/13] media: i2c: imx214: Extract format and crop settings André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-12 15:16 ` Dave Stevenson
2024-09-02 21:54 ` [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control André Apitzsch via B4 Relay
` (2 subsequent siblings)
12 siblings, 2 replies; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
The imx214 sensor supports horizontal and vertical flipping. Add
appropriate controls to the driver.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 73 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 65 insertions(+), 8 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 733f55257585..4a1433728cd5 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -30,7 +30,6 @@
#define IMX214_DEFAULT_LINK_FREQ 480000000
#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
#define IMX214_FPS 30
-#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
/* V-TIMING internal */
#define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
@@ -186,6 +185,22 @@ static const char * const imx214_supply_name[] = {
#define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name)
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 imx214_mbus_formats[] = {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+};
+
struct imx214 {
struct device *dev;
struct clk *xclk;
@@ -202,6 +217,8 @@ struct imx214 {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hflip;
struct v4l2_ctrl *unit_size;
struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
@@ -339,7 +356,6 @@ static const struct cci_reg_sequence mode_table_common[] = {
/* global setting */
/* basic config */
- { IMX214_REG_ORIENTATION, 0 },
{ IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
{ IMX214_REG_FAST_STANDBY_CTRL, 1 },
{ IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
@@ -518,11 +534,29 @@ static int __maybe_unused imx214_power_off(struct device *dev)
return 0;
}
+/* Get bayer order based on flip setting. */
+static u32 imx214_get_format_code(struct imx214 *imx214, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx214_mbus_formats); i++)
+ if (imx214_mbus_formats[i] == code)
+ break;
+
+ if (i >= ARRAY_SIZE(imx214_mbus_formats))
+ i = 0;
+
+ i = (i & ~3) | (imx214->vflip->val ? 2 : 0) |
+ (imx214->hflip->val ? 1 : 0);
+
+ return imx214_mbus_formats[i];
+}
+
static void imx214_update_pad_format(struct imx214 *imx214,
const struct imx214_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
{
- fmt->code = IMX214_MBUS_CODE;
+ fmt->code = imx214_get_format_code(imx214, code);
fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
@@ -538,10 +572,12 @@ static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->index > 0)
+ struct imx214 *imx214 = to_imx214(sd);
+
+ if (code->index >= (ARRAY_SIZE(imx214_mbus_formats) / 4))
return -EINVAL;
- code->code = IMX214_MBUS_CODE;
+ code->code = imx214_get_format_code(imx214, imx214_mbus_formats[code->index * 4]);
return 0;
}
@@ -550,7 +586,11 @@ static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->code != IMX214_MBUS_CODE)
+ struct imx214 *imx214 = to_imx214(subdev);
+ u32 code;
+
+ code = imx214_get_format_code(imx214, fse->code);
+ if (fse->code != code)
return -EINVAL;
if (fse->index >= ARRAY_SIZE(imx214_modes))
@@ -708,6 +748,7 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
struct v4l2_subdev_format fmt = { };
fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
fmt.format.width = imx214_modes[0].width;
fmt.format.height = imx214_modes[0].height;
@@ -750,6 +791,11 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ cci_write(imx214->regmap, IMX214_REG_ORIENTATION,
+ imx214->hflip->val | imx214->vflip->val << 1, &ret);
+ break;
case V4L2_CID_VBLANK:
cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
format->height + ctrl->val, &ret);
@@ -788,7 +834,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return ret;
ctrl_hdlr = &imx214->ctrls;
- ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
+ ret = v4l2_ctrl_handler_init(&imx214->ctrls, 10);
if (ret)
return ret;
@@ -825,6 +871,16 @@ static int imx214_ctrls_init(struct imx214 *imx214)
IMX214_EXPOSURE_STEP,
exposure_def);
+ imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (imx214->hflip)
+ imx214->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx214->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (imx214->vflip)
+ imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
NULL,
V4L2_CID_UNIT_CELL_SIZE,
@@ -1034,6 +1090,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval_enum *fie)
{
+ struct imx214 *imx214 = to_imx214(subdev);
const struct imx214_mode *mode;
if (fie->index != 0)
@@ -1043,7 +1100,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
ARRAY_SIZE(imx214_modes), width, height,
fie->width, fie->height);
- fie->code = IMX214_MBUS_CODE;
+ fie->code = imx214_get_format_code(imx214, fie->code);
fie->width = mode->width;
fie->height = mode->height;
fie->interval.numerator = 1;
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (9 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 12/13] media: i2c: imx214: Verify chip ID André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 13/13] media: i2c: imx214: Add test pattern control André Apitzsch via B4 Relay
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
The imx214 sensor supports analogue gain up to 8x and digital gain up to
16x. Implement the corresponding controls in the driver. Default gain
values are not modified by this patch.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
With the analogue gain control added by this patch, the kernel log shows
the following message when closing megapixels and a similar one when
closing qcam (from libcamera):
[ 100.042856] ------------[ cut here ]------------
[ 100.042886] WARNING: CPU: 4 PID: 3444 at drivers/media/common/videobuf2/videobuf2-core.c:2182 __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
[ 100.042948] Modules linked in: rfcomm zstd zstd_compress zram zsmalloc rpmsg_wwan_ctrl q6voice_dai q6asm_dai q6voice q6afe_dai q6routing q6cvs q6adm q6asm q6cvp q6mvm snd_q6dsp_common q6voice_common q6afe q6core apr pdr_interface nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink algif_hash algif_skcipher af_alg bnep qcom_pd_mapper qcom_pdr_msg wcn36xx btqcomsmd btqca ipv6 wcnss_ctrl qcom_bam_dmux imx214 v4l2_cci ledtrig_pattern bmi160_i2c ak8975 leds_ktd202x bmi160_core ltr501 leds_sy7802 qcom_wcnss_pil qcom_camss qcom_q6v5_mss snd_soc_msm8916_digital snd_soc_msm8916_analog pm8xxx_vibrator v4l2_fwnode qcom_pil_info videobuf2_dma_sg qcom_common qcom_q6v5 videobuf2_memops videobuf2_v4l2 videobuf2_common i2c_qcom_cci leds_sgm3140 v4l2_flash_led_class led_class_flash v4l2_async videodev qcom_memshare mc usb_f_ncm u_ether panel_longcheer_truly_nt35695 atmel_mxt_ts smb1360 msm mdt_loader drm_exec drm_display_he
lper gpu_sched libcomposite
[ 100.043688] CPU: 4 UID: 10000 PID: 3444 Comm: megapixels Not tainted 6.11.0-rc3-msm8916 #312
[ 100.043716] Hardware name: BQ Aquaris M5 (Longcheer L9100) (DT)
[ 100.043730] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 100.043756] pc : __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
[ 100.043787] lr : __vb2_queue_cancel+0x28/0x2c0 [videobuf2_common]
[ 100.043815] sp : ffff80008450ba50
[ 100.043826] x29: ffff80008450ba50 x28: 0000000000000001 x27: ffff00000f946180
[ 100.043867] x26: 0000000000000000 x25: ffff00000f946780 x24: ffff00000f946910
[ 100.043906] x23: ffff00000175a620 x22: ffff0000036ddc90 x21: ffff0000036e4410
[ 100.043946] x20: ffff0000036e44b8 x19: ffff0000036e4410 x18: ffff80008450ba98
[ 100.043985] x17: ffffffffffffffff x16: 0000000000000000 x15: 0000000000000040
[ 100.044023] x14: 0256932925642338 x13: ffff00000f946200 x12: 0000000000000001
[ 100.044062] x11: ffff00000f946200 x10: 0000000000000a20 x9 : 0000000000000000
[ 100.044100] x8 : ffff0000bf964880 x7 : 0000000000000020 x6 : 0000000000000100
[ 100.044138] x5 : ffff0000036e4b68 x4 : 0000000000000000 x3 : ffff00000f946180
[ 100.044176] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 000000000000000f
[ 100.044214] Call trace:
[ 100.044226] __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
[ 100.044257] vb2_core_queue_release+0x20/0x74 [videobuf2_common]
[ 100.044285] _vb2_fop_release+0x68/0xb0 [videobuf2_v4l2]
[ 100.044314] vb2_fop_release+0x28/0x50 [videobuf2_v4l2]
[ 100.044341] video_release+0x20/0x40 [qcom_camss]
[ 100.044406] v4l2_release+0xb4/0xf4 [videodev]
[ 100.044481] __fput+0xbc/0x274
[ 100.044510] ____fput+0xc/0x14
[ 100.044533] task_work_run+0x78/0xc0
[ 100.044563] do_exit+0x2dc/0x8b0
[ 100.044590] do_group_exit+0x30/0x8c
[ 100.044615] get_signal+0x7b4/0x8a0
[ 100.044643] do_signal+0x94/0xd14
[ 100.044672] do_notify_resume+0xd0/0x120
[ 100.044697] el0_svc+0x44/0x60
[ 100.044730] el0t_64_sync_handler+0x118/0x124
[ 100.044753] el0t_64_sync+0x14c/0x150
[ 100.044775] ---[ end trace 0000000000000000 ]---
[ 100.044793] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 0 in active state
[ 100.045722] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 1 in active state
[ 100.046587] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 2 in active state
[ 100.047439] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 3 in active state
[ 100.048288] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 4 in active state
[ 100.049242] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 5 in active state
[ 100.050098] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 6 in active state
[ 100.050945] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 7 in active state
[ 100.051793] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 8 in active state
[ 100.052692] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 14 in active state
[ 100.053548] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 15 in active state
[ 100.054396] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 16 in active state
[ 100.055244] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 17 in active state
[ 100.056137] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 18 in active state
[ 100.056988] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 19 in active state
From the log it looks like the cause is in some other module and not in
the imx214 driver, that's why the patch wasn't dropped from this series.
---
drivers/media/i2c/imx214.c | 53 +++++++++++++++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 4a1433728cd5..ce6d8a90f4a1 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -53,12 +53,20 @@
/* Analog gain control */
#define IMX214_REG_ANALOG_GAIN CCI_REG16(0x0204)
#define IMX214_REG_SHORT_ANALOG_GAIN CCI_REG16(0x0216)
+#define IMX214_ANA_GAIN_MIN 0
+#define IMX214_ANA_GAIN_MAX 448
+#define IMX214_ANA_GAIN_STEP 1
+#define IMX214_ANA_GAIN_DEFAULT 0x0
/* Digital gain control */
#define IMX214_REG_DIG_GAIN_GREENR CCI_REG16(0x020e)
#define IMX214_REG_DIG_GAIN_RED CCI_REG16(0x0210)
#define IMX214_REG_DIG_GAIN_BLUE CCI_REG16(0x0212)
#define IMX214_REG_DIG_GAIN_GREENB CCI_REG16(0x0214)
+#define IMX214_DGTL_GAIN_MIN 0x0100
+#define IMX214_DGTL_GAIN_MAX 0x0fff
+#define IMX214_DGTL_GAIN_DEFAULT 0x0100
+#define IMX214_DGTL_GAIN_STEP 1
#define IMX214_REG_ORIENTATION CCI_REG8(0x0101)
@@ -271,13 +279,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
{ IMX214_REG_SHORT_EXPOSURE, 500 },
- { IMX214_REG_ANALOG_GAIN, 0 },
- { IMX214_REG_DIG_GAIN_GREENR, 256 },
- { IMX214_REG_DIG_GAIN_RED, 256 },
- { IMX214_REG_DIG_GAIN_BLUE, 256 },
- { IMX214_REG_DIG_GAIN_GREENB, 256 },
- { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
-
{ CCI_REG8(0x4170), 0x00 },
{ CCI_REG8(0x4171), 0x10 },
{ CCI_REG8(0x4176), 0x00 },
@@ -327,13 +328,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
{ IMX214_REG_SHORT_EXPOSURE, 500 },
- { IMX214_REG_ANALOG_GAIN, 0 },
- { IMX214_REG_DIG_GAIN_GREENR, 256 },
- { IMX214_REG_DIG_GAIN_RED, 256 },
- { IMX214_REG_DIG_GAIN_BLUE, 256 },
- { IMX214_REG_DIG_GAIN_GREENB, 256 },
- { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
-
{ CCI_REG8(0x4170), 0x00 },
{ CCI_REG8(0x4171), 0x10 },
{ CCI_REG8(0x4176), 0x00 },
@@ -757,6 +751,18 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
return 0;
}
+static int imx214_update_digital_gain(struct imx214 *imx214, u32 val)
+{
+ int ret = 0;
+
+ cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_GREENR, val, &ret);
+ cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_RED, val, &ret);
+ cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_BLUE, val, &ret);
+ cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_GREENB, val, &ret);
+
+ return ret;
+}
+
static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
{
struct imx214 *imx214 = container_of(ctrl->handler,
@@ -788,6 +794,15 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
return 0;
switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ cci_write(imx214->regmap, IMX214_REG_ANALOG_GAIN,
+ ctrl->val, &ret);
+ cci_write(imx214->regmap, IMX214_REG_SHORT_ANALOG_GAIN,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx214_update_digital_gain(imx214, ctrl->val);
+ break;
case V4L2_CID_EXPOSURE:
cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
break;
@@ -834,7 +849,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
return ret;
ctrl_hdlr = &imx214->ctrls;
- ret = v4l2_ctrl_handler_init(&imx214->ctrls, 10);
+ ret = v4l2_ctrl_handler_init(&imx214->ctrls, 12);
if (ret)
return ret;
@@ -871,6 +886,14 @@ static int imx214_ctrls_init(struct imx214 *imx214)
IMX214_EXPOSURE_STEP,
exposure_def);
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX214_ANA_GAIN_MIN, IMX214_ANA_GAIN_MAX,
+ IMX214_ANA_GAIN_STEP, IMX214_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX214_DGTL_GAIN_MIN, IMX214_DGTL_GAIN_MAX,
+ IMX214_DGTL_GAIN_STEP, IMX214_DGTL_GAIN_DEFAULT);
+
imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
if (imx214->hflip)
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 12/13] media: i2c: imx214: Verify chip ID
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (10 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 13/13] media: i2c: imx214: Add test pattern control André Apitzsch via B4 Relay
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
Check the chip ID and stop probing if it is no imx214 sensor.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index ce6d8a90f4a1..6493a9b9ea88 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -20,6 +20,10 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
+/* Chip ID */
+#define IMX214_REG_CHIP_ID CCI_REG16(0x0016)
+#define IMX214_CHIP_ID 0x0214
+
#define IMX214_REG_MODE_SELECT CCI_REG8(0x0100)
#define IMX214_MODE_STANDBY 0x00
#define IMX214_MODE_STREAMING 0x01
@@ -1168,6 +1172,27 @@ static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
imx214->supplies);
}
+/* Verify chip ID */
+static int imx214_identify_module(struct imx214 *imx214)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&imx214->sd);
+ int ret;
+ u64 val;
+
+ ret = cci_read(imx214->regmap, IMX214_REG_CHIP_ID, &val, NULL);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to read chip id %x\n",
+ IMX214_CHIP_ID);
+
+ if (val != IMX214_CHIP_ID)
+ return dev_err_probe(&client->dev, -EIO,
+ "chip id mismatch: %x!=%llx\n",
+ IMX214_CHIP_ID, val);
+
+ return 0;
+}
+
static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214)
{
struct fwnode_handle *endpoint;
@@ -1261,6 +1286,10 @@ static int imx214_probe(struct i2c_client *client)
*/
imx214_power_on(imx214->dev);
+ ret = imx214_identify_module(imx214);
+ if (ret)
+ goto error_power_off;
+
pm_runtime_set_active(imx214->dev);
pm_runtime_enable(imx214->dev);
pm_runtime_idle(imx214->dev);
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* [PATCH 13/13] media: i2c: imx214: Add test pattern control
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
` (11 preceding siblings ...)
2024-09-02 21:54 ` [PATCH 12/13] media: i2c: imx214: Verify chip ID André Apitzsch via B4 Relay
@ 2024-09-02 21:54 ` André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
12 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch via B4 Relay @ 2024-09-02 21:54 UTC (permalink / raw)
To: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab
Cc: ~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel,
André Apitzsch
From: André Apitzsch <git@apitzsch.eu>
This adds V4L2_CID_TEST_PATTERN control support.
Signed-off-by: André Apitzsch <git@apitzsch.eu>
---
drivers/media/i2c/imx214.c | 77 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 75 insertions(+), 2 deletions(-)
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
index 6493a9b9ea88..6d67c7b307bd 100644
--- a/drivers/media/i2c/imx214.c
+++ b/drivers/media/i2c/imx214.c
@@ -181,6 +181,23 @@
#define IMX214_REG_ATR_FAST_MOVE CCI_REG8(0x9300)
+/* Test Pattern Control */
+#define IMX214_REG_TEST_PATTERN CCI_REG16(0x0600)
+#define IMX214_TEST_PATTERN_DISABLE 0
+#define IMX214_TEST_PATTERN_SOLID_COLOR 1
+#define IMX214_TEST_PATTERN_COLOR_BARS 2
+#define IMX214_TEST_PATTERN_GREY_COLOR 3
+#define IMX214_TEST_PATTERN_PN9 4
+
+/* Test pattern colour components */
+#define IMX214_REG_TESTP_RED CCI_REG16(0x0602)
+#define IMX214_REG_TESTP_GREENR CCI_REG16(0x0604)
+#define IMX214_REG_TESTP_BLUE CCI_REG16(0x0606)
+#define IMX214_REG_TESTP_GREENB CCI_REG16(0x0608)
+#define IMX214_TESTP_COLOUR_MIN 0
+#define IMX214_TESTP_COLOUR_MAX 0x03ff
+#define IMX214_TESTP_COLOUR_STEP 1
+
/* IMX214 native and active pixel array size */
#define IMX214_NATIVE_WIDTH 4224U
#define IMX214_NATIVE_HEIGHT 3136U
@@ -213,6 +230,22 @@ static const u32 imx214_mbus_formats[] = {
MEDIA_BUS_FMT_SBGGR10_1X10,
};
+static const char * const imx214_test_pattern_menu[] = {
+ "Disabled",
+ "Color Bars",
+ "Solid Color",
+ "Grey Color Bars",
+ "PN9"
+};
+
+static const int imx214_test_pattern_val[] = {
+ IMX214_TEST_PATTERN_DISABLE,
+ IMX214_TEST_PATTERN_COLOR_BARS,
+ IMX214_TEST_PATTERN_SOLID_COLOR,
+ IMX214_TEST_PATTERN_GREY_COLOR,
+ IMX214_TEST_PATTERN_PN9,
+};
+
struct imx214 {
struct device *dev;
struct clk *xclk;
@@ -819,6 +852,26 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
format->height + ctrl->val, &ret);
break;
+ case V4L2_CID_TEST_PATTERN:
+ cci_write(imx214->regmap, IMX214_REG_TEST_PATTERN,
+ imx214_test_pattern_val[ctrl->val], &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_RED:
+ cci_write(imx214->regmap, IMX214_REG_TESTP_RED,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENR:
+ cci_write(imx214->regmap, IMX214_REG_TESTP_GREENR,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_BLUE:
+ cci_write(imx214->regmap, IMX214_REG_TESTP_BLUE,
+ ctrl->val, &ret);
+ break;
+ case V4L2_CID_TEST_PATTERN_GREENB:
+ cci_write(imx214->regmap, IMX214_REG_TESTP_GREENB,
+ ctrl->val, &ret);
+ break;
default:
ret = -EINVAL;
}
@@ -846,14 +899,14 @@ static int imx214_ctrls_init(struct imx214 *imx214)
struct v4l2_ctrl_handler *ctrl_hdlr;
int exposure_max, exposure_def;
int hblank;
- int ret;
+ int i, ret;
ret = v4l2_fwnode_device_parse(imx214->dev, &props);
if (ret < 0)
return ret;
ctrl_hdlr = &imx214->ctrls;
- ret = v4l2_ctrl_handler_init(&imx214->ctrls, 12);
+ ret = v4l2_ctrl_handler_init(&imx214->ctrls, 13);
if (ret)
return ret;
@@ -908,6 +961,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
if (imx214->vflip)
imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx214_test_pattern_menu) - 1,
+ 0, 0, imx214_test_pattern_menu);
+ for (i = 0; i < 4; i++) {
+ /*
+ * The assumption is that
+ * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
+ * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
+ * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
+ */
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
+ V4L2_CID_TEST_PATTERN_RED + i,
+ IMX214_TESTP_COLOUR_MIN,
+ IMX214_TESTP_COLOUR_MAX,
+ IMX214_TESTP_COLOUR_STEP,
+ IMX214_TESTP_COLOUR_MAX);
+ /* The "Solid color" pattern is white by default */
+ }
+
imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
NULL,
V4L2_CID_UNIT_CELL_SIZE,
--
2.46.0
^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH 13/13] media: i2c: imx214: Add test pattern control
2024-09-02 21:54 ` [PATCH 13/13] media: i2c: imx214: Add test pattern control André Apitzsch via B4 Relay
@ 2024-09-12 13:39 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:39 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> This adds V4L2_CID_TEST_PATTERN control support.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/i2c/imx214.c | 77 ++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 75 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 6493a9b9ea88..6d67c7b307bd 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -181,6 +181,23 @@
>
> #define IMX214_REG_ATR_FAST_MOVE CCI_REG8(0x9300)
>
> +/* Test Pattern Control */
> +#define IMX214_REG_TEST_PATTERN CCI_REG16(0x0600)
> +#define IMX214_TEST_PATTERN_DISABLE 0
> +#define IMX214_TEST_PATTERN_SOLID_COLOR 1
> +#define IMX214_TEST_PATTERN_COLOR_BARS 2
> +#define IMX214_TEST_PATTERN_GREY_COLOR 3
> +#define IMX214_TEST_PATTERN_PN9 4
> +
> +/* Test pattern colour components */
> +#define IMX214_REG_TESTP_RED CCI_REG16(0x0602)
> +#define IMX214_REG_TESTP_GREENR CCI_REG16(0x0604)
> +#define IMX214_REG_TESTP_BLUE CCI_REG16(0x0606)
> +#define IMX214_REG_TESTP_GREENB CCI_REG16(0x0608)
> +#define IMX214_TESTP_COLOUR_MIN 0
> +#define IMX214_TESTP_COLOUR_MAX 0x03ff
> +#define IMX214_TESTP_COLOUR_STEP 1
> +
> /* IMX214 native and active pixel array size */
> #define IMX214_NATIVE_WIDTH 4224U
> #define IMX214_NATIVE_HEIGHT 3136U
> @@ -213,6 +230,22 @@ static const u32 imx214_mbus_formats[] = {
> MEDIA_BUS_FMT_SBGGR10_1X10,
> };
>
> +static const char * const imx214_test_pattern_menu[] = {
> + "Disabled",
> + "Color Bars",
> + "Solid Color",
> + "Grey Color Bars",
> + "PN9"
> +};
> +
> +static const int imx214_test_pattern_val[] = {
> + IMX214_TEST_PATTERN_DISABLE,
> + IMX214_TEST_PATTERN_COLOR_BARS,
> + IMX214_TEST_PATTERN_SOLID_COLOR,
> + IMX214_TEST_PATTERN_GREY_COLOR,
> + IMX214_TEST_PATTERN_PN9,
> +};
> +
> struct imx214 {
> struct device *dev;
> struct clk *xclk;
> @@ -819,6 +852,26 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> format->height + ctrl->val, &ret);
> break;
> + case V4L2_CID_TEST_PATTERN:
> + cci_write(imx214->regmap, IMX214_REG_TEST_PATTERN,
> + imx214_test_pattern_val[ctrl->val], &ret);
> + break;
> + case V4L2_CID_TEST_PATTERN_RED:
> + cci_write(imx214->regmap, IMX214_REG_TESTP_RED,
> + ctrl->val, &ret);
> + break;
> + case V4L2_CID_TEST_PATTERN_GREENR:
> + cci_write(imx214->regmap, IMX214_REG_TESTP_GREENR,
> + ctrl->val, &ret);
> + break;
> + case V4L2_CID_TEST_PATTERN_BLUE:
> + cci_write(imx214->regmap, IMX214_REG_TESTP_BLUE,
> + ctrl->val, &ret);
> + break;
> + case V4L2_CID_TEST_PATTERN_GREENB:
> + cci_write(imx214->regmap, IMX214_REG_TESTP_GREENB,
> + ctrl->val, &ret);
> + break;
> default:
> ret = -EINVAL;
> }
> @@ -846,14 +899,14 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> struct v4l2_ctrl_handler *ctrl_hdlr;
> int exposure_max, exposure_def;
> int hblank;
> - int ret;
> + int i, ret;
>
> ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> if (ret < 0)
> return ret;
>
> ctrl_hdlr = &imx214->ctrls;
> - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 12);
> + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 13);
> if (ret)
> return ret;
>
> @@ -908,6 +961,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> if (imx214->vflip)
> imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
>
> + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_TEST_PATTERN,
> + ARRAY_SIZE(imx214_test_pattern_menu) - 1,
> + 0, 0, imx214_test_pattern_menu);
> + for (i = 0; i < 4; i++) {
> + /*
> + * The assumption is that
> + * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1
> + * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2
> + * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3
> + */
> + v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_TEST_PATTERN_RED + i,
> + IMX214_TESTP_COLOUR_MIN,
> + IMX214_TESTP_COLOUR_MAX,
> + IMX214_TESTP_COLOUR_STEP,
> + IMX214_TESTP_COLOUR_MAX);
> + /* The "Solid color" pattern is white by default */
> + }
> +
> imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> NULL,
> V4L2_CID_UNIT_CELL_SIZE,
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 12/13] media: i2c: imx214: Verify chip ID
2024-09-02 21:54 ` [PATCH 12/13] media: i2c: imx214: Verify chip ID André Apitzsch via B4 Relay
@ 2024-09-12 13:39 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:39 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Check the chip ID and stop probing if it is no imx214 sensor.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/i2c/imx214.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index ce6d8a90f4a1..6493a9b9ea88 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -20,6 +20,10 @@
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> +/* Chip ID */
> +#define IMX214_REG_CHIP_ID CCI_REG16(0x0016)
> +#define IMX214_CHIP_ID 0x0214
> +
> #define IMX214_REG_MODE_SELECT CCI_REG8(0x0100)
> #define IMX214_MODE_STANDBY 0x00
> #define IMX214_MODE_STREAMING 0x01
> @@ -1168,6 +1172,27 @@ static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
> imx214->supplies);
> }
>
> +/* Verify chip ID */
> +static int imx214_identify_module(struct imx214 *imx214)
> +{
> + struct i2c_client *client = v4l2_get_subdevdata(&imx214->sd);
> + int ret;
> + u64 val;
> +
> + ret = cci_read(imx214->regmap, IMX214_REG_CHIP_ID, &val, NULL);
> + if (ret)
> + return dev_err_probe(&client->dev, ret,
> + "failed to read chip id %x\n",
> + IMX214_CHIP_ID);
> +
> + if (val != IMX214_CHIP_ID)
> + return dev_err_probe(&client->dev, -EIO,
> + "chip id mismatch: %x!=%llx\n",
> + IMX214_CHIP_ID, val);
> +
> + return 0;
> +}
> +
> static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214)
> {
> struct fwnode_handle *endpoint;
> @@ -1261,6 +1286,10 @@ static int imx214_probe(struct i2c_client *client)
> */
> imx214_power_on(imx214->dev);
>
> + ret = imx214_identify_module(imx214);
> + if (ret)
> + goto error_power_off;
> +
> pm_runtime_set_active(imx214->dev);
> pm_runtime_enable(imx214->dev);
> pm_runtime_idle(imx214->dev);
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control
2024-09-02 21:54 ` [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control André Apitzsch via B4 Relay
@ 2024-09-12 13:39 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:39 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> The imx214 sensor supports analogue gain up to 8x and digital gain up to
> 16x. Implement the corresponding controls in the driver. Default gain
> values are not modified by this patch.
>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
>
> ---
>
> With the analogue gain control added by this patch, the kernel log shows
> the following message when closing megapixels and a similar one when
> closing qcam (from libcamera):
>
> [ 100.042856] ------------[ cut here ]------------
> [ 100.042886] WARNING: CPU: 4 PID: 3444 at drivers/media/common/videobuf2/videobuf2-core.c:2182 __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
> [ 100.042948] Modules linked in: rfcomm zstd zstd_compress zram zsmalloc rpmsg_wwan_ctrl q6voice_dai q6asm_dai q6voice q6afe_dai q6routing q6cvs q6adm q6asm q6cvp q6mvm snd_q6dsp_common q6voice_common q6afe q6core apr pdr_interface nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables nfnetlink algif_hash algif_skcipher af_alg bnep qcom_pd_mapper qcom_pdr_msg wcn36xx btqcomsmd btqca ipv6 wcnss_ctrl qcom_bam_dmux imx214 v4l2_cci ledtrig_pattern bmi160_i2c ak8975 leds_ktd202x bmi160_core ltr501 leds_sy7802 qcom_wcnss_pil qcom_camss qcom_q6v5_mss snd_soc_msm8916_digital snd_soc_msm8916_analog pm8xxx_vibrator v4l2_fwnode qcom_pil_info videobuf2_dma_sg qcom_common qcom_q6v5 videobuf2_memops videobuf2_v4l2 videobuf2_common i2c_qcom_cci leds_sgm3140 v4l2_flash_led_class led_class_flash v4l2_async videodev qcom_memshare mc usb_f_ncm u_ether panel_longcheer_truly_nt35695 atmel_mxt_ts smb1360 msm mdt_loader drm_exec drm_display_he
> lper gpu_sched libcomposite
> [ 100.043688] CPU: 4 UID: 10000 PID: 3444 Comm: megapixels Not tainted 6.11.0-rc3-msm8916 #312
> [ 100.043716] Hardware name: BQ Aquaris M5 (Longcheer L9100) (DT)
> [ 100.043730] pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> [ 100.043756] pc : __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
> [ 100.043787] lr : __vb2_queue_cancel+0x28/0x2c0 [videobuf2_common]
> [ 100.043815] sp : ffff80008450ba50
> [ 100.043826] x29: ffff80008450ba50 x28: 0000000000000001 x27: ffff00000f946180
> [ 100.043867] x26: 0000000000000000 x25: ffff00000f946780 x24: ffff00000f946910
> [ 100.043906] x23: ffff00000175a620 x22: ffff0000036ddc90 x21: ffff0000036e4410
> [ 100.043946] x20: ffff0000036e44b8 x19: ffff0000036e4410 x18: ffff80008450ba98
> [ 100.043985] x17: ffffffffffffffff x16: 0000000000000000 x15: 0000000000000040
> [ 100.044023] x14: 0256932925642338 x13: ffff00000f946200 x12: 0000000000000001
> [ 100.044062] x11: ffff00000f946200 x10: 0000000000000a20 x9 : 0000000000000000
> [ 100.044100] x8 : ffff0000bf964880 x7 : 0000000000000020 x6 : 0000000000000100
> [ 100.044138] x5 : ffff0000036e4b68 x4 : 0000000000000000 x3 : ffff00000f946180
> [ 100.044176] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 000000000000000f
> [ 100.044214] Call trace:
> [ 100.044226] __vb2_queue_cancel+0x228/0x2c0 [videobuf2_common]
> [ 100.044257] vb2_core_queue_release+0x20/0x74 [videobuf2_common]
> [ 100.044285] _vb2_fop_release+0x68/0xb0 [videobuf2_v4l2]
> [ 100.044314] vb2_fop_release+0x28/0x50 [videobuf2_v4l2]
> [ 100.044341] video_release+0x20/0x40 [qcom_camss]
> [ 100.044406] v4l2_release+0xb4/0xf4 [videodev]
> [ 100.044481] __fput+0xbc/0x274
> [ 100.044510] ____fput+0xc/0x14
> [ 100.044533] task_work_run+0x78/0xc0
> [ 100.044563] do_exit+0x2dc/0x8b0
> [ 100.044590] do_group_exit+0x30/0x8c
> [ 100.044615] get_signal+0x7b4/0x8a0
> [ 100.044643] do_signal+0x94/0xd14
> [ 100.044672] do_notify_resume+0xd0/0x120
> [ 100.044697] el0_svc+0x44/0x60
> [ 100.044730] el0t_64_sync_handler+0x118/0x124
> [ 100.044753] el0t_64_sync+0x14c/0x150
> [ 100.044775] ---[ end trace 0000000000000000 ]---
> [ 100.044793] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 0 in active state
> [ 100.045722] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 1 in active state
> [ 100.046587] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 2 in active state
> [ 100.047439] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 3 in active state
> [ 100.048288] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 4 in active state
> [ 100.049242] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 5 in active state
> [ 100.050098] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 6 in active state
> [ 100.050945] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 7 in active state
> [ 100.051793] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 8 in active state
> [ 100.052692] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 14 in active state
> [ 100.053548] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 15 in active state
> [ 100.054396] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 16 in active state
> [ 100.055244] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 17 in active state
> [ 100.056137] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 18 in active state
> [ 100.056988] videobuf2_common: driver bug: stop_streaming operation is leaving buffer 19 in active state
>
> From the log it looks like the cause is in some other module and not in
> the imx214 driver, that's why the patch wasn't dropped from this series.
> ---
> drivers/media/i2c/imx214.c | 53 +++++++++++++++++++++++++++++++++-------------
> 1 file changed, 38 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 4a1433728cd5..ce6d8a90f4a1 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -53,12 +53,20 @@
> /* Analog gain control */
> #define IMX214_REG_ANALOG_GAIN CCI_REG16(0x0204)
> #define IMX214_REG_SHORT_ANALOG_GAIN CCI_REG16(0x0216)
> +#define IMX214_ANA_GAIN_MIN 0
> +#define IMX214_ANA_GAIN_MAX 448
> +#define IMX214_ANA_GAIN_STEP 1
> +#define IMX214_ANA_GAIN_DEFAULT 0x0
>
> /* Digital gain control */
> #define IMX214_REG_DIG_GAIN_GREENR CCI_REG16(0x020e)
> #define IMX214_REG_DIG_GAIN_RED CCI_REG16(0x0210)
> #define IMX214_REG_DIG_GAIN_BLUE CCI_REG16(0x0212)
> #define IMX214_REG_DIG_GAIN_GREENB CCI_REG16(0x0214)
> +#define IMX214_DGTL_GAIN_MIN 0x0100
> +#define IMX214_DGTL_GAIN_MAX 0x0fff
> +#define IMX214_DGTL_GAIN_DEFAULT 0x0100
> +#define IMX214_DGTL_GAIN_STEP 1
>
> #define IMX214_REG_ORIENTATION CCI_REG8(0x0101)
>
> @@ -271,13 +279,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
>
> { IMX214_REG_SHORT_EXPOSURE, 500 },
>
> - { IMX214_REG_ANALOG_GAIN, 0 },
> - { IMX214_REG_DIG_GAIN_GREENR, 256 },
> - { IMX214_REG_DIG_GAIN_RED, 256 },
> - { IMX214_REG_DIG_GAIN_BLUE, 256 },
> - { IMX214_REG_DIG_GAIN_GREENB, 256 },
> - { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
> -
> { CCI_REG8(0x4170), 0x00 },
> { CCI_REG8(0x4171), 0x10 },
> { CCI_REG8(0x4176), 0x00 },
> @@ -327,13 +328,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
>
> { IMX214_REG_SHORT_EXPOSURE, 500 },
>
> - { IMX214_REG_ANALOG_GAIN, 0 },
> - { IMX214_REG_DIG_GAIN_GREENR, 256 },
> - { IMX214_REG_DIG_GAIN_RED, 256 },
> - { IMX214_REG_DIG_GAIN_BLUE, 256 },
> - { IMX214_REG_DIG_GAIN_GREENB, 256 },
> - { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
> -
> { CCI_REG8(0x4170), 0x00 },
> { CCI_REG8(0x4171), 0x10 },
> { CCI_REG8(0x4176), 0x00 },
> @@ -757,6 +751,18 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
> return 0;
> }
>
> +static int imx214_update_digital_gain(struct imx214 *imx214, u32 val)
> +{
> + int ret = 0;
> +
> + cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_GREENR, val, &ret);
> + cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_RED, val, &ret);
> + cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_BLUE, val, &ret);
> + cci_write(imx214->regmap, IMX214_REG_DIG_GAIN_GREENB, val, &ret);
> +
> + return ret;
> +}
> +
> static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> {
> struct imx214 *imx214 = container_of(ctrl->handler,
> @@ -788,6 +794,15 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> return 0;
>
> switch (ctrl->id) {
> + case V4L2_CID_ANALOGUE_GAIN:
> + cci_write(imx214->regmap, IMX214_REG_ANALOG_GAIN,
> + ctrl->val, &ret);
> + cci_write(imx214->regmap, IMX214_REG_SHORT_ANALOG_GAIN,
> + ctrl->val, &ret);
> + break;
> + case V4L2_CID_DIGITAL_GAIN:
> + ret = imx214_update_digital_gain(imx214, ctrl->val);
> + break;
> case V4L2_CID_EXPOSURE:
> cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> break;
> @@ -834,7 +849,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return ret;
>
> ctrl_hdlr = &imx214->ctrls;
> - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 10);
> + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 12);
> if (ret)
> return ret;
>
> @@ -871,6 +886,14 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> IMX214_EXPOSURE_STEP,
> exposure_def);
>
> + v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
> + IMX214_ANA_GAIN_MIN, IMX214_ANA_GAIN_MAX,
> + IMX214_ANA_GAIN_STEP, IMX214_ANA_GAIN_DEFAULT);
> +
> + v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
> + IMX214_DGTL_GAIN_MIN, IMX214_DGTL_GAIN_MAX,
> + IMX214_DGTL_GAIN_STEP, IMX214_DGTL_GAIN_DEFAULT);
> +
> imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> V4L2_CID_HFLIP, 0, 1, 1, 0);
> if (imx214->hflip)
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-09-02 21:54 ` [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-12 14:51 ` Dave Stevenson
0 siblings, 1 reply; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi
Arent you missing some chage in enum_frame_interval?
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Add vblank control to allow changing the framerate /
> higher exposure values.
>
> The vblank and hblank controls are needed for libcamera support.
>
> While at it, fix the minimal exposure time according to the datasheet.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 112 ++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 91 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 3b422cddbdce..9f5a57aebb86 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -34,11 +34,18 @@
>
> /* V-TIMING internal */
> #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> +#define IMX214_VTS_MAX 0xffff
> +
> +#define IMX214_VBLANK_MIN 4
> +
> +/* HBLANK control - read only */
> +#define IMX214_PPL_DEFAULT 5008
>
> /* Exposure control */
> #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> -#define IMX214_EXPOSURE_MIN 0
> -#define IMX214_EXPOSURE_MAX 3184
> +#define IMX214_EXPOSURE_OFFSET 10
> +#define IMX214_EXPOSURE_MIN 1
> +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX - IMX214_EXPOSURE_OFFSET)
> #define IMX214_EXPOSURE_STEP 1
> #define IMX214_EXPOSURE_DEFAULT 3184
> #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> @@ -189,6 +196,8 @@ struct imx214 {
> struct v4l2_ctrl_handler ctrls;
> struct v4l2_ctrl *pixel_rate;
> struct v4l2_ctrl *link_freq;
> + struct v4l2_ctrl *vblank;
> + struct v4l2_ctrl *hblank;
> struct v4l2_ctrl *exposure;
> struct v4l2_ctrl *unit_size;
>
> @@ -205,8 +214,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> { IMX214_REG_X_ADD_STA, 56 },
> { IMX214_REG_Y_ADD_STA, 408 },
> { IMX214_REG_X_ADD_END, 4151 },
> @@ -277,8 +284,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> { IMX214_REG_X_ADD_STA, 1144 },
> { IMX214_REG_Y_ADD_STA, 1020 },
> { IMX214_REG_X_ADD_END, 3063 },
> @@ -362,6 +367,7 @@ static const struct cci_reg_sequence mode_table_common[] = {
> { IMX214_REG_ORIENTATION, 0 },
> { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> { CCI_REG8(0x4550), 0x02 },
> { CCI_REG8(0x4601), 0x00 },
> { CCI_REG8(0x4642), 0x05 },
> @@ -465,18 +471,24 @@ static const struct cci_reg_sequence mode_table_common[] = {
> static const struct imx214_mode {
> u32 width;
> u32 height;
> +
> + /* V-timing */
> + unsigned int vts_def;
> +
> unsigned int num_of_regs;
> const struct cci_reg_sequence *reg_table;
> } imx214_modes[] = {
> {
> .width = 4096,
> .height = 2304,
> + .vts_def = 3194,
> .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> .reg_table = mode_4096x2304,
> },
> {
> .width = 1920,
> .height = 1080,
> + .vts_def = 3194,
> .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> .reg_table = mode_1920x1080,
> },
> @@ -629,6 +641,37 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> __crop->width = mode->width;
> __crop->height = mode->height;
>
> + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> + int exposure_max;
> + int exposure_def;
> + int hblank;
> +
> + /* Update limits and set FPS to default */
> + __v4l2_ctrl_modify_range(imx214->vblank, IMX214_VBLANK_MIN,
> + IMX214_VTS_MAX - mode->height, 1,
> + mode->vts_def - mode->height);
> + __v4l2_ctrl_s_ctrl(imx214->vblank,
> + mode->vts_def - mode->height);
> +
> + /* Update max exposure while meeting expected vblanking */
> + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> + exposure_def = (exposure_max < IMX214_EXPOSURE_DEFAULT) ?
> + exposure_max : IMX214_EXPOSURE_DEFAULT;
> + __v4l2_ctrl_modify_range(imx214->exposure,
> + imx214->exposure->minimum,
> + exposure_max, imx214->exposure->step,
> + exposure_def);
> +
> + /*
> + * Currently PPL is fixed to IMX214_PPL_DEFAULT, so hblank
> + * depends on mode->width only, and is not changeble in any
> + * way other than changing the mode.
> + */
> + hblank = IMX214_PPL_DEFAULT - mode->width;
> + __v4l2_ctrl_modify_range(imx214->hblank, hblank, hblank, 1,
> + hblank);
> + }
> +
> return 0;
> }
>
> @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> {
> struct imx214 *imx214 = container_of(ctrl->handler,
> struct imx214, ctrls);
> + const struct v4l2_mbus_framefmt *format;
> + struct v4l2_subdev_state *state;
> int ret;
>
> + state = v4l2_subdev_get_locked_active_state(&imx214->sd);
> + format = v4l2_subdev_state_get_format(state, 0);
> +
> + if (ctrl->id == V4L2_CID_VBLANK) {
> + int exposure_max, exposure_def;
> +
> + /* Update max exposure while meeting expected vblanking */
> + exposure_max = format->height + ctrl->val - IMX214_EXPOSURE_OFFSET;
> + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> + __v4l2_ctrl_modify_range(imx214->exposure,
> + imx214->exposure->minimum,
> + exposure_max, imx214->exposure->step,
> + exposure_def);
> + }
> +
> /*
> * Applying V4L2 control value only happens
> * when power is up for streaming
> @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> case V4L2_CID_EXPOSURE:
> cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> break;
> -
> + case V4L2_CID_VBLANK:
> + cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> + format->height + ctrl->val, &ret);
> + break;
> default:
> ret = -EINVAL;
> }
> @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> .width = 1120,
> .height = 1120,
> };
> + const struct imx214_mode *mode = &imx214_modes[0];
> struct v4l2_fwnode_device_properties props;
> struct v4l2_ctrl_handler *ctrl_hdlr;
> + int exposure_max, exposure_def;
> + int hblank;
> int ret;
>
> ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return ret;
>
> ctrl_hdlr = &imx214->ctrls;
> - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> if (ret)
> return ret;
>
> @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> if (imx214->link_freq)
> imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
>
> - /*
> - * WARNING!
> - * Values obtained reverse engineering blobs and/or devices.
> - * Ranges and functionality might be wrong.
> - *
> - * Sony, please release some register set documentation for the
> - * device.
> - *
> - * Yours sincerely, Ricardo.
> - */
I would like to keep this comment until there is a public document available.
> + /* Initial vblank/hblank/exposure parameters based on current mode */
> + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_VBLANK, IMX214_VBLANK_MIN,
> + IMX214_VTS_MAX - mode->height, 1,
> + mode->vts_def - mode->height);
> +
> + hblank = IMX214_PPL_DEFAULT - mode->width;
> + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_HBLANK, hblank, hblank,
> + 1, hblank);
> + if (imx214->hblank)
> + imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
> + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> V4L2_CID_EXPOSURE,
> - IMX214_EXPOSURE_MIN,
> - IMX214_EXPOSURE_MAX,
> + IMX214_EXPOSURE_MIN, exposure_max,
> IMX214_EXPOSURE_STEP,
> - IMX214_EXPOSURE_DEFAULT);
> + exposure_def);
>
> imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> NULL,
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls
2024-09-02 21:54 ` [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-12 15:16 ` Dave Stevenson
1 sibling, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> The imx214 sensor supports horizontal and vertical flipping. Add
> appropriate controls to the driver.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 73 +++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 65 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 733f55257585..4a1433728cd5 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -30,7 +30,6 @@
> #define IMX214_DEFAULT_LINK_FREQ 480000000
> #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
> #define IMX214_FPS 30
> -#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
>
> /* V-TIMING internal */
> #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> @@ -186,6 +185,22 @@ static const char * const imx214_supply_name[] = {
>
> #define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name)
>
> +/*
> + * The supported formats.
> + * This table MUST contain 4 entries per format, to cover the various flip
> + * combinations in the order
> + * - no flip
> + * - h flip
> + * - v flip
> + * - h&v flips
> + */
> +static const u32 imx214_mbus_formats[] = {
> + MEDIA_BUS_FMT_SRGGB10_1X10,
> + MEDIA_BUS_FMT_SGRBG10_1X10,
> + MEDIA_BUS_FMT_SGBRG10_1X10,
> + MEDIA_BUS_FMT_SBGGR10_1X10,
> +};
> +
> struct imx214 {
> struct device *dev;
> struct clk *xclk;
> @@ -202,6 +217,8 @@ struct imx214 {
> struct v4l2_ctrl *vblank;
> struct v4l2_ctrl *hblank;
> struct v4l2_ctrl *exposure;
> + struct v4l2_ctrl *vflip;
> + struct v4l2_ctrl *hflip;
> struct v4l2_ctrl *unit_size;
>
> struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
> @@ -339,7 +356,6 @@ static const struct cci_reg_sequence mode_table_common[] = {
>
> /* global setting */
> /* basic config */
> - { IMX214_REG_ORIENTATION, 0 },
> { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> @@ -518,11 +534,29 @@ static int __maybe_unused imx214_power_off(struct device *dev)
> return 0;
> }
>
> +/* Get bayer order based on flip setting. */
> +static u32 imx214_get_format_code(struct imx214 *imx214, u32 code)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(imx214_mbus_formats); i++)
> + if (imx214_mbus_formats[i] == code)
> + break;
> +
> + if (i >= ARRAY_SIZE(imx214_mbus_formats))
> + i = 0;
i will have values between 0 and 3, so (i & ~3) is always 0.
You can remove the loop and the code argument.
> +
> + i = (i & ~3) | (imx214->vflip->val ? 2 : 0) |
> + (imx214->hflip->val ? 1 : 0);
> +
> + return imx214_mbus_formats[i];
> +}
> +
> static void imx214_update_pad_format(struct imx214 *imx214,
> const struct imx214_mode *mode,
> struct v4l2_mbus_framefmt *fmt, u32 code)
> {
> - fmt->code = IMX214_MBUS_CODE;
> + fmt->code = imx214_get_format_code(imx214, code);
> fmt->width = mode->width;
> fmt->height = mode->height;
> fmt->field = V4L2_FIELD_NONE;
> @@ -538,10 +572,12 @@ static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_mbus_code_enum *code)
> {
> - if (code->index > 0)
> + struct imx214 *imx214 = to_imx214(sd);
> +
> + if (code->index >= (ARRAY_SIZE(imx214_mbus_formats) / 4))
> return -EINVAL;
>
> - code->code = IMX214_MBUS_CODE;
> + code->code = imx214_get_format_code(imx214, imx214_mbus_formats[code->index * 4]);
>
> return 0;
> }
> @@ -550,7 +586,11 @@ static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_frame_size_enum *fse)
> {
> - if (fse->code != IMX214_MBUS_CODE)
> + struct imx214 *imx214 = to_imx214(subdev);
> + u32 code;
> +
> + code = imx214_get_format_code(imx214, fse->code);
> + if (fse->code != code)
> return -EINVAL;
>
> if (fse->index >= ARRAY_SIZE(imx214_modes))
> @@ -708,6 +748,7 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
> struct v4l2_subdev_format fmt = { };
>
> fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
> + fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
> fmt.format.width = imx214_modes[0].width;
> fmt.format.height = imx214_modes[0].height;
>
> @@ -750,6 +791,11 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> case V4L2_CID_EXPOSURE:
> cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> break;
> + case V4L2_CID_HFLIP:
> + case V4L2_CID_VFLIP:
> + cci_write(imx214->regmap, IMX214_REG_ORIENTATION,
> + imx214->hflip->val | imx214->vflip->val << 1, &ret);
> + break;
> case V4L2_CID_VBLANK:
> cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> format->height + ctrl->val, &ret);
> @@ -788,7 +834,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return ret;
>
> ctrl_hdlr = &imx214->ctrls;
> - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 10);
> if (ret)
> return ret;
>
> @@ -825,6 +871,16 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> IMX214_EXPOSURE_STEP,
> exposure_def);
>
> + imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_HFLIP, 0, 1, 1, 0);
> + if (imx214->hflip)
> + imx214->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> +
> + imx214->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_VFLIP, 0, 1, 1, 0);
> + if (imx214->vflip)
> + imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> +
> imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> NULL,
> V4L2_CID_UNIT_CELL_SIZE,
> @@ -1034,6 +1090,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_frame_interval_enum *fie)
> {
> + struct imx214 *imx214 = to_imx214(subdev);
> const struct imx214_mode *mode;
>
> if (fie->index != 0)
> @@ -1043,7 +1100,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
> ARRAY_SIZE(imx214_modes), width, height,
> fie->width, fie->height);
>
> - fie->code = IMX214_MBUS_CODE;
> + fie->code = imx214_get_format_code(imx214, fie->code);
> fie->width = mode->width;
> fie->height = mode->height;
> fie->interval.numerator = 1;
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 09/13] media: i2c: imx214: Extract format and crop settings
2024-09-02 21:54 ` [PATCH 09/13] media: i2c: imx214: Extract format and crop settings André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-10-06 21:28 ` André
0 siblings, 1 reply; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:54 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Remove format and crop settings from register sequences and set them
> programmatically.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 137 ++++++++++++++++++++++++++++++++++-----------
> 1 file changed, 105 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 9f5a57aebb86..733f55257585 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -132,6 +132,9 @@
> #define IMX214_BINNING_NONE 0
> #define IMX214_BINNING_ENABLE 1
> #define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
> +#define IMX214_BINNING_1X1 0
> +#define IMX214_BINNING_2X2 0x22
> +#define IMX214_BINNING_4X4 0x44
> #define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
> #define IMX214_BINNING_AVERAGE 0x00
> #define IMX214_BINNING_SUMMED 0x01
> @@ -214,36 +217,22 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_X_ADD_STA, 56 },
> - { IMX214_REG_Y_ADD_STA, 408 },
> - { IMX214_REG_X_ADD_END, 4151 },
> - { IMX214_REG_Y_ADD_END, 2711 },
> { IMX214_REG_X_EVEN_INC, 1 },
> { IMX214_REG_X_ODD_INC, 1 },
> { IMX214_REG_Y_EVEN_INC, 1 },
> { IMX214_REG_Y_ODD_INC, 1 },
> - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> - { IMX214_REG_BINNING_TYPE, 0 },
> { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> - { IMX214_REG_X_OUTPUT_SIZE, 4096 },
> - { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
> { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> { IMX214_REG_SCALE_M, 2 },
> - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_WIDTH, 4096 },
> - { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
>
> { IMX214_REG_VTPXCK_DIV, 5 },
> { IMX214_REG_VTSYCK_DIV, 2 },
> { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> { IMX214_REG_PLL_VT_MPY, 150 },
> - { IMX214_REG_OPPXCK_DIV, 10 },
> { IMX214_REG_OPSYCK_DIV, 1 },
> { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
>
> @@ -284,36 +273,22 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> - { IMX214_REG_X_ADD_STA, 1144 },
> - { IMX214_REG_Y_ADD_STA, 1020 },
> - { IMX214_REG_X_ADD_END, 3063 },
> - { IMX214_REG_Y_ADD_END, 2099 },
> { IMX214_REG_X_EVEN_INC, 1 },
> { IMX214_REG_X_ODD_INC, 1 },
> { IMX214_REG_Y_EVEN_INC, 1 },
> { IMX214_REG_Y_ODD_INC, 1 },
> - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> - { IMX214_REG_BINNING_TYPE, 0 },
> { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> - { IMX214_REG_X_OUTPUT_SIZE, 1920 },
> - { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
> { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> { IMX214_REG_SCALE_M, 2 },
> - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> - { IMX214_REG_DIG_CROP_WIDTH, 1920 },
> - { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
>
> { IMX214_REG_VTPXCK_DIV, 5 },
> { IMX214_REG_VTSYCK_DIV, 2 },
> { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> { IMX214_REG_PLL_VT_MPY, 150 },
> - { IMX214_REG_OPPXCK_DIV, 10 },
> { IMX214_REG_OPSYCK_DIV, 1 },
> { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
>
> @@ -626,6 +601,7 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> struct v4l2_mbus_framefmt *__format;
> struct v4l2_rect *__crop;
> const struct imx214_mode *mode;
> + unsigned int bin_h, bin_v, bin;
>
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> @@ -637,9 +613,32 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> __format = v4l2_subdev_state_get_format(sd_state, 0);
> *__format = format->format;
>
> + /*
> + * Use binning to maximize the crop rectangle size, and centre it in the
> + * sensor.
> + */
We only support two modes. Wouldn't it be easier to add a new
"binning" field to imx124_mode?
> + bin_h = IMX214_PIXEL_ARRAY_WIDTH / __format->width;
> + bin_v = IMX214_PIXEL_ARRAY_HEIGHT / __format->height;
> +
> + switch (min(bin_h, bin_v)) {
> + case 1:
> + bin = 1;
> + break;
> + case 2:
> + case 3:
> + bin = 2;
> + break;
> + case 4:
> + default:
> + bin = 4;
> + break;
> + }
> +
> __crop = v4l2_subdev_state_get_crop(sd_state, 0);
> - __crop->width = mode->width;
> - __crop->height = mode->height;
> + __crop->width = __format->width * bin;
> + __crop->height = __format->height * bin;
> + __crop->left = (IMX214_NATIVE_WIDTH - __crop->width) / 2;
> + __crop->top = (IMX214_NATIVE_HEIGHT - __crop->height) / 2;
>
> if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> int exposure_max;
> @@ -845,6 +844,71 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return 0;
> };
>
> +static int imx214_set_framefmt(struct imx214 *imx214,
> + struct v4l2_subdev_state *state)
> +{
> + const struct v4l2_mbus_framefmt *format;
> + const struct v4l2_rect *crop;
> + unsigned int bpp;
> + u64 bin_mode;
> + u64 bin_type;
> + int ret = 0;
> +
> + format = v4l2_subdev_state_get_format(state, 0);
> + crop = v4l2_subdev_state_get_crop(state, 0);
> +
This code does not do anything, bpp is always 10.
We can remove the switch and setting IMX214_REG_CSI_DATA_FORMAT
IMX214_REG_OPPXCK_DIV programmatically
> + switch (format->code) {
> + case MEDIA_BUS_FMT_SRGGB10_1X10:
> + case MEDIA_BUS_FMT_SGRBG10_1X10:
> + case MEDIA_BUS_FMT_SGBRG10_1X10:
> + case MEDIA_BUS_FMT_SBGGR10_1X10:
> + default:
> + bpp = 10;
> + break;
> + }
> +
> + cci_write(imx214->regmap, IMX214_REG_X_ADD_STA,
> + crop->left - IMX214_PIXEL_ARRAY_LEFT, &ret);
> + cci_write(imx214->regmap, IMX214_REG_X_ADD_END,
> + crop->left - IMX214_PIXEL_ARRAY_LEFT + crop->width - 1, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_ADD_STA,
> + crop->top - IMX214_PIXEL_ARRAY_TOP, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_ADD_END,
> + crop->top - IMX214_PIXEL_ARRAY_TOP + crop->height - 1, &ret);
> +
> + /* Proper setting is required even if cropping is not used */
> + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_WIDTH, crop->width, &ret);
> + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_HEIGHT, crop->height, &ret);
> +
> + switch (crop->width / format->width) {
> + case 1:
> + default:
> + bin_mode = IMX214_BINNING_NONE;
> + bin_type = IMX214_BINNING_1X1;
> + break;
> + case 2:
> + bin_mode = IMX214_BINNING_ENABLE;
> + bin_type = IMX214_BINNING_2X2;
> + break;
> + case 4:
> + bin_mode = IMX214_BINNING_ENABLE;
> + bin_type = IMX214_BINNING_4X4;
> + break;
> + }
> +
> + cci_write(imx214->regmap, IMX214_REG_BINNING_MODE, bin_mode, &ret);
> + cci_write(imx214->regmap, IMX214_REG_BINNING_TYPE, bin_type, &ret);
> +
> + cci_write(imx214->regmap, IMX214_REG_X_OUTPUT_SIZE, format->width, &ret);
> + cci_write(imx214->regmap, IMX214_REG_Y_OUTPUT_SIZE, format->height, &ret);
> +
> + cci_write(imx214->regmap, IMX214_REG_CSI_DATA_FORMAT,
> + (bpp << 8) | bpp, &ret);
> + cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, bpp, &ret);
> +
> + return ret;
> +};
> +
> static int imx214_configure_lanes(struct imx214 *imx214)
> {
> return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
> @@ -852,7 +916,8 @@ static int imx214_configure_lanes(struct imx214 *imx214)
> IMX214_CSI_4_LANE_MODE, NULL);
> };
>
> -static int imx214_start_streaming(struct imx214 *imx214)
> +static int imx214_start_streaming(struct imx214 *imx214,
> + struct v4l2_subdev_state *state)
> {
> const struct imx214_mode *mode;
> int ret;
> @@ -871,6 +936,14 @@ static int imx214_start_streaming(struct imx214 *imx214)
> return ret;
> }
>
> + /* Apply format and crop settings */
> + ret = imx214_set_framefmt(imx214, state);
> + if (ret) {
> + dev_err(imx214->dev, "%s failed to set frame format: %d\n",
> + __func__, ret);
> + return ret;
> + }
> +
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> imx214->fmt.width, imx214->fmt.height);
> @@ -922,7 +995,7 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
> return ret;
>
> state = v4l2_subdev_lock_and_get_active_state(subdev);
> - ret = imx214_start_streaming(imx214);
> + ret = imx214_start_streaming(imx214, state);
> v4l2_subdev_unlock_state(state);
> if (ret < 0)
> goto err_rpm_put;
>
> --
> 2.46.0
>
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree
2024-09-02 21:54 ` [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> The imx214 camera is capable of either two-lane or four-lane operation.
>
> Currently only the four-lane mode is supported, as proper pixel rates
> and link frequences for the two-lane mode are unknown.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 37 ++++++++++++++++++++++++++++++-------
> 1 file changed, 30 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 4507e12dd4cd..3b422cddbdce 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -195,11 +195,13 @@ struct imx214 {
> struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
>
> struct gpio_desc *enable_gpio;
> +
> + /* Two or Four lanes */
> + u8 lanes;
> };
>
> /*From imx214_mode_tbls.h*/
> static const struct cci_reg_sequence mode_4096x2304[] = {
> - { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> @@ -272,7 +274,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> };
>
> static const struct cci_reg_sequence mode_1920x1080[] = {
> - { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
> { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> { IMX214_REG_EXPOSURE_RATIO, 1 },
> @@ -774,6 +775,13 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return 0;
> };
>
> +static int imx214_configure_lanes(struct imx214 *imx214)
> +{
> + return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
> + imx214->lanes == 2 ? IMX214_CSI_2_LANE_MODE :
> + IMX214_CSI_4_LANE_MODE, NULL);
> +};
> +
> static int imx214_start_streaming(struct imx214 *imx214)
> {
> const struct imx214_mode *mode;
> @@ -786,6 +794,13 @@ static int imx214_start_streaming(struct imx214 *imx214)
> return ret;
> }
>
> + /* Configure two or four Lane mode */
> + ret = imx214_configure_lanes(imx214);
> + if (ret) {
> + dev_err(imx214->dev, "%s failed to configure lanes\n", __func__);
> + return ret;
> + }
> +
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> imx214->fmt.width, imx214->fmt.height);
> @@ -930,7 +945,7 @@ static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
> imx214->supplies);
> }
>
> -static int imx214_parse_fwnode(struct device *dev)
> +static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214)
> {
> struct fwnode_handle *endpoint;
> struct v4l2_fwnode_endpoint bus_cfg = {
> @@ -949,6 +964,14 @@ static int imx214_parse_fwnode(struct device *dev)
> goto done;
> }
>
> + /* Check the number of MIPI CSI2 data lanes */
> + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
> + dev_err_probe(dev, -EINVAL,
> + "only 4 data lanes are currently supported\n");
> + goto done;
> + }
Until there is support for lanes !=4. I think is best if we just add
this check to imx214_parse_fwnode() and remove everything else from
this patch
> + imx214->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
> +
> for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
> if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ)
> break;
> @@ -973,14 +996,14 @@ static int imx214_probe(struct i2c_client *client)
> struct imx214 *imx214;
> int ret;
>
> - ret = imx214_parse_fwnode(dev);
> - if (ret)
> - return ret;
> -
> imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL);
> if (!imx214)
> return -ENOMEM;
>
> + ret = imx214_parse_fwnode(dev, imx214);
> + if (ret)
> + return ret;
> +
> imx214->dev = dev;
>
> imx214->xclk = devm_clk_get(dev, NULL);
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays
2024-09-02 21:54 ` [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> The IMX214_REG_EXPOSURE is configured twice, once with a hardcoded value
> in the mode_<res> registers arrays, and once via v4l2_ctrl_ops. The
> latter is enough, drop the former.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/i2c/imx214.c | 2 --
> 1 file changed, 2 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 91664e188fd0..4507e12dd4cd 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -254,7 +254,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> { CCI_REG8(0x3011), 0x00 },
> { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
>
> - { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
> { IMX214_REG_SHORT_EXPOSURE, 500 },
>
> { IMX214_REG_ANALOG_GAIN, 0 },
> @@ -328,7 +327,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> { CCI_REG8(0x3011), 0x00 },
> { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
>
> - { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
> { IMX214_REG_SHORT_EXPOSURE, 500 },
>
> { IMX214_REG_ANALOG_GAIN, 0 },
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros
2024-09-02 21:54 ` [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Define macros for all the known registers used in the register arrays,
> and use them to replace the numerical addresses. This improves
> readability.
Could you share the documentation?
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> ---
> drivers/media/i2c/imx214.c | 407 ++++++++++++++++++++++++++-------------------
> 1 file changed, 236 insertions(+), 171 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 780c9b8f88b0..91664e188fd0 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -24,18 +24,141 @@
> #define IMX214_MODE_STANDBY 0x00
> #define IMX214_MODE_STREAMING 0x01
>
> +#define IMX214_REG_FAST_STANDBY_CTRL CCI_REG8(0x0106)
> +
> #define IMX214_DEFAULT_CLK_FREQ 24000000
> #define IMX214_DEFAULT_LINK_FREQ 480000000
> #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
> #define IMX214_FPS 30
> #define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
>
> +/* V-TIMING internal */
> +#define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> +
> /* Exposure control */
> #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> #define IMX214_EXPOSURE_MIN 0
> #define IMX214_EXPOSURE_MAX 3184
> #define IMX214_EXPOSURE_STEP 1
> #define IMX214_EXPOSURE_DEFAULT 3184
> +#define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> +#define IMX214_REG_SHORT_EXPOSURE CCI_REG16(0x0224)
> +
> +/* Analog gain control */
> +#define IMX214_REG_ANALOG_GAIN CCI_REG16(0x0204)
> +#define IMX214_REG_SHORT_ANALOG_GAIN CCI_REG16(0x0216)
> +
> +/* Digital gain control */
> +#define IMX214_REG_DIG_GAIN_GREENR CCI_REG16(0x020e)
> +#define IMX214_REG_DIG_GAIN_RED CCI_REG16(0x0210)
> +#define IMX214_REG_DIG_GAIN_BLUE CCI_REG16(0x0212)
> +#define IMX214_REG_DIG_GAIN_GREENB CCI_REG16(0x0214)
> +
> +#define IMX214_REG_ORIENTATION CCI_REG8(0x0101)
> +
> +#define IMX214_REG_MASK_CORR_FRAMES CCI_REG8(0x0105)
> +#define IMX214_CORR_FRAMES_TRANSMIT 0
> +#define IMX214_CORR_FRAMES_MASK 1
> +
> +#define IMX214_REG_CSI_DATA_FORMAT CCI_REG16(0x0112)
> +#define IMX214_CSI_DATA_FORMAT_RAW8 0x0808
> +#define IMX214_CSI_DATA_FORMAT_RAW10 0x0A0A
> +#define IMX214_CSI_DATA_FORMAT_COMP6 0x0A06
> +#define IMX214_CSI_DATA_FORMAT_COMP8 0x0A08
> +
> +#define IMX214_REG_CSI_LANE_MODE CCI_REG8(0x0114)
> +#define IMX214_CSI_2_LANE_MODE 1
> +#define IMX214_CSI_4_LANE_MODE 3
> +
> +#define IMX214_REG_EXCK_FREQ CCI_REG16(0x0136)
> +#define IMX214_EXCK_FREQ(n) ((n) * 256) /* n expressed in MHz */
> +
> +#define IMX214_REG_TEMP_SENSOR_CONTROL CCI_REG8(0x0138)
> +
> +#define IMX214_REG_HDR_MODE CCI_REG8(0x0220)
> +#define IMX214_HDR_MODE_OFF 0
> +#define IMX214_HDR_MODE_ON 1
> +
> +#define IMX214_REG_HDR_RES_REDUCTION CCI_REG8(0x0221)
> +#define IMX214_HDR_RES_REDU_THROUGH 0x11
> +#define IMX214_HDR_RES_REDU_2_BINNING 0x22
> +
> +/* PLL settings */
> +#define IMX214_REG_VTPXCK_DIV CCI_REG8(0x0301)
> +#define IMX214_REG_VTSYCK_DIV CCI_REG8(0x0303)
> +#define IMX214_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
> +#define IMX214_REG_PLL_VT_MPY CCI_REG16(0x0306)
> +#define IMX214_REG_OPPXCK_DIV CCI_REG8(0x0309)
> +#define IMX214_REG_OPSYCK_DIV CCI_REG8(0x030b)
> +#define IMX214_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
> +#define IMX214_PLL_SINGLE 0
> +#define IMX214_PLL_DUAL 1
> +
> +#define IMX214_REG_LINE_LENGTH_PCK CCI_REG16(0x0342)
> +#define IMX214_REG_X_ADD_STA CCI_REG16(0x0344)
> +#define IMX214_REG_Y_ADD_STA CCI_REG16(0x0346)
> +#define IMX214_REG_X_ADD_END CCI_REG16(0x0348)
> +#define IMX214_REG_Y_ADD_END CCI_REG16(0x034a)
> +#define IMX214_REG_X_OUTPUT_SIZE CCI_REG16(0x034c)
> +#define IMX214_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e)
> +#define IMX214_REG_X_EVEN_INC CCI_REG8(0x0381)
> +#define IMX214_REG_X_ODD_INC CCI_REG8(0x0383)
> +#define IMX214_REG_Y_EVEN_INC CCI_REG8(0x0385)
> +#define IMX214_REG_Y_ODD_INC CCI_REG8(0x0387)
> +
> +#define IMX214_REG_SCALE_MODE CCI_REG8(0x0401)
> +#define IMX214_SCALE_NONE 0
> +#define IMX214_SCALE_HORIZONTAL 1
> +#define IMX214_SCALE_FULL 2
> +#define IMX214_REG_SCALE_M CCI_REG16(0x0404)
> +
> +#define IMX214_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
> +#define IMX214_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
> +#define IMX214_REG_DIG_CROP_WIDTH CCI_REG16(0x040c)
> +#define IMX214_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e)
> +
> +#define IMX214_REG_REQ_LINK_BIT_RATE CCI_REG32(0x0820)
> +#define IMX214_LINK_BIT_RATE_MBPS(n) ((n) << 16)
> +
> +/* Binning mode */
> +#define IMX214_REG_BINNING_MODE CCI_REG8(0x0900)
> +#define IMX214_BINNING_NONE 0
> +#define IMX214_BINNING_ENABLE 1
> +#define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
> +#define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
> +#define IMX214_BINNING_AVERAGE 0x00
> +#define IMX214_BINNING_SUMMED 0x01
> +#define IMX214_BINNING_BAYER 0x02
> +
> +#define IMX214_REG_SING_DEF_CORR_EN CCI_REG8(0x0b06)
> +#define IMX214_SING_DEF_CORR_OFF 0
> +#define IMX214_SING_DEF_CORR_ON 1
> +
> +/* AWB control */
> +#define IMX214_REG_ABS_GAIN_GREENR CCI_REG16(0x0b8e)
> +#define IMX214_REG_ABS_GAIN_RED CCI_REG16(0x0b90)
> +#define IMX214_REG_ABS_GAIN_BLUE CCI_REG16(0x0b92)
> +#define IMX214_REG_ABS_GAIN_GREENB CCI_REG16(0x0b94)
> +
> +#define IMX214_REG_RMSC_NR_MODE CCI_REG8(0x3001)
> +#define IMX214_REG_STATS_OUT_EN CCI_REG8(0x3013)
> +#define IMX214_STATS_OUT_OFF 0
> +#define IMX214_STATS_OUT_ON 1
> +
> +/* Chroma noise reduction */
> +#define IMX214_REG_NML_NR_EN CCI_REG8(0x30a2)
> +#define IMX214_NML_NR_OFF 0
> +#define IMX214_NML_NR_ON 1
> +
> +#define IMX214_REG_EBD_SIZE_V CCI_REG8(0x5041)
> +#define IMX214_EBD_NO 0
> +#define IMX214_EBD_4_LINE 4
> +
> +#define IMX214_REG_RG_STATS_LMT CCI_REG16(0x6d12)
> +#define IMX214_RG_STATS_LMT_10_BIT 0x03FF
> +#define IMX214_RG_STATS_LMT_14_BIT 0x3FFF
> +
> +#define IMX214_REG_ATR_FAST_MOVE CCI_REG8(0x9300)
>
> /* IMX214 native and active pixel array size */
> #define IMX214_NATIVE_WIDTH 4224U
> @@ -76,96 +199,70 @@ struct imx214 {
>
> /*From imx214_mode_tbls.h*/
> static const struct cci_reg_sequence mode_4096x2304[] = {
> - { CCI_REG8(0x0114), 0x03 },
> - { CCI_REG8(0x0220), 0x00 },
> - { CCI_REG8(0x0221), 0x11 },
> - { CCI_REG8(0x0222), 0x01 },
> - { CCI_REG8(0x0340), 0x0C },
> - { CCI_REG8(0x0341), 0x7A },
> - { CCI_REG8(0x0342), 0x13 },
> - { CCI_REG8(0x0343), 0x90 },
> - { CCI_REG8(0x0344), 0x00 },
> - { CCI_REG8(0x0345), 0x38 },
> - { CCI_REG8(0x0346), 0x01 },
> - { CCI_REG8(0x0347), 0x98 },
> - { CCI_REG8(0x0348), 0x10 },
> - { CCI_REG8(0x0349), 0x37 },
> - { CCI_REG8(0x034A), 0x0A },
> - { CCI_REG8(0x034B), 0x97 },
> - { CCI_REG8(0x0381), 0x01 },
> - { CCI_REG8(0x0383), 0x01 },
> - { CCI_REG8(0x0385), 0x01 },
> - { CCI_REG8(0x0387), 0x01 },
> - { CCI_REG8(0x0900), 0x00 },
> - { CCI_REG8(0x0901), 0x00 },
> - { CCI_REG8(0x0902), 0x00 },
> + { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
> + { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> + { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> + { IMX214_REG_EXPOSURE_RATIO, 1 },
> + { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> + { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> + { IMX214_REG_X_ADD_STA, 56 },
> + { IMX214_REG_Y_ADD_STA, 408 },
> + { IMX214_REG_X_ADD_END, 4151 },
> + { IMX214_REG_Y_ADD_END, 2711 },
> + { IMX214_REG_X_EVEN_INC, 1 },
> + { IMX214_REG_X_ODD_INC, 1 },
> + { IMX214_REG_Y_EVEN_INC, 1 },
> + { IMX214_REG_Y_ODD_INC, 1 },
> + { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> + { IMX214_REG_BINNING_TYPE, 0 },
> + { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { CCI_REG8(0x0112), 0x0A },
> - { CCI_REG8(0x0113), 0x0A },
> - { CCI_REG8(0x034C), 0x10 },
> - { CCI_REG8(0x034D), 0x00 },
> - { CCI_REG8(0x034E), 0x09 },
> - { CCI_REG8(0x034F), 0x00 },
> - { CCI_REG8(0x0401), 0x00 },
> - { CCI_REG8(0x0404), 0x00 },
> - { CCI_REG8(0x0405), 0x10 },
> - { CCI_REG8(0x0408), 0x00 },
> - { CCI_REG8(0x0409), 0x00 },
> - { CCI_REG8(0x040A), 0x00 },
> - { CCI_REG8(0x040B), 0x00 },
> - { CCI_REG8(0x040C), 0x10 },
> - { CCI_REG8(0x040D), 0x00 },
> - { CCI_REG8(0x040E), 0x09 },
> - { CCI_REG8(0x040F), 0x00 },
> -
> - { CCI_REG8(0x0301), 0x05 },
> - { CCI_REG8(0x0303), 0x02 },
> - { CCI_REG8(0x0305), 0x03 },
> - { CCI_REG8(0x0306), 0x00 },
> - { CCI_REG8(0x0307), 0x96 },
> - { CCI_REG8(0x0309), 0x0A },
> - { CCI_REG8(0x030B), 0x01 },
> - { CCI_REG8(0x0310), 0x00 },
> -
> - { CCI_REG8(0x0820), 0x12 },
> - { CCI_REG8(0x0821), 0xC0 },
> - { CCI_REG8(0x0822), 0x00 },
> - { CCI_REG8(0x0823), 0x00 },
> + { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> + { IMX214_REG_X_OUTPUT_SIZE, 4096 },
> + { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
> + { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> + { IMX214_REG_SCALE_M, 2 },
> + { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> + { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> + { IMX214_REG_DIG_CROP_WIDTH, 4096 },
> + { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
> +
> + { IMX214_REG_VTPXCK_DIV, 5 },
> + { IMX214_REG_VTSYCK_DIV, 2 },
> + { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> + { IMX214_REG_PLL_VT_MPY, 150 },
> + { IMX214_REG_OPPXCK_DIV, 10 },
> + { IMX214_REG_OPSYCK_DIV, 1 },
> + { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
> +
> + { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
>
> { CCI_REG8(0x3A03), 0x09 },
> { CCI_REG8(0x3A04), 0x50 },
> { CCI_REG8(0x3A05), 0x01 },
>
> - { CCI_REG8(0x0B06), 0x01 },
> - { CCI_REG8(0x30A2), 0x00 },
> + { IMX214_REG_SING_DEF_CORR_EN, IMX214_SING_DEF_CORR_ON },
> + { IMX214_REG_NML_NR_EN, IMX214_NML_NR_OFF },
>
> { CCI_REG8(0x30B4), 0x00 },
>
> { CCI_REG8(0x3A02), 0xFF },
>
> { CCI_REG8(0x3011), 0x00 },
> - { CCI_REG8(0x3013), 0x01 },
> -
> - { CCI_REG8(0x0202), 0x0C },
> - { CCI_REG8(0x0203), 0x70 },
> - { CCI_REG8(0x0224), 0x01 },
> - { CCI_REG8(0x0225), 0xF4 },
> -
> - { CCI_REG8(0x0204), 0x00 },
> - { CCI_REG8(0x0205), 0x00 },
> - { CCI_REG8(0x020E), 0x01 },
> - { CCI_REG8(0x020F), 0x00 },
> - { CCI_REG8(0x0210), 0x01 },
> - { CCI_REG8(0x0211), 0x00 },
> - { CCI_REG8(0x0212), 0x01 },
> - { CCI_REG8(0x0213), 0x00 },
> - { CCI_REG8(0x0214), 0x01 },
> - { CCI_REG8(0x0215), 0x00 },
> - { CCI_REG8(0x0216), 0x00 },
> - { CCI_REG8(0x0217), 0x00 },
> + { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
> +
> + { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
> + { IMX214_REG_SHORT_EXPOSURE, 500 },
> +
> + { IMX214_REG_ANALOG_GAIN, 0 },
> + { IMX214_REG_DIG_GAIN_GREENR, 256 },
> + { IMX214_REG_DIG_GAIN_RED, 256 },
> + { IMX214_REG_DIG_GAIN_BLUE, 256 },
> + { IMX214_REG_DIG_GAIN_GREENB, 256 },
> + { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
>
> { CCI_REG8(0x4170), 0x00 },
> { CCI_REG8(0x4171), 0x10 },
> @@ -176,96 +273,70 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> };
>
> static const struct cci_reg_sequence mode_1920x1080[] = {
> - { CCI_REG8(0x0114), 0x03 },
> - { CCI_REG8(0x0220), 0x00 },
> - { CCI_REG8(0x0221), 0x11 },
> - { CCI_REG8(0x0222), 0x01 },
> - { CCI_REG8(0x0340), 0x0C },
> - { CCI_REG8(0x0341), 0x7A },
> - { CCI_REG8(0x0342), 0x13 },
> - { CCI_REG8(0x0343), 0x90 },
> - { CCI_REG8(0x0344), 0x04 },
> - { CCI_REG8(0x0345), 0x78 },
> - { CCI_REG8(0x0346), 0x03 },
> - { CCI_REG8(0x0347), 0xFC },
> - { CCI_REG8(0x0348), 0x0B },
> - { CCI_REG8(0x0349), 0xF7 },
> - { CCI_REG8(0x034A), 0x08 },
> - { CCI_REG8(0x034B), 0x33 },
> - { CCI_REG8(0x0381), 0x01 },
> - { CCI_REG8(0x0383), 0x01 },
> - { CCI_REG8(0x0385), 0x01 },
> - { CCI_REG8(0x0387), 0x01 },
> - { CCI_REG8(0x0900), 0x00 },
> - { CCI_REG8(0x0901), 0x00 },
> - { CCI_REG8(0x0902), 0x00 },
> + { IMX214_REG_CSI_LANE_MODE, IMX214_CSI_4_LANE_MODE },
> + { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> + { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> + { IMX214_REG_EXPOSURE_RATIO, 1 },
> + { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> + { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> + { IMX214_REG_X_ADD_STA, 1144 },
> + { IMX214_REG_Y_ADD_STA, 1020 },
> + { IMX214_REG_X_ADD_END, 3063 },
> + { IMX214_REG_Y_ADD_END, 2099 },
> + { IMX214_REG_X_EVEN_INC, 1 },
> + { IMX214_REG_X_ODD_INC, 1 },
> + { IMX214_REG_Y_EVEN_INC, 1 },
> + { IMX214_REG_Y_ODD_INC, 1 },
> + { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> + { IMX214_REG_BINNING_TYPE, 0 },
> + { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> { CCI_REG8(0x3000), 0x35 },
> { CCI_REG8(0x3054), 0x01 },
> { CCI_REG8(0x305C), 0x11 },
>
> - { CCI_REG8(0x0112), 0x0A },
> - { CCI_REG8(0x0113), 0x0A },
> - { CCI_REG8(0x034C), 0x07 },
> - { CCI_REG8(0x034D), 0x80 },
> - { CCI_REG8(0x034E), 0x04 },
> - { CCI_REG8(0x034F), 0x38 },
> - { CCI_REG8(0x0401), 0x00 },
> - { CCI_REG8(0x0404), 0x00 },
> - { CCI_REG8(0x0405), 0x10 },
> - { CCI_REG8(0x0408), 0x00 },
> - { CCI_REG8(0x0409), 0x00 },
> - { CCI_REG8(0x040A), 0x00 },
> - { CCI_REG8(0x040B), 0x00 },
> - { CCI_REG8(0x040C), 0x07 },
> - { CCI_REG8(0x040D), 0x80 },
> - { CCI_REG8(0x040E), 0x04 },
> - { CCI_REG8(0x040F), 0x38 },
> -
> - { CCI_REG8(0x0301), 0x05 },
> - { CCI_REG8(0x0303), 0x02 },
> - { CCI_REG8(0x0305), 0x03 },
> - { CCI_REG8(0x0306), 0x00 },
> - { CCI_REG8(0x0307), 0x96 },
> - { CCI_REG8(0x0309), 0x0A },
> - { CCI_REG8(0x030B), 0x01 },
> - { CCI_REG8(0x0310), 0x00 },
> -
> - { CCI_REG8(0x0820), 0x12 },
> - { CCI_REG8(0x0821), 0xC0 },
> - { CCI_REG8(0x0822), 0x00 },
> - { CCI_REG8(0x0823), 0x00 },
> + { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10 },
> + { IMX214_REG_X_OUTPUT_SIZE, 1920 },
> + { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
> + { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> + { IMX214_REG_SCALE_M, 2 },
> + { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> + { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> + { IMX214_REG_DIG_CROP_WIDTH, 1920 },
> + { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
> +
> + { IMX214_REG_VTPXCK_DIV, 5 },
> + { IMX214_REG_VTSYCK_DIV, 2 },
> + { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> + { IMX214_REG_PLL_VT_MPY, 150 },
> + { IMX214_REG_OPPXCK_DIV, 10 },
> + { IMX214_REG_OPSYCK_DIV, 1 },
> + { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
> +
> + { IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(4800) },
>
> { CCI_REG8(0x3A03), 0x04 },
> { CCI_REG8(0x3A04), 0xF8 },
> { CCI_REG8(0x3A05), 0x02 },
>
> - { CCI_REG8(0x0B06), 0x01 },
> - { CCI_REG8(0x30A2), 0x00 },
> + { IMX214_REG_SING_DEF_CORR_EN, IMX214_SING_DEF_CORR_ON },
> + { IMX214_REG_NML_NR_EN, IMX214_NML_NR_OFF },
>
> { CCI_REG8(0x30B4), 0x00 },
>
> { CCI_REG8(0x3A02), 0xFF },
>
> { CCI_REG8(0x3011), 0x00 },
> - { CCI_REG8(0x3013), 0x01 },
> -
> - { CCI_REG8(0x0202), 0x0C },
> - { CCI_REG8(0x0203), 0x70 },
> - { CCI_REG8(0x0224), 0x01 },
> - { CCI_REG8(0x0225), 0xF4 },
> -
> - { CCI_REG8(0x0204), 0x00 },
> - { CCI_REG8(0x0205), 0x00 },
> - { CCI_REG8(0x020E), 0x01 },
> - { CCI_REG8(0x020F), 0x00 },
> - { CCI_REG8(0x0210), 0x01 },
> - { CCI_REG8(0x0211), 0x00 },
> - { CCI_REG8(0x0212), 0x01 },
> - { CCI_REG8(0x0213), 0x00 },
> - { CCI_REG8(0x0214), 0x01 },
> - { CCI_REG8(0x0215), 0x00 },
> - { CCI_REG8(0x0216), 0x00 },
> - { CCI_REG8(0x0217), 0x00 },
> + { IMX214_REG_STATS_OUT_EN, IMX214_STATS_OUT_ON },
> +
> + { IMX214_REG_EXPOSURE, IMX214_EXPOSURE_DEFAULT },
> + { IMX214_REG_SHORT_EXPOSURE, 500 },
> +
> + { IMX214_REG_ANALOG_GAIN, 0 },
> + { IMX214_REG_DIG_GAIN_GREENR, 256 },
> + { IMX214_REG_DIG_GAIN_RED, 256 },
> + { IMX214_REG_DIG_GAIN_BLUE, 256 },
> + { IMX214_REG_DIG_GAIN_GREENB, 256 },
> + { IMX214_REG_SHORT_ANALOG_GAIN, 0 },
>
> { CCI_REG8(0x4170), 0x00 },
> { CCI_REG8(0x4171), 0x10 },
> @@ -279,20 +350,19 @@ static const struct cci_reg_sequence mode_table_common[] = {
> /* software reset */
>
> /* software standby settings */
> - { CCI_REG8(0x0100), 0x00 },
> + { IMX214_REG_MODE_SELECT, IMX214_MODE_STANDBY },
>
> /* ATR setting */
> - { CCI_REG8(0x9300), 0x02 },
> + { IMX214_REG_ATR_FAST_MOVE, 2 },
>
> /* external clock setting */
> - { CCI_REG8(0x0136), 0x18 },
> - { CCI_REG8(0x0137), 0x00 },
> + { IMX214_REG_EXCK_FREQ, IMX214_EXCK_FREQ(IMX214_DEFAULT_CLK_FREQ / 1000000) },
>
> /* global setting */
> /* basic config */
> - { CCI_REG8(0x0101), 0x00 },
> - { CCI_REG8(0x0105), 0x01 },
> - { CCI_REG8(0x0106), 0x01 },
> + { IMX214_REG_ORIENTATION, 0 },
> + { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> + { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> { CCI_REG8(0x4550), 0x02 },
> { CCI_REG8(0x4601), 0x00 },
> { CCI_REG8(0x4642), 0x05 },
> @@ -337,18 +407,17 @@ static const struct cci_reg_sequence mode_table_common[] = {
> { CCI_REG8(0x4A87), 0xFF },
>
> /* embedded data */
> - { CCI_REG8(0x5041), 0x04 },
> + { IMX214_REG_EBD_SIZE_V, IMX214_EBD_4_LINE },
> { CCI_REG8(0x583C), 0x04 },
> { CCI_REG8(0x620E), 0x04 },
> { CCI_REG8(0x6EB2), 0x01 },
> { CCI_REG8(0x6EB3), 0x00 },
> - { CCI_REG8(0x9300), 0x02 },
> + { IMX214_REG_ATR_FAST_MOVE, 2 },
>
> /* imagequality */
> /* HDR setting */
> - { CCI_REG8(0x3001), 0x07 },
> - { CCI_REG8(0x6D12), 0x3F },
> - { CCI_REG8(0x6D13), 0xFF },
> + { IMX214_REG_RMSC_NR_MODE, 0x07 },
> + { IMX214_REG_RG_STATS_LMT, IMX214_RG_STATS_LMT_14_BIT },
> { CCI_REG8(0x9344), 0x03 },
> { CCI_REG8(0x9706), 0x10 },
> { CCI_REG8(0x9707), 0x03 },
> @@ -376,14 +445,10 @@ static const struct cci_reg_sequence mode_table_common[] = {
> { CCI_REG8(0x698B), 0x03 },
>
> /* white balanace */
> - { CCI_REG8(0x0B8E), 0x01 },
> - { CCI_REG8(0x0B8F), 0x00 },
> - { CCI_REG8(0x0B90), 0x01 },
> - { CCI_REG8(0x0B91), 0x00 },
> - { CCI_REG8(0x0B92), 0x01 },
> - { CCI_REG8(0x0B93), 0x00 },
> - { CCI_REG8(0x0B94), 0x01 },
> - { CCI_REG8(0x0B95), 0x00 },
> + { IMX214_REG_ABS_GAIN_GREENR, 0x0100 },
> + { IMX214_REG_ABS_GAIN_RED, 0x0100 },
> + { IMX214_REG_ABS_GAIN_BLUE, 0x0100 },
> + { IMX214_REG_ABS_GAIN_GREENB, 0x0100 },
>
> /* ATR setting */
> { CCI_REG8(0x6E50), 0x00 },
> @@ -735,7 +800,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
>
> usleep_range(10000, 10500);
>
> - cci_write(imx214->regmap, CCI_REG8(0x0138), 0x01, NULL);
> + cci_write(imx214->regmap, IMX214_REG_TEMP_SENSOR_CONTROL, 0x01, NULL);
>
> ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
> if (ret < 0) {
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers
2024-09-02 21:54 ` [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Use the new common CCI register access helpers to replace the private
> register access helpers in the imx214 driver. This simplifies the driver
> by reducing the amount of code.
>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/Kconfig | 1 +
> drivers/media/i2c/imx214.c | 672 +++++++++++++++++++++------------------------
> 2 files changed, 310 insertions(+), 363 deletions(-)
>
> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
> index 8ba096b8ebca..85ecb2aeefdb 100644
> --- a/drivers/media/i2c/Kconfig
> +++ b/drivers/media/i2c/Kconfig
> @@ -140,6 +140,7 @@ config VIDEO_IMX214
> tristate "Sony IMX214 sensor support"
> depends on GPIOLIB
> select REGMAP_I2C
> + select V4L2_CCI_I2C
> help
> This is a Video4Linux2 sensor driver for the Sony
> IMX214 camera.
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index ad2f1db6baeb..780c9b8f88b0 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -15,11 +15,12 @@
> #include <linux/regmap.h>
> #include <linux/regulator/consumer.h>
> #include <media/media-entity.h>
> +#include <media/v4l2-cci.h>
> #include <media/v4l2-ctrls.h>
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> -#define IMX214_REG_MODE_SELECT 0x0100
> +#define IMX214_REG_MODE_SELECT CCI_REG8(0x0100)
> #define IMX214_MODE_STANDBY 0x00
> #define IMX214_MODE_STREAMING 0x01
>
> @@ -30,7 +31,7 @@
> #define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
>
> /* Exposure control */
> -#define IMX214_REG_EXPOSURE 0x0202
> +#define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> #define IMX214_EXPOSURE_MIN 0
> #define IMX214_EXPOSURE_MAX 3184
> #define IMX214_EXPOSURE_STEP 1
> @@ -73,345 +74,324 @@ struct imx214 {
> struct gpio_desc *enable_gpio;
> };
>
> -struct reg_8 {
> - u16 addr;
> - u8 val;
> -};
> -
> -enum {
> - IMX214_TABLE_WAIT_MS = 0,
> - IMX214_TABLE_END,
> - IMX214_MAX_RETRIES,
> - IMX214_WAIT_MS
> -};
> -
> /*From imx214_mode_tbls.h*/
> -static const struct reg_8 mode_4096x2304[] = {
> - {0x0114, 0x03},
> - {0x0220, 0x00},
> - {0x0221, 0x11},
> - {0x0222, 0x01},
> - {0x0340, 0x0C},
> - {0x0341, 0x7A},
> - {0x0342, 0x13},
> - {0x0343, 0x90},
> - {0x0344, 0x00},
> - {0x0345, 0x38},
> - {0x0346, 0x01},
> - {0x0347, 0x98},
> - {0x0348, 0x10},
> - {0x0349, 0x37},
> - {0x034A, 0x0A},
> - {0x034B, 0x97},
> - {0x0381, 0x01},
> - {0x0383, 0x01},
> - {0x0385, 0x01},
> - {0x0387, 0x01},
> - {0x0900, 0x00},
> - {0x0901, 0x00},
> - {0x0902, 0x00},
> - {0x3000, 0x35},
> - {0x3054, 0x01},
> - {0x305C, 0x11},
> -
> - {0x0112, 0x0A},
> - {0x0113, 0x0A},
> - {0x034C, 0x10},
> - {0x034D, 0x00},
> - {0x034E, 0x09},
> - {0x034F, 0x00},
> - {0x0401, 0x00},
> - {0x0404, 0x00},
> - {0x0405, 0x10},
> - {0x0408, 0x00},
> - {0x0409, 0x00},
> - {0x040A, 0x00},
> - {0x040B, 0x00},
> - {0x040C, 0x10},
> - {0x040D, 0x00},
> - {0x040E, 0x09},
> - {0x040F, 0x00},
> -
> - {0x0301, 0x05},
> - {0x0303, 0x02},
> - {0x0305, 0x03},
> - {0x0306, 0x00},
> - {0x0307, 0x96},
> - {0x0309, 0x0A},
> - {0x030B, 0x01},
> - {0x0310, 0x00},
> -
> - {0x0820, 0x12},
> - {0x0821, 0xC0},
> - {0x0822, 0x00},
> - {0x0823, 0x00},
> -
> - {0x3A03, 0x09},
> - {0x3A04, 0x50},
> - {0x3A05, 0x01},
> -
> - {0x0B06, 0x01},
> - {0x30A2, 0x00},
> -
> - {0x30B4, 0x00},
> -
> - {0x3A02, 0xFF},
> -
> - {0x3011, 0x00},
> - {0x3013, 0x01},
> -
> - {0x0202, 0x0C},
> - {0x0203, 0x70},
> - {0x0224, 0x01},
> - {0x0225, 0xF4},
> -
> - {0x0204, 0x00},
> - {0x0205, 0x00},
> - {0x020E, 0x01},
> - {0x020F, 0x00},
> - {0x0210, 0x01},
> - {0x0211, 0x00},
> - {0x0212, 0x01},
> - {0x0213, 0x00},
> - {0x0214, 0x01},
> - {0x0215, 0x00},
> - {0x0216, 0x00},
> - {0x0217, 0x00},
> -
> - {0x4170, 0x00},
> - {0x4171, 0x10},
> - {0x4176, 0x00},
> - {0x4177, 0x3C},
> - {0xAE20, 0x04},
> - {0xAE21, 0x5C},
> -
> - {IMX214_TABLE_WAIT_MS, 10},
> - {0x0138, 0x01},
> - {IMX214_TABLE_END, 0x00}
> +static const struct cci_reg_sequence mode_4096x2304[] = {
> + { CCI_REG8(0x0114), 0x03 },
> + { CCI_REG8(0x0220), 0x00 },
> + { CCI_REG8(0x0221), 0x11 },
> + { CCI_REG8(0x0222), 0x01 },
> + { CCI_REG8(0x0340), 0x0C },
> + { CCI_REG8(0x0341), 0x7A },
> + { CCI_REG8(0x0342), 0x13 },
> + { CCI_REG8(0x0343), 0x90 },
> + { CCI_REG8(0x0344), 0x00 },
> + { CCI_REG8(0x0345), 0x38 },
> + { CCI_REG8(0x0346), 0x01 },
> + { CCI_REG8(0x0347), 0x98 },
> + { CCI_REG8(0x0348), 0x10 },
> + { CCI_REG8(0x0349), 0x37 },
> + { CCI_REG8(0x034A), 0x0A },
> + { CCI_REG8(0x034B), 0x97 },
> + { CCI_REG8(0x0381), 0x01 },
> + { CCI_REG8(0x0383), 0x01 },
> + { CCI_REG8(0x0385), 0x01 },
> + { CCI_REG8(0x0387), 0x01 },
> + { CCI_REG8(0x0900), 0x00 },
> + { CCI_REG8(0x0901), 0x00 },
> + { CCI_REG8(0x0902), 0x00 },
> + { CCI_REG8(0x3000), 0x35 },
> + { CCI_REG8(0x3054), 0x01 },
> + { CCI_REG8(0x305C), 0x11 },
> +
> + { CCI_REG8(0x0112), 0x0A },
> + { CCI_REG8(0x0113), 0x0A },
> + { CCI_REG8(0x034C), 0x10 },
> + { CCI_REG8(0x034D), 0x00 },
> + { CCI_REG8(0x034E), 0x09 },
> + { CCI_REG8(0x034F), 0x00 },
> + { CCI_REG8(0x0401), 0x00 },
> + { CCI_REG8(0x0404), 0x00 },
> + { CCI_REG8(0x0405), 0x10 },
> + { CCI_REG8(0x0408), 0x00 },
> + { CCI_REG8(0x0409), 0x00 },
> + { CCI_REG8(0x040A), 0x00 },
> + { CCI_REG8(0x040B), 0x00 },
> + { CCI_REG8(0x040C), 0x10 },
> + { CCI_REG8(0x040D), 0x00 },
> + { CCI_REG8(0x040E), 0x09 },
> + { CCI_REG8(0x040F), 0x00 },
> +
> + { CCI_REG8(0x0301), 0x05 },
> + { CCI_REG8(0x0303), 0x02 },
> + { CCI_REG8(0x0305), 0x03 },
> + { CCI_REG8(0x0306), 0x00 },
> + { CCI_REG8(0x0307), 0x96 },
> + { CCI_REG8(0x0309), 0x0A },
> + { CCI_REG8(0x030B), 0x01 },
> + { CCI_REG8(0x0310), 0x00 },
> +
> + { CCI_REG8(0x0820), 0x12 },
> + { CCI_REG8(0x0821), 0xC0 },
> + { CCI_REG8(0x0822), 0x00 },
> + { CCI_REG8(0x0823), 0x00 },
> +
> + { CCI_REG8(0x3A03), 0x09 },
> + { CCI_REG8(0x3A04), 0x50 },
> + { CCI_REG8(0x3A05), 0x01 },
> +
> + { CCI_REG8(0x0B06), 0x01 },
> + { CCI_REG8(0x30A2), 0x00 },
> +
> + { CCI_REG8(0x30B4), 0x00 },
> +
> + { CCI_REG8(0x3A02), 0xFF },
> +
> + { CCI_REG8(0x3011), 0x00 },
> + { CCI_REG8(0x3013), 0x01 },
> +
> + { CCI_REG8(0x0202), 0x0C },
> + { CCI_REG8(0x0203), 0x70 },
> + { CCI_REG8(0x0224), 0x01 },
> + { CCI_REG8(0x0225), 0xF4 },
> +
> + { CCI_REG8(0x0204), 0x00 },
> + { CCI_REG8(0x0205), 0x00 },
> + { CCI_REG8(0x020E), 0x01 },
> + { CCI_REG8(0x020F), 0x00 },
> + { CCI_REG8(0x0210), 0x01 },
> + { CCI_REG8(0x0211), 0x00 },
> + { CCI_REG8(0x0212), 0x01 },
> + { CCI_REG8(0x0213), 0x00 },
> + { CCI_REG8(0x0214), 0x01 },
> + { CCI_REG8(0x0215), 0x00 },
> + { CCI_REG8(0x0216), 0x00 },
> + { CCI_REG8(0x0217), 0x00 },
> +
> + { CCI_REG8(0x4170), 0x00 },
> + { CCI_REG8(0x4171), 0x10 },
> + { CCI_REG8(0x4176), 0x00 },
> + { CCI_REG8(0x4177), 0x3C },
> + { CCI_REG8(0xAE20), 0x04 },
> + { CCI_REG8(0xAE21), 0x5C },
> };
>
> -static const struct reg_8 mode_1920x1080[] = {
> - {0x0114, 0x03},
> - {0x0220, 0x00},
> - {0x0221, 0x11},
> - {0x0222, 0x01},
> - {0x0340, 0x0C},
> - {0x0341, 0x7A},
> - {0x0342, 0x13},
> - {0x0343, 0x90},
> - {0x0344, 0x04},
> - {0x0345, 0x78},
> - {0x0346, 0x03},
> - {0x0347, 0xFC},
> - {0x0348, 0x0B},
> - {0x0349, 0xF7},
> - {0x034A, 0x08},
> - {0x034B, 0x33},
> - {0x0381, 0x01},
> - {0x0383, 0x01},
> - {0x0385, 0x01},
> - {0x0387, 0x01},
> - {0x0900, 0x00},
> - {0x0901, 0x00},
> - {0x0902, 0x00},
> - {0x3000, 0x35},
> - {0x3054, 0x01},
> - {0x305C, 0x11},
> -
> - {0x0112, 0x0A},
> - {0x0113, 0x0A},
> - {0x034C, 0x07},
> - {0x034D, 0x80},
> - {0x034E, 0x04},
> - {0x034F, 0x38},
> - {0x0401, 0x00},
> - {0x0404, 0x00},
> - {0x0405, 0x10},
> - {0x0408, 0x00},
> - {0x0409, 0x00},
> - {0x040A, 0x00},
> - {0x040B, 0x00},
> - {0x040C, 0x07},
> - {0x040D, 0x80},
> - {0x040E, 0x04},
> - {0x040F, 0x38},
> -
> - {0x0301, 0x05},
> - {0x0303, 0x02},
> - {0x0305, 0x03},
> - {0x0306, 0x00},
> - {0x0307, 0x96},
> - {0x0309, 0x0A},
> - {0x030B, 0x01},
> - {0x0310, 0x00},
> -
> - {0x0820, 0x12},
> - {0x0821, 0xC0},
> - {0x0822, 0x00},
> - {0x0823, 0x00},
> -
> - {0x3A03, 0x04},
> - {0x3A04, 0xF8},
> - {0x3A05, 0x02},
> -
> - {0x0B06, 0x01},
> - {0x30A2, 0x00},
> -
> - {0x30B4, 0x00},
> -
> - {0x3A02, 0xFF},
> -
> - {0x3011, 0x00},
> - {0x3013, 0x01},
> -
> - {0x0202, 0x0C},
> - {0x0203, 0x70},
> - {0x0224, 0x01},
> - {0x0225, 0xF4},
> -
> - {0x0204, 0x00},
> - {0x0205, 0x00},
> - {0x020E, 0x01},
> - {0x020F, 0x00},
> - {0x0210, 0x01},
> - {0x0211, 0x00},
> - {0x0212, 0x01},
> - {0x0213, 0x00},
> - {0x0214, 0x01},
> - {0x0215, 0x00},
> - {0x0216, 0x00},
> - {0x0217, 0x00},
> -
> - {0x4170, 0x00},
> - {0x4171, 0x10},
> - {0x4176, 0x00},
> - {0x4177, 0x3C},
> - {0xAE20, 0x04},
> - {0xAE21, 0x5C},
> -
> - {IMX214_TABLE_WAIT_MS, 10},
> - {0x0138, 0x01},
> - {IMX214_TABLE_END, 0x00}
> +static const struct cci_reg_sequence mode_1920x1080[] = {
> + { CCI_REG8(0x0114), 0x03 },
> + { CCI_REG8(0x0220), 0x00 },
> + { CCI_REG8(0x0221), 0x11 },
> + { CCI_REG8(0x0222), 0x01 },
> + { CCI_REG8(0x0340), 0x0C },
> + { CCI_REG8(0x0341), 0x7A },
> + { CCI_REG8(0x0342), 0x13 },
> + { CCI_REG8(0x0343), 0x90 },
> + { CCI_REG8(0x0344), 0x04 },
> + { CCI_REG8(0x0345), 0x78 },
> + { CCI_REG8(0x0346), 0x03 },
> + { CCI_REG8(0x0347), 0xFC },
> + { CCI_REG8(0x0348), 0x0B },
> + { CCI_REG8(0x0349), 0xF7 },
> + { CCI_REG8(0x034A), 0x08 },
> + { CCI_REG8(0x034B), 0x33 },
> + { CCI_REG8(0x0381), 0x01 },
> + { CCI_REG8(0x0383), 0x01 },
> + { CCI_REG8(0x0385), 0x01 },
> + { CCI_REG8(0x0387), 0x01 },
> + { CCI_REG8(0x0900), 0x00 },
> + { CCI_REG8(0x0901), 0x00 },
> + { CCI_REG8(0x0902), 0x00 },
> + { CCI_REG8(0x3000), 0x35 },
> + { CCI_REG8(0x3054), 0x01 },
> + { CCI_REG8(0x305C), 0x11 },
> +
> + { CCI_REG8(0x0112), 0x0A },
> + { CCI_REG8(0x0113), 0x0A },
> + { CCI_REG8(0x034C), 0x07 },
> + { CCI_REG8(0x034D), 0x80 },
> + { CCI_REG8(0x034E), 0x04 },
> + { CCI_REG8(0x034F), 0x38 },
> + { CCI_REG8(0x0401), 0x00 },
> + { CCI_REG8(0x0404), 0x00 },
> + { CCI_REG8(0x0405), 0x10 },
> + { CCI_REG8(0x0408), 0x00 },
> + { CCI_REG8(0x0409), 0x00 },
> + { CCI_REG8(0x040A), 0x00 },
> + { CCI_REG8(0x040B), 0x00 },
> + { CCI_REG8(0x040C), 0x07 },
> + { CCI_REG8(0x040D), 0x80 },
> + { CCI_REG8(0x040E), 0x04 },
> + { CCI_REG8(0x040F), 0x38 },
> +
> + { CCI_REG8(0x0301), 0x05 },
> + { CCI_REG8(0x0303), 0x02 },
> + { CCI_REG8(0x0305), 0x03 },
> + { CCI_REG8(0x0306), 0x00 },
> + { CCI_REG8(0x0307), 0x96 },
> + { CCI_REG8(0x0309), 0x0A },
> + { CCI_REG8(0x030B), 0x01 },
> + { CCI_REG8(0x0310), 0x00 },
> +
> + { CCI_REG8(0x0820), 0x12 },
> + { CCI_REG8(0x0821), 0xC0 },
> + { CCI_REG8(0x0822), 0x00 },
> + { CCI_REG8(0x0823), 0x00 },
> +
> + { CCI_REG8(0x3A03), 0x04 },
> + { CCI_REG8(0x3A04), 0xF8 },
> + { CCI_REG8(0x3A05), 0x02 },
> +
> + { CCI_REG8(0x0B06), 0x01 },
> + { CCI_REG8(0x30A2), 0x00 },
> +
> + { CCI_REG8(0x30B4), 0x00 },
> +
> + { CCI_REG8(0x3A02), 0xFF },
> +
> + { CCI_REG8(0x3011), 0x00 },
> + { CCI_REG8(0x3013), 0x01 },
> +
> + { CCI_REG8(0x0202), 0x0C },
> + { CCI_REG8(0x0203), 0x70 },
> + { CCI_REG8(0x0224), 0x01 },
> + { CCI_REG8(0x0225), 0xF4 },
> +
> + { CCI_REG8(0x0204), 0x00 },
> + { CCI_REG8(0x0205), 0x00 },
> + { CCI_REG8(0x020E), 0x01 },
> + { CCI_REG8(0x020F), 0x00 },
> + { CCI_REG8(0x0210), 0x01 },
> + { CCI_REG8(0x0211), 0x00 },
> + { CCI_REG8(0x0212), 0x01 },
> + { CCI_REG8(0x0213), 0x00 },
> + { CCI_REG8(0x0214), 0x01 },
> + { CCI_REG8(0x0215), 0x00 },
> + { CCI_REG8(0x0216), 0x00 },
> + { CCI_REG8(0x0217), 0x00 },
> +
> + { CCI_REG8(0x4170), 0x00 },
> + { CCI_REG8(0x4171), 0x10 },
> + { CCI_REG8(0x4176), 0x00 },
> + { CCI_REG8(0x4177), 0x3C },
> + { CCI_REG8(0xAE20), 0x04 },
> + { CCI_REG8(0xAE21), 0x5C },
> };
>
> -static const struct reg_8 mode_table_common[] = {
> +static const struct cci_reg_sequence mode_table_common[] = {
> /* software reset */
>
> /* software standby settings */
> - {0x0100, 0x00},
> + { CCI_REG8(0x0100), 0x00 },
>
> /* ATR setting */
> - {0x9300, 0x02},
> + { CCI_REG8(0x9300), 0x02 },
>
> /* external clock setting */
> - {0x0136, 0x18},
> - {0x0137, 0x00},
> + { CCI_REG8(0x0136), 0x18 },
> + { CCI_REG8(0x0137), 0x00 },
>
> /* global setting */
> /* basic config */
> - {0x0101, 0x00},
> - {0x0105, 0x01},
> - {0x0106, 0x01},
> - {0x4550, 0x02},
> - {0x4601, 0x00},
> - {0x4642, 0x05},
> - {0x6227, 0x11},
> - {0x6276, 0x00},
> - {0x900E, 0x06},
> - {0xA802, 0x90},
> - {0xA803, 0x11},
> - {0xA804, 0x62},
> - {0xA805, 0x77},
> - {0xA806, 0xAE},
> - {0xA807, 0x34},
> - {0xA808, 0xAE},
> - {0xA809, 0x35},
> - {0xA80A, 0x62},
> - {0xA80B, 0x83},
> - {0xAE33, 0x00},
> + { CCI_REG8(0x0101), 0x00 },
> + { CCI_REG8(0x0105), 0x01 },
> + { CCI_REG8(0x0106), 0x01 },
> + { CCI_REG8(0x4550), 0x02 },
> + { CCI_REG8(0x4601), 0x00 },
> + { CCI_REG8(0x4642), 0x05 },
> + { CCI_REG8(0x6227), 0x11 },
> + { CCI_REG8(0x6276), 0x00 },
> + { CCI_REG8(0x900E), 0x06 },
> + { CCI_REG8(0xA802), 0x90 },
> + { CCI_REG8(0xA803), 0x11 },
> + { CCI_REG8(0xA804), 0x62 },
> + { CCI_REG8(0xA805), 0x77 },
> + { CCI_REG8(0xA806), 0xAE },
> + { CCI_REG8(0xA807), 0x34 },
> + { CCI_REG8(0xA808), 0xAE },
> + { CCI_REG8(0xA809), 0x35 },
> + { CCI_REG8(0xA80A), 0x62 },
> + { CCI_REG8(0xA80B), 0x83 },
> + { CCI_REG8(0xAE33), 0x00 },
>
> /* analog setting */
> - {0x4174, 0x00},
> - {0x4175, 0x11},
> - {0x4612, 0x29},
> - {0x461B, 0x12},
> - {0x461F, 0x06},
> - {0x4635, 0x07},
> - {0x4637, 0x30},
> - {0x463F, 0x18},
> - {0x4641, 0x0D},
> - {0x465B, 0x12},
> - {0x465F, 0x11},
> - {0x4663, 0x11},
> - {0x4667, 0x0F},
> - {0x466F, 0x0F},
> - {0x470E, 0x09},
> - {0x4909, 0xAB},
> - {0x490B, 0x95},
> - {0x4915, 0x5D},
> - {0x4A5F, 0xFF},
> - {0x4A61, 0xFF},
> - {0x4A73, 0x62},
> - {0x4A85, 0x00},
> - {0x4A87, 0xFF},
> + { CCI_REG8(0x4174), 0x00 },
> + { CCI_REG8(0x4175), 0x11 },
> + { CCI_REG8(0x4612), 0x29 },
> + { CCI_REG8(0x461B), 0x12 },
> + { CCI_REG8(0x461F), 0x06 },
> + { CCI_REG8(0x4635), 0x07 },
> + { CCI_REG8(0x4637), 0x30 },
> + { CCI_REG8(0x463F), 0x18 },
> + { CCI_REG8(0x4641), 0x0D },
> + { CCI_REG8(0x465B), 0x12 },
> + { CCI_REG8(0x465F), 0x11 },
> + { CCI_REG8(0x4663), 0x11 },
> + { CCI_REG8(0x4667), 0x0F },
> + { CCI_REG8(0x466F), 0x0F },
> + { CCI_REG8(0x470E), 0x09 },
> + { CCI_REG8(0x4909), 0xAB },
> + { CCI_REG8(0x490B), 0x95 },
> + { CCI_REG8(0x4915), 0x5D },
> + { CCI_REG8(0x4A5F), 0xFF },
> + { CCI_REG8(0x4A61), 0xFF },
> + { CCI_REG8(0x4A73), 0x62 },
> + { CCI_REG8(0x4A85), 0x00 },
> + { CCI_REG8(0x4A87), 0xFF },
>
> /* embedded data */
> - {0x5041, 0x04},
> - {0x583C, 0x04},
> - {0x620E, 0x04},
> - {0x6EB2, 0x01},
> - {0x6EB3, 0x00},
> - {0x9300, 0x02},
> + { CCI_REG8(0x5041), 0x04 },
> + { CCI_REG8(0x583C), 0x04 },
> + { CCI_REG8(0x620E), 0x04 },
> + { CCI_REG8(0x6EB2), 0x01 },
> + { CCI_REG8(0x6EB3), 0x00 },
> + { CCI_REG8(0x9300), 0x02 },
>
> /* imagequality */
> /* HDR setting */
> - {0x3001, 0x07},
> - {0x6D12, 0x3F},
> - {0x6D13, 0xFF},
> - {0x9344, 0x03},
> - {0x9706, 0x10},
> - {0x9707, 0x03},
> - {0x9708, 0x03},
> - {0x9E04, 0x01},
> - {0x9E05, 0x00},
> - {0x9E0C, 0x01},
> - {0x9E0D, 0x02},
> - {0x9E24, 0x00},
> - {0x9E25, 0x8C},
> - {0x9E26, 0x00},
> - {0x9E27, 0x94},
> - {0x9E28, 0x00},
> - {0x9E29, 0x96},
> + { CCI_REG8(0x3001), 0x07 },
> + { CCI_REG8(0x6D12), 0x3F },
> + { CCI_REG8(0x6D13), 0xFF },
> + { CCI_REG8(0x9344), 0x03 },
> + { CCI_REG8(0x9706), 0x10 },
> + { CCI_REG8(0x9707), 0x03 },
> + { CCI_REG8(0x9708), 0x03 },
> + { CCI_REG8(0x9E04), 0x01 },
> + { CCI_REG8(0x9E05), 0x00 },
> + { CCI_REG8(0x9E0C), 0x01 },
> + { CCI_REG8(0x9E0D), 0x02 },
> + { CCI_REG8(0x9E24), 0x00 },
> + { CCI_REG8(0x9E25), 0x8C },
> + { CCI_REG8(0x9E26), 0x00 },
> + { CCI_REG8(0x9E27), 0x94 },
> + { CCI_REG8(0x9E28), 0x00 },
> + { CCI_REG8(0x9E29), 0x96 },
>
> /* CNR parameter setting */
> - {0x69DB, 0x01},
> + { CCI_REG8(0x69DB), 0x01 },
>
> /* Moire reduction */
> - {0x6957, 0x01},
> + { CCI_REG8(0x6957), 0x01 },
>
> /* image enhancement */
> - {0x6987, 0x17},
> - {0x698A, 0x03},
> - {0x698B, 0x03},
> + { CCI_REG8(0x6987), 0x17 },
> + { CCI_REG8(0x698A), 0x03 },
> + { CCI_REG8(0x698B), 0x03 },
>
> /* white balanace */
> - {0x0B8E, 0x01},
> - {0x0B8F, 0x00},
> - {0x0B90, 0x01},
> - {0x0B91, 0x00},
> - {0x0B92, 0x01},
> - {0x0B93, 0x00},
> - {0x0B94, 0x01},
> - {0x0B95, 0x00},
> + { CCI_REG8(0x0B8E), 0x01 },
> + { CCI_REG8(0x0B8F), 0x00 },
> + { CCI_REG8(0x0B90), 0x01 },
> + { CCI_REG8(0x0B91), 0x00 },
> + { CCI_REG8(0x0B92), 0x01 },
> + { CCI_REG8(0x0B93), 0x00 },
> + { CCI_REG8(0x0B94), 0x01 },
> + { CCI_REG8(0x0B95), 0x00 },
>
> /* ATR setting */
> - {0x6E50, 0x00},
> - {0x6E51, 0x32},
> - {0x9340, 0x00},
> - {0x9341, 0x3C},
> - {0x9342, 0x03},
> - {0x9343, 0xFF},
> - {IMX214_TABLE_END, 0x00}
> + { CCI_REG8(0x6E50), 0x00 },
> + { CCI_REG8(0x6E51), 0x32 },
> + { CCI_REG8(0x9340), 0x00 },
> + { CCI_REG8(0x9341), 0x3C },
> + { CCI_REG8(0x9342), 0x03 },
> + { CCI_REG8(0x9343), 0xFF },
> };
>
> /*
> @@ -421,16 +401,19 @@ static const struct reg_8 mode_table_common[] = {
> static const struct imx214_mode {
> u32 width;
> u32 height;
> - const struct reg_8 *reg_table;
> + unsigned int num_of_regs;
> + const struct cci_reg_sequence *reg_table;
> } imx214_modes[] = {
> {
> .width = 4096,
> .height = 2304,
> + .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> .reg_table = mode_4096x2304,
> },
> {
> .width = 1920,
> .height = 1080,
> + .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> .reg_table = mode_1920x1080,
> },
> };
> @@ -631,7 +614,6 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> {
> struct imx214 *imx214 = container_of(ctrl->handler,
> struct imx214, ctrls);
> - u8 vals[2];
> int ret;
>
> /*
> @@ -643,12 +625,7 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
>
> switch (ctrl->id) {
> case V4L2_CID_EXPOSURE:
> - vals[1] = ctrl->val;
> - vals[0] = ctrl->val >> 8;
> - ret = regmap_bulk_write(imx214->regmap, IMX214_REG_EXPOSURE, vals, 2);
> - if (ret < 0)
> - dev_err(imx214->dev, "Error %d\n", ret);
> - ret = 0;
> + cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> break;
>
> default:
> @@ -734,46 +711,13 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return 0;
> };
>
> -#define MAX_CMD 4
> -static int imx214_write_table(struct imx214 *imx214,
> - const struct reg_8 table[])
> -{
> - u8 vals[MAX_CMD];
> - int i;
> - int ret;
> -
> - for (; table->addr != IMX214_TABLE_END ; table++) {
> - if (table->addr == IMX214_TABLE_WAIT_MS) {
> - usleep_range(table->val * 1000,
> - table->val * 1000 + 500);
> - continue;
> - }
> -
> - for (i = 0; i < MAX_CMD; i++) {
> - if (table[i].addr != (table[0].addr + i))
> - break;
> - vals[i] = table[i].val;
> - }
> -
> - ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i);
> -
> - if (ret) {
> - dev_err(imx214->dev, "write_table error: %d\n", ret);
> - return ret;
> - }
> -
> - table += i - 1;
> - }
> -
> - return 0;
> -}
> -
> static int imx214_start_streaming(struct imx214 *imx214)
> {
> const struct imx214_mode *mode;
> int ret;
>
> - ret = imx214_write_table(imx214, mode_table_common);
> + ret = cci_multi_reg_write(imx214->regmap, mode_table_common,
> + ARRAY_SIZE(mode_table_common), NULL);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sent common table %d\n", ret);
> return ret;
> @@ -782,17 +726,24 @@ static int imx214_start_streaming(struct imx214 *imx214)
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> imx214->fmt.width, imx214->fmt.height);
> - ret = imx214_write_table(imx214, mode->reg_table);
> + ret = cci_multi_reg_write(imx214->regmap, mode->reg_table,
> + mode->num_of_regs, NULL);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sent mode table %d\n", ret);
> return ret;
> }
> +
> + usleep_range(10000, 10500);
> +
> + cci_write(imx214->regmap, CCI_REG8(0x0138), 0x01, NULL);
> +
> ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sync v4l2 controls\n");
> return ret;
> }
> - ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STREAMING);
> + ret = cci_write(imx214->regmap, IMX214_REG_MODE_SELECT,
> + IMX214_MODE_STREAMING, NULL);
> if (ret < 0)
> dev_err(imx214->dev, "could not sent start table %d\n", ret);
>
> @@ -803,7 +754,8 @@ static int imx214_stop_streaming(struct imx214 *imx214)
> {
> int ret;
>
> - ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STANDBY);
> + ret = cci_write(imx214->regmap, IMX214_REG_MODE_SELECT,
> + IMX214_MODE_STANDBY, NULL);
> if (ret < 0)
> dev_err(imx214->dev, "could not sent stop table %d\n", ret);
>
> @@ -904,12 +856,6 @@ static const struct v4l2_subdev_internal_ops imx214_internal_ops = {
> .init_state = imx214_entity_init_state,
> };
>
> -static const struct regmap_config sensor_regmap_config = {
> - .reg_bits = 16,
> - .val_bits = 8,
> - .cache_type = REGCACHE_MAPLE,
> -};
> -
> static int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
> {
> unsigned int i;
> @@ -992,10 +938,10 @@ static int imx214_probe(struct i2c_client *client)
> return dev_err_probe(dev, PTR_ERR(imx214->enable_gpio),
> "failed to get enable gpio\n");
>
> - imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
> + imx214->regmap = devm_cci_regmap_init_i2c(client, 16);
> if (IS_ERR(imx214->regmap))
> return dev_err_probe(dev, PTR_ERR(imx214->regmap),
> - "regmap init failed\n");
> + "failed to initialize CCI\n");
>
> v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
> imx214->sd.internal_ops = &imx214_internal_ops;
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe()
2024-09-02 21:54 ` [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe() André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Error handling in probe() can be a bit simpler with dev_err_probe().
>
Acked-by: Ricardo Ribalda <ribalda@chromium.org>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 52 ++++++++++++++++++++--------------------------
> 1 file changed, 22 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 283d4783c22e..ad2f1db6baeb 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -931,14 +931,12 @@ static int imx214_parse_fwnode(struct device *dev)
> int ret;
>
> endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
> - if (!endpoint) {
> - dev_err(dev, "endpoint node not found\n");
> - return -EINVAL;
> - }
> + if (!endpoint)
> + return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
>
> ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
> if (ret) {
> - dev_err(dev, "parsing endpoint node failed\n");
> + dev_err_probe(dev, ret, "parsing endpoint node failed\n");
> goto done;
> }
>
> @@ -947,8 +945,9 @@ static int imx214_parse_fwnode(struct device *dev)
> break;
>
> if (i == bus_cfg.nr_of_link_frequencies) {
> - dev_err(dev, "link-frequencies %d not supported, Please review your DT\n",
> - IMX214_DEFAULT_LINK_FREQ);
> + dev_err_probe(dev, -EINVAL,
> + "link-frequencies %d not supported, Please review your DT\n",
> + IMX214_DEFAULT_LINK_FREQ);
> ret = -EINVAL;
> goto done;
> }
> @@ -976,34 +975,27 @@ static int imx214_probe(struct i2c_client *client)
> imx214->dev = dev;
>
> imx214->xclk = devm_clk_get(dev, NULL);
> - if (IS_ERR(imx214->xclk)) {
> - dev_err(dev, "could not get xclk");
> - return PTR_ERR(imx214->xclk);
> - }
> + if (IS_ERR(imx214->xclk))
> + return dev_err_probe(dev, PTR_ERR(imx214->xclk),
> + "failed to get xclk\n");
>
> ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ);
> - if (ret) {
> - dev_err(dev, "could not set xclk frequency\n");
> - return ret;
> - }
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to set xclk frequency\n");
>
> ret = imx214_get_regulators(dev, imx214);
> - if (ret < 0) {
> - dev_err(dev, "cannot get regulators\n");
> - return ret;
> - }
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "failed to get regulators\n");
>
> imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
> - if (IS_ERR(imx214->enable_gpio)) {
> - dev_err(dev, "cannot get enable gpio\n");
> - return PTR_ERR(imx214->enable_gpio);
> - }
> + if (IS_ERR(imx214->enable_gpio))
> + return dev_err_probe(dev, PTR_ERR(imx214->enable_gpio),
> + "failed to get enable gpio\n");
>
> imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
> - if (IS_ERR(imx214->regmap)) {
> - dev_err(dev, "regmap init failed\n");
> - return PTR_ERR(imx214->regmap);
> - }
> + if (IS_ERR(imx214->regmap))
> + return dev_err_probe(dev, PTR_ERR(imx214->regmap),
> + "regmap init failed\n");
>
> v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
> imx214->sd.internal_ops = &imx214_internal_ops;
> @@ -1029,20 +1021,20 @@ static int imx214_probe(struct i2c_client *client)
>
> ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad);
> if (ret < 0) {
> - dev_err(dev, "could not register media entity\n");
> + dev_err_probe(dev, ret, "failed to init entity pads\n");
> goto free_ctrl;
> }
>
> imx214->sd.state_lock = imx214->ctrls.lock;
> ret = v4l2_subdev_init_finalize(&imx214->sd);
> if (ret < 0) {
> - dev_err(dev, "subdev init error: %d\n", ret);
> + dev_err_probe(dev, ret, "subdev init error\n");
> goto free_entity;
> }
>
> ret = v4l2_async_register_subdev_sensor(&imx214->sd);
> if (ret < 0) {
> - dev_err(dev, "could not register v4l2 device\n");
> + dev_err_probe(dev, ret, "failed to register sensor sub-device\n");
> goto error_subdev_cleanup;
> }
>
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 01/13] media: i2c: imx214: Use subdev active state
2024-09-02 21:54 ` [PATCH 01/13] media: i2c: imx214: Use subdev active state André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi Andre
I don't have access to the hardware anymore, so I cannot test this...
but looking at the code I am not sure how it is working...
I would assume that after moving to the subdev active state, you need to remove
struct v4l2_mbus_framefmt fmt;
struct v4l2_rect crop;
for struct imx214.
After this patch it looks like you have left the driver in a state
where it is using imx214->fmt in imx214_start_streaming() and the
subdev active state in others.
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Port the imx214 sensor driver to use the subdev active state.
>
> Move all the format configuration to the subdevice state and simplify
> the format handling, locking and initialization.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 129 +++++++++++++--------------------------------
> 1 file changed, 38 insertions(+), 91 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 4962cfe7c83d..58f3c3f67e0d 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -71,12 +71,6 @@ struct imx214 {
> struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
>
> struct gpio_desc *enable_gpio;
> -
> - /*
> - * Serialize control access, get/set format, get selection
> - * and start streaming.
> - */
> - struct mutex mutex;
> };
>
> struct reg_8 {
> @@ -490,6 +484,22 @@ static int __maybe_unused imx214_power_off(struct device *dev)
> return 0;
> }
>
> +static void imx214_update_pad_format(struct imx214 *imx214,
> + const struct imx214_mode *mode,
> + struct v4l2_mbus_framefmt *fmt, u32 code)
> +{
> + fmt->code = IMX214_MBUS_CODE;
> + fmt->width = mode->width;
> + fmt->height = mode->height;
> + fmt->field = V4L2_FIELD_NONE;
> + fmt->colorspace = V4L2_COLORSPACE_SRGB;
> + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
> + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
> + fmt->colorspace,
> + fmt->ycbcr_enc);
> + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
> +}
> +
> static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_mbus_code_enum *code)
> @@ -549,52 +559,6 @@ static const struct v4l2_subdev_core_ops imx214_core_ops = {
> #endif
> };
>
> -static struct v4l2_mbus_framefmt *
> -__imx214_get_pad_format(struct imx214 *imx214,
> - struct v4l2_subdev_state *sd_state,
> - unsigned int pad,
> - enum v4l2_subdev_format_whence which)
> -{
> - switch (which) {
> - case V4L2_SUBDEV_FORMAT_TRY:
> - return v4l2_subdev_state_get_format(sd_state, pad);
> - case V4L2_SUBDEV_FORMAT_ACTIVE:
> - return &imx214->fmt;
> - default:
> - return NULL;
> - }
> -}
> -
> -static int imx214_get_format(struct v4l2_subdev *sd,
> - struct v4l2_subdev_state *sd_state,
> - struct v4l2_subdev_format *format)
> -{
> - struct imx214 *imx214 = to_imx214(sd);
> -
> - mutex_lock(&imx214->mutex);
> - format->format = *__imx214_get_pad_format(imx214, sd_state,
> - format->pad,
> - format->which);
> - mutex_unlock(&imx214->mutex);
> -
> - return 0;
> -}
> -
> -static struct v4l2_rect *
> -__imx214_get_pad_crop(struct imx214 *imx214,
> - struct v4l2_subdev_state *sd_state,
> - unsigned int pad, enum v4l2_subdev_format_whence which)
> -{
> - switch (which) {
> - case V4L2_SUBDEV_FORMAT_TRY:
> - return v4l2_subdev_state_get_crop(sd_state, pad);
> - case V4L2_SUBDEV_FORMAT_ACTIVE:
> - return &imx214->crop;
> - default:
> - return NULL;
> - }
> -}
> -
> static int imx214_set_format(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_format *format)
> @@ -604,34 +568,19 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> struct v4l2_rect *__crop;
> const struct imx214_mode *mode;
>
> - mutex_lock(&imx214->mutex);
> -
> - __crop = __imx214_get_pad_crop(imx214, sd_state, format->pad,
> - format->which);
> -
> mode = v4l2_find_nearest_size(imx214_modes,
> ARRAY_SIZE(imx214_modes), width, height,
> format->format.width,
> format->format.height);
>
> - __crop->width = mode->width;
> - __crop->height = mode->height;
> + imx214_update_pad_format(imx214, mode, &format->format, format->format.code);
>
> - __format = __imx214_get_pad_format(imx214, sd_state, format->pad,
> - format->which);
> - __format->width = __crop->width;
> - __format->height = __crop->height;
> - __format->code = IMX214_MBUS_CODE;
> - __format->field = V4L2_FIELD_NONE;
> - __format->colorspace = V4L2_COLORSPACE_SRGB;
> - __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace);
> - __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
> - __format->colorspace, __format->ycbcr_enc);
> - __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace);
> + __format = v4l2_subdev_state_get_format(sd_state, 0);
> + *__format = format->format;
>
> - format->format = *__format;
> -
> - mutex_unlock(&imx214->mutex);
> + __crop = v4l2_subdev_state_get_crop(sd_state, 0);
> + __crop->width = mode->width;
> + __crop->height = mode->height;
>
> return 0;
> }
> @@ -640,14 +589,9 @@ static int imx214_get_selection(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_selection *sel)
> {
> - struct imx214 *imx214 = to_imx214(sd);
> -
> switch (sel->target) {
> case V4L2_SEL_TGT_CROP:
> - mutex_lock(&imx214->mutex);
> - sel->r = *__imx214_get_pad_crop(imx214, sd_state, sel->pad,
> - sel->which);
> - mutex_unlock(&imx214->mutex);
> + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
> return 0;
>
> case V4L2_SEL_TGT_NATIVE_SIZE:
> @@ -829,7 +773,6 @@ static int imx214_start_streaming(struct imx214 *imx214)
> const struct imx214_mode *mode;
> int ret;
>
> - mutex_lock(&imx214->mutex);
> ret = imx214_write_table(imx214, mode_table_common);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sent common table %d\n", ret);
> @@ -855,11 +798,9 @@ static int imx214_start_streaming(struct imx214 *imx214)
> goto error;
> }
>
> - mutex_unlock(&imx214->mutex);
> return 0;
>
> error:
> - mutex_unlock(&imx214->mutex);
> return ret;
> }
>
> @@ -877,6 +818,7 @@ static int imx214_stop_streaming(struct imx214 *imx214)
> static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
> {
> struct imx214 *imx214 = to_imx214(subdev);
> + struct v4l2_subdev_state *state;
> int ret;
>
> if (enable) {
> @@ -884,7 +826,9 @@ static int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
> if (ret < 0)
> return ret;
>
> + state = v4l2_subdev_lock_and_get_active_state(subdev);
> ret = imx214_start_streaming(imx214);
> + v4l2_subdev_unlock_state(state);
> if (ret < 0)
> goto err_rpm_put;
> } else {
> @@ -948,7 +892,7 @@ static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
> .enum_mbus_code = imx214_enum_mbus_code,
> .enum_frame_size = imx214_enum_frame_size,
> .enum_frame_interval = imx214_enum_frame_interval,
> - .get_fmt = imx214_get_format,
> + .get_fmt = v4l2_subdev_get_fmt,
> .set_fmt = imx214_set_format,
> .get_selection = imx214_get_selection,
> .get_frame_interval = imx214_get_frame_interval,
> @@ -1083,9 +1027,6 @@ static int imx214_probe(struct i2c_client *client)
> if (ret < 0)
> goto error_power_off;
>
> - mutex_init(&imx214->mutex);
> - imx214->ctrls.lock = &imx214->mutex;
> -
> imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> imx214->pad.flags = MEDIA_PAD_FL_SOURCE;
> imx214->sd.dev = &client->dev;
> @@ -1097,20 +1038,27 @@ static int imx214_probe(struct i2c_client *client)
> goto free_ctrl;
> }
>
> - imx214_entity_init_state(&imx214->sd, NULL);
> + imx214->sd.state_lock = imx214->ctrls.lock;
> + ret = v4l2_subdev_init_finalize(&imx214->sd);
> + if (ret < 0) {
> + dev_err(dev, "subdev init error: %d\n", ret);
> + goto free_entity;
> + }
>
> ret = v4l2_async_register_subdev_sensor(&imx214->sd);
> if (ret < 0) {
> dev_err(dev, "could not register v4l2 device\n");
> - goto free_entity;
> + goto error_subdev_cleanup;
> }
>
> return 0;
>
> +error_subdev_cleanup:
> + v4l2_subdev_cleanup(&imx214->sd);
> +
> free_entity:
> media_entity_cleanup(&imx214->sd.entity);
> free_ctrl:
> - mutex_destroy(&imx214->mutex);
> v4l2_ctrl_handler_free(&imx214->ctrls);
> error_power_off:
> pm_runtime_disable(imx214->dev);
> @@ -1125,13 +1073,12 @@ static void imx214_remove(struct i2c_client *client)
> struct imx214 *imx214 = to_imx214(sd);
>
> v4l2_async_unregister_subdev(&imx214->sd);
> + v4l2_subdev_cleanup(sd);
> media_entity_cleanup(&imx214->sd.entity);
> v4l2_ctrl_handler_free(&imx214->ctrls);
>
> pm_runtime_disable(&client->dev);
> pm_runtime_set_suspended(&client->dev);
> -
> - mutex_destroy(&imx214->mutex);
> }
>
> static const struct of_device_id imx214_of_match[] = {
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 02/13] media: i2c: imx214: Remove unneeded goto
2024-09-02 21:54 ` [PATCH 02/13] media: i2c: imx214: Remove unneeded goto André Apitzsch via B4 Relay
@ 2024-09-12 13:40 ` Ricardo Ribalda Delgado
0 siblings, 0 replies; 35+ messages in thread
From: Ricardo Ribalda Delgado @ 2024-09-12 13:40 UTC (permalink / raw)
To: git
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi Andre
On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> Simplify the imx214_start_streaming() by removing unneeded goto
> statements, and the corresponding error label.
Could you squash this patch with the previous one?
Thanks!
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 13 ++++---------
> 1 file changed, 4 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 58f3c3f67e0d..283d4783c22e 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -776,7 +776,7 @@ static int imx214_start_streaming(struct imx214 *imx214)
> ret = imx214_write_table(imx214, mode_table_common);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sent common table %d\n", ret);
> - goto error;
> + return ret;
> }
>
> mode = v4l2_find_nearest_size(imx214_modes,
> @@ -785,22 +785,17 @@ static int imx214_start_streaming(struct imx214 *imx214)
> ret = imx214_write_table(imx214, mode->reg_table);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sent mode table %d\n", ret);
> - goto error;
> + return ret;
> }
> ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
> if (ret < 0) {
> dev_err(imx214->dev, "could not sync v4l2 controls\n");
> - goto error;
> + return ret;
> }
> ret = regmap_write(imx214->regmap, IMX214_REG_MODE_SELECT, IMX214_MODE_STREAMING);
> - if (ret < 0) {
> + if (ret < 0)
> dev_err(imx214->dev, "could not sent start table %d\n", ret);
> - goto error;
> - }
> -
> - return 0;
>
> -error:
> return ret;
> }
>
>
> --
> 2.46.0
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-09-12 13:40 ` Ricardo Ribalda Delgado
@ 2024-09-12 14:51 ` Dave Stevenson
2024-09-13 17:40 ` Dave Stevenson
0 siblings, 1 reply; 35+ messages in thread
From: Dave Stevenson @ 2024-09-12 14:51 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: git, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
Hi André & Ricardo
On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
<ribalda@kernel.org> wrote:
>
> Hi
>
> Arent you missing some chage in enum_frame_interval?
Raw sensors shouldn't be using [enum|set|get]_frame_interval at all
https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
The question now is how to handle the backwards compatibility for any
userspace app that might be using this driver and expecting to use the
frame_interval calls.
Seeing as it only ever allowed a fixed value of 30fps, leaving it as
is with a comment as to why it is there would be reasonable in my
view.
> On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> <devnull+git.apitzsch.eu@kernel.org> wrote:
> >
> > From: André Apitzsch <git@apitzsch.eu>
> >
> > Add vblank control to allow changing the framerate /
> > higher exposure values.
> >
> > The vblank and hblank controls are needed for libcamera support.
> >
> > While at it, fix the minimal exposure time according to the datasheet.
> >
> > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > ---
> > drivers/media/i2c/imx214.c | 112 ++++++++++++++++++++++++++++++++++++---------
> > 1 file changed, 91 insertions(+), 21 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> > index 3b422cddbdce..9f5a57aebb86 100644
> > --- a/drivers/media/i2c/imx214.c
> > +++ b/drivers/media/i2c/imx214.c
> > @@ -34,11 +34,18 @@
> >
> > /* V-TIMING internal */
> > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > +#define IMX214_VTS_MAX 0xffff
> > +
> > +#define IMX214_VBLANK_MIN 4
> > +
> > +/* HBLANK control - read only */
> > +#define IMX214_PPL_DEFAULT 5008
> >
> > /* Exposure control */
> > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > -#define IMX214_EXPOSURE_MIN 0
> > -#define IMX214_EXPOSURE_MAX 3184
> > +#define IMX214_EXPOSURE_OFFSET 10
> > +#define IMX214_EXPOSURE_MIN 1
> > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX - IMX214_EXPOSURE_OFFSET)
> > #define IMX214_EXPOSURE_STEP 1
> > #define IMX214_EXPOSURE_DEFAULT 3184
> > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > @@ -189,6 +196,8 @@ struct imx214 {
> > struct v4l2_ctrl_handler ctrls;
> > struct v4l2_ctrl *pixel_rate;
> > struct v4l2_ctrl *link_freq;
> > + struct v4l2_ctrl *vblank;
> > + struct v4l2_ctrl *hblank;
> > struct v4l2_ctrl *exposure;
> > struct v4l2_ctrl *unit_size;
> >
> > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > { IMX214_REG_X_ADD_STA, 56 },
> > { IMX214_REG_Y_ADD_STA, 408 },
> > { IMX214_REG_X_ADD_END, 4151 },
> > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > { IMX214_REG_X_ADD_STA, 1144 },
> > { IMX214_REG_Y_ADD_STA, 1020 },
> > { IMX214_REG_X_ADD_END, 3063 },
> > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence mode_table_common[] = {
> > { IMX214_REG_ORIENTATION, 0 },
> > { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > { CCI_REG8(0x4550), 0x02 },
> > { CCI_REG8(0x4601), 0x00 },
> > { CCI_REG8(0x4642), 0x05 },
> > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence mode_table_common[] = {
> > static const struct imx214_mode {
> > u32 width;
> > u32 height;
> > +
> > + /* V-timing */
> > + unsigned int vts_def;
> > +
> > unsigned int num_of_regs;
> > const struct cci_reg_sequence *reg_table;
> > } imx214_modes[] = {
> > {
> > .width = 4096,
> > .height = 2304,
> > + .vts_def = 3194,
> > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > .reg_table = mode_4096x2304,
> > },
> > {
> > .width = 1920,
> > .height = 1080,
> > + .vts_def = 3194,
> > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > .reg_table = mode_1920x1080,
> > },
> > @@ -629,6 +641,37 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> > __crop->width = mode->width;
> > __crop->height = mode->height;
> >
> > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > + int exposure_max;
> > + int exposure_def;
> > + int hblank;
> > +
> > + /* Update limits and set FPS to default */
> > + __v4l2_ctrl_modify_range(imx214->vblank, IMX214_VBLANK_MIN,
> > + IMX214_VTS_MAX - mode->height, 1,
> > + mode->vts_def - mode->height);
> > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > + mode->vts_def - mode->height);
> > +
> > + /* Update max exposure while meeting expected vblanking */
> > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > + exposure_def = (exposure_max < IMX214_EXPOSURE_DEFAULT) ?
> > + exposure_max : IMX214_EXPOSURE_DEFAULT;
> > + __v4l2_ctrl_modify_range(imx214->exposure,
> > + imx214->exposure->minimum,
> > + exposure_max, imx214->exposure->step,
> > + exposure_def);
> > +
> > + /*
> > + * Currently PPL is fixed to IMX214_PPL_DEFAULT, so hblank
> > + * depends on mode->width only, and is not changeble in any
> > + * way other than changing the mode.
> > + */
> > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > + __v4l2_ctrl_modify_range(imx214->hblank, hblank, hblank, 1,
> > + hblank);
> > + }
> > +
> > return 0;
> > }
> >
> > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> > {
> > struct imx214 *imx214 = container_of(ctrl->handler,
> > struct imx214, ctrls);
> > + const struct v4l2_mbus_framefmt *format;
> > + struct v4l2_subdev_state *state;
> > int ret;
> >
> > + state = v4l2_subdev_get_locked_active_state(&imx214->sd);
> > + format = v4l2_subdev_state_get_format(state, 0);
> > +
> > + if (ctrl->id == V4L2_CID_VBLANK) {
> > + int exposure_max, exposure_def;
> > +
> > + /* Update max exposure while meeting expected vblanking */
> > + exposure_max = format->height + ctrl->val - IMX214_EXPOSURE_OFFSET;
> > + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> > + __v4l2_ctrl_modify_range(imx214->exposure,
> > + imx214->exposure->minimum,
> > + exposure_max, imx214->exposure->step,
> > + exposure_def);
> > + }
> > +
> > /*
> > * Applying V4L2 control value only happens
> > * when power is up for streaming
> > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> > case V4L2_CID_EXPOSURE:
> > cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> > break;
> > -
> > + case V4L2_CID_VBLANK:
> > + cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> > + format->height + ctrl->val, &ret);
My datasheet says this register is "set up in multiples of 2".
(LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
I don't have one of these modules, but is that saying only multiples
of 2 are permitted (in which case the step size for the control needs
to reflect that), or that setting a value of N is interpreted by the
hardware as 2N?
Do all the numbers with PIXEL_RATE work out correctly in the frame rate calcs?
Reading the spec sheet that 30fps is the max frame rate at full res
(4096x2304), and the driver was setting a value of 3194 to this
register, I don't see it being interpreted as 2N. Then again having
VBLANK at 890 seems pretty high.
> > + break;
> > default:
> > ret = -EINVAL;
> > }
> > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > .width = 1120,
> > .height = 1120,
> > };
> > + const struct imx214_mode *mode = &imx214_modes[0];
> > struct v4l2_fwnode_device_properties props;
> > struct v4l2_ctrl_handler *ctrl_hdlr;
> > + int exposure_max, exposure_def;
> > + int hblank;
> > int ret;
> >
> > ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > return ret;
> >
> > ctrl_hdlr = &imx214->ctrls;
> > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > if (ret)
> > return ret;
> >
> > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > if (imx214->link_freq)
> > imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> >
> > - /*
> > - * WARNING!
> > - * Values obtained reverse engineering blobs and/or devices.
> > - * Ranges and functionality might be wrong.
> > - *
> > - * Sony, please release some register set documentation for the
> > - * device.
> > - *
> > - * Yours sincerely, Ricardo.
> > - */
>
> I would like to keep this comment until there is a public document available.
I suspect you'll be waiting forever for a document to be officially released.
I have a datasheet for IMX214, and I believe Kieran and Jacopo do too.
Which specific values do you wish to be verified?
>
> > + /* Initial vblank/hblank/exposure parameters based on current mode */
> > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > + V4L2_CID_VBLANK, IMX214_VBLANK_MIN,
IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
I read the datasheet to say there are 4 embedded data lines per image.
Seeing as you have STATS data output enabled as well that makes 5
lines of non-image data per frame, but you're only adding blanking
time for 4 lines.
As noted above, I think you've also increased the max frame rate
significantly above that quoted by Sony. Has that been actually
exercised and confirmed to function correctly?
Dave
> > + IMX214_VTS_MAX - mode->height, 1,
> > + mode->vts_def - mode->height);
> > +
> > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > + V4L2_CID_HBLANK, hblank, hblank,
> > + 1, hblank);
> > + if (imx214->hblank)
> > + imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +
> > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > V4L2_CID_EXPOSURE,
> > - IMX214_EXPOSURE_MIN,
> > - IMX214_EXPOSURE_MAX,
> > + IMX214_EXPOSURE_MIN, exposure_max,
> > IMX214_EXPOSURE_STEP,
> > - IMX214_EXPOSURE_DEFAULT);
> > + exposure_def);
> >
> > imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > NULL,
> >
> > --
> > 2.46.0
> >
> >
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls
2024-09-02 21:54 ` [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
@ 2024-09-12 15:16 ` Dave Stevenson
1 sibling, 0 replies; 35+ messages in thread
From: Dave Stevenson @ 2024-09-12 15:16 UTC (permalink / raw)
To: git
Cc: Ricardo Ribalda, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
Hi André
On Mon, 2 Sept 2024 at 22:54, André Apitzsch via B4 Relay
<devnull+git.apitzsch.eu@kernel.org> wrote:
>
> From: André Apitzsch <git@apitzsch.eu>
>
> The imx214 sensor supports horizontal and vertical flipping. Add
> appropriate controls to the driver.
>
> Signed-off-by: André Apitzsch <git@apitzsch.eu>
> ---
> drivers/media/i2c/imx214.c | 73 +++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 65 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> index 733f55257585..4a1433728cd5 100644
> --- a/drivers/media/i2c/imx214.c
> +++ b/drivers/media/i2c/imx214.c
> @@ -30,7 +30,6 @@
> #define IMX214_DEFAULT_LINK_FREQ 480000000
> #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
> #define IMX214_FPS 30
> -#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
>
> /* V-TIMING internal */
> #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> @@ -186,6 +185,22 @@ static const char * const imx214_supply_name[] = {
>
> #define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name)
>
> +/*
> + * The supported formats.
> + * This table MUST contain 4 entries per format, to cover the various flip
> + * combinations in the order
> + * - no flip
> + * - h flip
> + * - v flip
> + * - h&v flips
> + */
> +static const u32 imx214_mbus_formats[] = {
> + MEDIA_BUS_FMT_SRGGB10_1X10,
> + MEDIA_BUS_FMT_SGRBG10_1X10,
> + MEDIA_BUS_FMT_SGBRG10_1X10,
> + MEDIA_BUS_FMT_SBGGR10_1X10,
> +};
> +
> struct imx214 {
> struct device *dev;
> struct clk *xclk;
> @@ -202,6 +217,8 @@ struct imx214 {
> struct v4l2_ctrl *vblank;
> struct v4l2_ctrl *hblank;
> struct v4l2_ctrl *exposure;
> + struct v4l2_ctrl *vflip;
> + struct v4l2_ctrl *hflip;
> struct v4l2_ctrl *unit_size;
>
> struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES];
> @@ -339,7 +356,6 @@ static const struct cci_reg_sequence mode_table_common[] = {
>
> /* global setting */
> /* basic config */
> - { IMX214_REG_ORIENTATION, 0 },
> { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> @@ -518,11 +534,29 @@ static int __maybe_unused imx214_power_off(struct device *dev)
> return 0;
> }
>
> +/* Get bayer order based on flip setting. */
> +static u32 imx214_get_format_code(struct imx214 *imx214, u32 code)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < ARRAY_SIZE(imx214_mbus_formats); i++)
> + if (imx214_mbus_formats[i] == code)
> + break;
> +
> + if (i >= ARRAY_SIZE(imx214_mbus_formats))
> + i = 0;
> +
> + i = (i & ~3) | (imx214->vflip->val ? 2 : 0) |
> + (imx214->hflip->val ? 1 : 0);
> +
> + return imx214_mbus_formats[i];
> +}
> +
> static void imx214_update_pad_format(struct imx214 *imx214,
> const struct imx214_mode *mode,
> struct v4l2_mbus_framefmt *fmt, u32 code)
> {
> - fmt->code = IMX214_MBUS_CODE;
> + fmt->code = imx214_get_format_code(imx214, code);
> fmt->width = mode->width;
> fmt->height = mode->height;
> fmt->field = V4L2_FIELD_NONE;
> @@ -538,10 +572,12 @@ static int imx214_enum_mbus_code(struct v4l2_subdev *sd,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_mbus_code_enum *code)
> {
> - if (code->index > 0)
> + struct imx214 *imx214 = to_imx214(sd);
> +
> + if (code->index >= (ARRAY_SIZE(imx214_mbus_formats) / 4))
> return -EINVAL;
>
> - code->code = IMX214_MBUS_CODE;
> + code->code = imx214_get_format_code(imx214, imx214_mbus_formats[code->index * 4]);
>
> return 0;
> }
> @@ -550,7 +586,11 @@ static int imx214_enum_frame_size(struct v4l2_subdev *subdev,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_frame_size_enum *fse)
> {
> - if (fse->code != IMX214_MBUS_CODE)
> + struct imx214 *imx214 = to_imx214(subdev);
> + u32 code;
> +
> + code = imx214_get_format_code(imx214, fse->code);
> + if (fse->code != code)
> return -EINVAL;
>
> if (fse->index >= ARRAY_SIZE(imx214_modes))
> @@ -708,6 +748,7 @@ static int imx214_entity_init_state(struct v4l2_subdev *subdev,
> struct v4l2_subdev_format fmt = { };
>
> fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
> + fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10;
> fmt.format.width = imx214_modes[0].width;
> fmt.format.height = imx214_modes[0].height;
>
> @@ -750,6 +791,11 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> case V4L2_CID_EXPOSURE:
> cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> break;
> + case V4L2_CID_HFLIP:
> + case V4L2_CID_VFLIP:
> + cci_write(imx214->regmap, IMX214_REG_ORIENTATION,
> + imx214->hflip->val | imx214->vflip->val << 1, &ret);
> + break;
> case V4L2_CID_VBLANK:
> cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> format->height + ctrl->val, &ret);
> @@ -788,7 +834,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> return ret;
>
> ctrl_hdlr = &imx214->ctrls;
> - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 10);
> if (ret)
> return ret;
>
> @@ -825,6 +871,16 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> IMX214_EXPOSURE_STEP,
> exposure_def);
>
> + imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_HFLIP, 0, 1, 1, 0);
> + if (imx214->hflip)
> + imx214->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> +
> + imx214->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> + V4L2_CID_VFLIP, 0, 1, 1, 0);
> + if (imx214->vflip)
> + imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> +
A minor optimisation.
Currently a VIDIOC_S_EXT_CTRLS with both HFLIP and VFLIP in the list
will call your set_ctrl function twice, which gives a redundant update
to the register.
Define the two controls as a cluster via v4l2_ctrl_cluster(), and
you'll only get called once.
See ccs-core.c or imx290.c for an example, and docs at
https://www.kernel.org/doc/html/latest/driver-api/media/v4l2-controls.html#control-clusters
Dave
> imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> NULL,
> V4L2_CID_UNIT_CELL_SIZE,
> @@ -1034,6 +1090,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
> struct v4l2_subdev_state *sd_state,
> struct v4l2_subdev_frame_interval_enum *fie)
> {
> + struct imx214 *imx214 = to_imx214(subdev);
> const struct imx214_mode *mode;
>
> if (fie->index != 0)
> @@ -1043,7 +1100,7 @@ static int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
> ARRAY_SIZE(imx214_modes), width, height,
> fie->width, fie->height);
>
> - fie->code = IMX214_MBUS_CODE;
> + fie->code = imx214_get_format_code(imx214, fie->code);
> fie->width = mode->width;
> fie->height = mode->height;
> fie->interval.numerator = 1;
>
> --
> 2.46.0
>
>
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-09-12 14:51 ` Dave Stevenson
@ 2024-09-13 17:40 ` Dave Stevenson
2024-10-06 21:41 ` André
0 siblings, 1 reply; 35+ messages in thread
From: Dave Stevenson @ 2024-09-13 17:40 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: git, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
On Thu, 12 Sept 2024 at 15:51, Dave Stevenson
<dave.stevenson@raspberrypi.com> wrote:
>
> Hi André & Ricardo
>
> On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
> <ribalda@kernel.org> wrote:
> >
> > Hi
> >
> > Arent you missing some chage in enum_frame_interval?
>
> Raw sensors shouldn't be using [enum|set|get]_frame_interval at all
> https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
>
> The question now is how to handle the backwards compatibility for any
> userspace app that might be using this driver and expecting to use the
> frame_interval calls.
> Seeing as it only ever allowed a fixed value of 30fps, leaving it as
> is with a comment as to why it is there would be reasonable in my
> view.
>
> > On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> > <devnull+git.apitzsch.eu@kernel.org> wrote:
> > >
> > > From: André Apitzsch <git@apitzsch.eu>
> > >
> > > Add vblank control to allow changing the framerate /
> > > higher exposure values.
> > >
> > > The vblank and hblank controls are needed for libcamera support.
> > >
> > > While at it, fix the minimal exposure time according to the datasheet.
> > >
> > > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > > ---
> > > drivers/media/i2c/imx214.c | 112 ++++++++++++++++++++++++++++++++++++---------
> > > 1 file changed, 91 insertions(+), 21 deletions(-)
> > >
> > > diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c
> > > index 3b422cddbdce..9f5a57aebb86 100644
> > > --- a/drivers/media/i2c/imx214.c
> > > +++ b/drivers/media/i2c/imx214.c
> > > @@ -34,11 +34,18 @@
> > >
> > > /* V-TIMING internal */
> > > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > > +#define IMX214_VTS_MAX 0xffff
> > > +
> > > +#define IMX214_VBLANK_MIN 4
> > > +
> > > +/* HBLANK control - read only */
> > > +#define IMX214_PPL_DEFAULT 5008
> > >
> > > /* Exposure control */
> > > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > > -#define IMX214_EXPOSURE_MIN 0
> > > -#define IMX214_EXPOSURE_MAX 3184
> > > +#define IMX214_EXPOSURE_OFFSET 10
> > > +#define IMX214_EXPOSURE_MIN 1
> > > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX - IMX214_EXPOSURE_OFFSET)
> > > #define IMX214_EXPOSURE_STEP 1
> > > #define IMX214_EXPOSURE_DEFAULT 3184
> > > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > > @@ -189,6 +196,8 @@ struct imx214 {
> > > struct v4l2_ctrl_handler ctrls;
> > > struct v4l2_ctrl *pixel_rate;
> > > struct v4l2_ctrl *link_freq;
> > > + struct v4l2_ctrl *vblank;
> > > + struct v4l2_ctrl *hblank;
> > > struct v4l2_ctrl *exposure;
> > > struct v4l2_ctrl *unit_size;
> > >
> > > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence mode_4096x2304[] = {
> > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > { IMX214_REG_X_ADD_STA, 56 },
> > > { IMX214_REG_Y_ADD_STA, 408 },
> > > { IMX214_REG_X_ADD_END, 4151 },
> > > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence mode_1920x1080[] = {
> > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH },
> > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > { IMX214_REG_X_ADD_STA, 1144 },
> > > { IMX214_REG_Y_ADD_STA, 1020 },
> > > { IMX214_REG_X_ADD_END, 3063 },
> > > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence mode_table_common[] = {
> > > { IMX214_REG_ORIENTATION, 0 },
> > > { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK },
> > > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > > { CCI_REG8(0x4550), 0x02 },
> > > { CCI_REG8(0x4601), 0x00 },
> > > { CCI_REG8(0x4642), 0x05 },
> > > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence mode_table_common[] = {
> > > static const struct imx214_mode {
> > > u32 width;
> > > u32 height;
> > > +
> > > + /* V-timing */
> > > + unsigned int vts_def;
> > > +
> > > unsigned int num_of_regs;
> > > const struct cci_reg_sequence *reg_table;
> > > } imx214_modes[] = {
> > > {
> > > .width = 4096,
> > > .height = 2304,
> > > + .vts_def = 3194,
> > > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > > .reg_table = mode_4096x2304,
> > > },
> > > {
> > > .width = 1920,
> > > .height = 1080,
> > > + .vts_def = 3194,
> > > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > > .reg_table = mode_1920x1080,
> > > },
> > > @@ -629,6 +641,37 @@ static int imx214_set_format(struct v4l2_subdev *sd,
> > > __crop->width = mode->width;
> > > __crop->height = mode->height;
> > >
> > > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > > + int exposure_max;
> > > + int exposure_def;
> > > + int hblank;
> > > +
> > > + /* Update limits and set FPS to default */
> > > + __v4l2_ctrl_modify_range(imx214->vblank, IMX214_VBLANK_MIN,
> > > + IMX214_VTS_MAX - mode->height, 1,
> > > + mode->vts_def - mode->height);
> > > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > > + mode->vts_def - mode->height);
> > > +
> > > + /* Update max exposure while meeting expected vblanking */
> > > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > > + exposure_def = (exposure_max < IMX214_EXPOSURE_DEFAULT) ?
> > > + exposure_max : IMX214_EXPOSURE_DEFAULT;
> > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > + imx214->exposure->minimum,
> > > + exposure_max, imx214->exposure->step,
> > > + exposure_def);
> > > +
> > > + /*
> > > + * Currently PPL is fixed to IMX214_PPL_DEFAULT, so hblank
> > > + * depends on mode->width only, and is not changeble in any
> > > + * way other than changing the mode.
> > > + */
> > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > + __v4l2_ctrl_modify_range(imx214->hblank, hblank, hblank, 1,
> > > + hblank);
> > > + }
> > > +
> > > return 0;
> > > }
> > >
> > > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> > > {
> > > struct imx214 *imx214 = container_of(ctrl->handler,
> > > struct imx214, ctrls);
> > > + const struct v4l2_mbus_framefmt *format;
> > > + struct v4l2_subdev_state *state;
> > > int ret;
> > >
> > > + state = v4l2_subdev_get_locked_active_state(&imx214->sd);
> > > + format = v4l2_subdev_state_get_format(state, 0);
> > > +
> > > + if (ctrl->id == V4L2_CID_VBLANK) {
> > > + int exposure_max, exposure_def;
> > > +
> > > + /* Update max exposure while meeting expected vblanking */
> > > + exposure_max = format->height + ctrl->val - IMX214_EXPOSURE_OFFSET;
> > > + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > + imx214->exposure->minimum,
> > > + exposure_max, imx214->exposure->step,
> > > + exposure_def);
> > > + }
> > > +
> > > /*
> > > * Applying V4L2 control value only happens
> > > * when power is up for streaming
> > > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
> > > case V4L2_CID_EXPOSURE:
> > > cci_write(imx214->regmap, IMX214_REG_EXPOSURE, ctrl->val, &ret);
> > > break;
> > > -
> > > + case V4L2_CID_VBLANK:
> > > + cci_write(imx214->regmap, IMX214_REG_FRM_LENGTH_LINES,
> > > + format->height + ctrl->val, &ret);
>
> My datasheet says this register is "set up in multiples of 2".
> (LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
>
> I don't have one of these modules, but is that saying only multiples
> of 2 are permitted (in which case the step size for the control needs
> to reflect that), or that setting a value of N is interpreted by the
> hardware as 2N?
> Do all the numbers with PIXEL_RATE work out correctly in the frame rate calcs?
Answering my own question, PIXEL_RATE looks dubious.
The original code had LINE_LENGTH_PCK as 5008, and FRAME_LENGTH_LINES
as 3194. If enum_frame_intervals is to be believed, then it delivered
30fps.
5008 * 3194 * 30 = 479,866,560 Pix/s.
The driver defines IMX214_DEFAULT_LINK_FREQ 480000000, and then
IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10),
which works out as 384MPix/s. (Presumably the 8 is 4 lanes and DDR,
but it's not obvious)
Parsing the PLL registers with the defined 24MHz input. We're in
single PLL mode, so MIPI frequency is directly linked to pixel rate.
VTCK ends up being 1200MHz, and VTPXCK and OPPXCK both are 120MHz.
Section 5.3 "Frame rate calculation formula" says "Pixel rate
[pixels/s] = VTPXCK [MHz] * 4", so 120 * 4 = 480MPix/s, which
basically agrees with my number above.
3.1.4. MIPI global timing setting says "Output bitrate = OPPXCK * reg
0x113[7:0]", so 120MHz * 10, or 1200Mbit/s. That would be a link
frequency of 600MHz due to DDR.
That also matches to 480MPix/s * 10bpp / 4 lanes / 2 for DDR
Registers 0x0820-0823 are meant to define the target CSI2 bitrate, and
are set to 0x12c00000, or 314,572,800 decimal. I can't get that to
square with the above.
So my conclusion is that both PIXEL_RATE and LINK_FREQUENCY are wrong,
however the relationship used to define them looks to be correct.
Correct IMX214_DEFAULT_LINK_FREQ to 600MHz, and all should be good.
However you almost certainly want to set IMX214_VBLANK_MIN to
something significantly greater than 4.
Dave
> Reading the spec sheet that 30fps is the max frame rate at full res
> (4096x2304), and the driver was setting a value of 3194 to this
> register, I don't see it being interpreted as 2N. Then again having
> VBLANK at 890 seems pretty high.
>
> > > + break;
> > > default:
> > > ret = -EINVAL;
> > > }
> > > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > > .width = 1120,
> > > .height = 1120,
> > > };
> > > + const struct imx214_mode *mode = &imx214_modes[0];
> > > struct v4l2_fwnode_device_properties props;
> > > struct v4l2_ctrl_handler *ctrl_hdlr;
> > > + int exposure_max, exposure_def;
> > > + int hblank;
> > > int ret;
> > >
> > > ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> > > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > > return ret;
> > >
> > > ctrl_hdlr = &imx214->ctrls;
> > > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > > if (ret)
> > > return ret;
> > >
> > > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct imx214 *imx214)
> > > if (imx214->link_freq)
> > > imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > >
> > > - /*
> > > - * WARNING!
> > > - * Values obtained reverse engineering blobs and/or devices.
> > > - * Ranges and functionality might be wrong.
> > > - *
> > > - * Sony, please release some register set documentation for the
> > > - * device.
> > > - *
> > > - * Yours sincerely, Ricardo.
> > > - */
> >
> > I would like to keep this comment until there is a public document available.
>
> I suspect you'll be waiting forever for a document to be officially released.
>
> I have a datasheet for IMX214, and I believe Kieran and Jacopo do too.
> Which specific values do you wish to be verified?
>
> >
> > > + /* Initial vblank/hblank/exposure parameters based on current mode */
> > > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > > + V4L2_CID_VBLANK, IMX214_VBLANK_MIN,
>
> IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
> I read the datasheet to say there are 4 embedded data lines per image.
> Seeing as you have STATS data output enabled as well that makes 5
> lines of non-image data per frame, but you're only adding blanking
> time for 4 lines.
>
> As noted above, I think you've also increased the max frame rate
> significantly above that quoted by Sony. Has that been actually
> exercised and confirmed to function correctly?
>
> Dave
>
> > > + IMX214_VTS_MAX - mode->height, 1,
> > > + mode->vts_def - mode->height);
> > > +
> > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > > + V4L2_CID_HBLANK, hblank, hblank,
> > > + 1, hblank);
> > > + if (imx214->hblank)
> > > + imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > > +
> > > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > > + exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT);
> > > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops,
> > > V4L2_CID_EXPOSURE,
> > > - IMX214_EXPOSURE_MIN,
> > > - IMX214_EXPOSURE_MAX,
> > > + IMX214_EXPOSURE_MIN, exposure_max,
> > > IMX214_EXPOSURE_STEP,
> > > - IMX214_EXPOSURE_DEFAULT);
> > > + exposure_def);
> > >
> > > imx214->unit_size = v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > > NULL,
> > >
> > > --
> > > 2.46.0
> > >
> > >
> >
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 09/13] media: i2c: imx214: Extract format and crop settings
2024-09-12 13:40 ` Ricardo Ribalda Delgado
@ 2024-10-06 21:28 ` André
0 siblings, 0 replies; 35+ messages in thread
From: André @ 2024-10-06 21:28 UTC (permalink / raw)
To: Ricardo Ribalda Delgado
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi Ricardo,
Am Donnerstag, dem 12.09.2024 um 15:40 +0200 schrieb Ricardo Ribalda
Delgado:
> On Mon, Sep 2, 2024 at 11:54 PM André Apitzsch via B4 Relay
> <devnull+git.apitzsch.eu@kernel.org> wrote:
> >
> > From: André Apitzsch <git@apitzsch.eu>
> >
> > Remove format and crop settings from register sequences and set
> > them
> > programmatically.
> >
> > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > ---
> > drivers/media/i2c/imx214.c | 137
> > ++++++++++++++++++++++++++++++++++-----------
> > 1 file changed, 105 insertions(+), 32 deletions(-)
> >
> > diff --git a/drivers/media/i2c/imx214.c
> > b/drivers/media/i2c/imx214.c
> > index 9f5a57aebb86..733f55257585 100644
> > --- a/drivers/media/i2c/imx214.c
> > +++ b/drivers/media/i2c/imx214.c
> > @@ -132,6 +132,9 @@
> > #define IMX214_BINNING_NONE 0
> > #define IMX214_BINNING_ENABLE 1
> > #define IMX214_REG_BINNING_TYPE CCI_REG8(0x0901)
> > +#define IMX214_BINNING_1X1 0
> > +#define IMX214_BINNING_2X2 0x22
> > +#define IMX214_BINNING_4X4 0x44
> > #define IMX214_REG_BINNING_WEIGHTING CCI_REG8(0x0902)
> > #define IMX214_BINNING_AVERAGE 0x00
> > #define IMX214_BINNING_SUMMED 0x01
> > @@ -214,36 +217,22 @@ static const struct cci_reg_sequence
> > mode_4096x2304[] = {
> > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH
> > },
> > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > - { IMX214_REG_X_ADD_STA, 56 },
> > - { IMX214_REG_Y_ADD_STA, 408 },
> > - { IMX214_REG_X_ADD_END, 4151 },
> > - { IMX214_REG_Y_ADD_END, 2711 },
> > { IMX214_REG_X_EVEN_INC, 1 },
> > { IMX214_REG_X_ODD_INC, 1 },
> > { IMX214_REG_Y_EVEN_INC, 1 },
> > { IMX214_REG_Y_ODD_INC, 1 },
> > - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> > - { IMX214_REG_BINNING_TYPE, 0 },
> > { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> > { CCI_REG8(0x3000), 0x35 },
> > { CCI_REG8(0x3054), 0x01 },
> > { CCI_REG8(0x305C), 0x11 },
> >
> > - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10
> > },
> > - { IMX214_REG_X_OUTPUT_SIZE, 4096 },
> > - { IMX214_REG_Y_OUTPUT_SIZE, 2304 },
> > { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> > { IMX214_REG_SCALE_M, 2 },
> > - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> > - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> > - { IMX214_REG_DIG_CROP_WIDTH, 4096 },
> > - { IMX214_REG_DIG_CROP_HEIGHT, 2304 },
> >
> > { IMX214_REG_VTPXCK_DIV, 5 },
> > { IMX214_REG_VTSYCK_DIV, 2 },
> > { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> > { IMX214_REG_PLL_VT_MPY, 150 },
> > - { IMX214_REG_OPPXCK_DIV, 10 },
> > { IMX214_REG_OPSYCK_DIV, 1 },
> > { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
> >
> > @@ -284,36 +273,22 @@ static const struct cci_reg_sequence
> > mode_1920x1080[] = {
> > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > { IMX214_REG_HDR_RES_REDUCTION, IMX214_HDR_RES_REDU_THROUGH
> > },
> > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > - { IMX214_REG_X_ADD_STA, 1144 },
> > - { IMX214_REG_Y_ADD_STA, 1020 },
> > - { IMX214_REG_X_ADD_END, 3063 },
> > - { IMX214_REG_Y_ADD_END, 2099 },
> > { IMX214_REG_X_EVEN_INC, 1 },
> > { IMX214_REG_X_ODD_INC, 1 },
> > { IMX214_REG_Y_EVEN_INC, 1 },
> > { IMX214_REG_Y_ODD_INC, 1 },
> > - { IMX214_REG_BINNING_MODE, IMX214_BINNING_NONE },
> > - { IMX214_REG_BINNING_TYPE, 0 },
> > { IMX214_REG_BINNING_WEIGHTING, IMX214_BINNING_AVERAGE },
> > { CCI_REG8(0x3000), 0x35 },
> > { CCI_REG8(0x3054), 0x01 },
> > { CCI_REG8(0x305C), 0x11 },
> >
> > - { IMX214_REG_CSI_DATA_FORMAT, IMX214_CSI_DATA_FORMAT_RAW10
> > },
> > - { IMX214_REG_X_OUTPUT_SIZE, 1920 },
> > - { IMX214_REG_Y_OUTPUT_SIZE, 1080 },
> > { IMX214_REG_SCALE_MODE, IMX214_SCALE_NONE },
> > { IMX214_REG_SCALE_M, 2 },
> > - { IMX214_REG_DIG_CROP_X_OFFSET, 0 },
> > - { IMX214_REG_DIG_CROP_Y_OFFSET, 0 },
> > - { IMX214_REG_DIG_CROP_WIDTH, 1920 },
> > - { IMX214_REG_DIG_CROP_HEIGHT, 1080 },
> >
> > { IMX214_REG_VTPXCK_DIV, 5 },
> > { IMX214_REG_VTSYCK_DIV, 2 },
> > { IMX214_REG_PREPLLCK_VT_DIV, 3 },
> > { IMX214_REG_PLL_VT_MPY, 150 },
> > - { IMX214_REG_OPPXCK_DIV, 10 },
> > { IMX214_REG_OPSYCK_DIV, 1 },
> > { IMX214_REG_PLL_MULT_DRIV, IMX214_PLL_SINGLE },
> >
> > @@ -626,6 +601,7 @@ static int imx214_set_format(struct v4l2_subdev
> > *sd,
> > struct v4l2_mbus_framefmt *__format;
> > struct v4l2_rect *__crop;
> > const struct imx214_mode *mode;
> > + unsigned int bin_h, bin_v, bin;
> >
> > mode = v4l2_find_nearest_size(imx214_modes,
> > ARRAY_SIZE(imx214_modes),
> > width, height,
> > @@ -637,9 +613,32 @@ static int imx214_set_format(struct
> > v4l2_subdev *sd,
> > __format = v4l2_subdev_state_get_format(sd_state, 0);
> > *__format = format->format;
> >
> > + /*
> > + * Use binning to maximize the crop rectangle size, and
> > centre it in the
> > + * sensor.
> > + */
>
> We only support two modes. Wouldn't it be easier to add a new
> "binning" field to imx124_mode?
>
I prefer this more general approach. It's similar to what is done for
imx219. And we might add more modes later.
But I'm also fine with using the "binning" field if you are in favor of
it.
> > + bin_h = IMX214_PIXEL_ARRAY_WIDTH / __format->width;
> > + bin_v = IMX214_PIXEL_ARRAY_HEIGHT / __format->height;
> > +
> > + switch (min(bin_h, bin_v)) {
> > + case 1:
> > + bin = 1;
> > + break;
> > + case 2:
> > + case 3:
> > + bin = 2;
> > + break;
> > + case 4:
> > + default:
> > + bin = 4;
> > + break;
> > + }
> > +
> > __crop = v4l2_subdev_state_get_crop(sd_state, 0);
> > - __crop->width = mode->width;
> > - __crop->height = mode->height;
> > + __crop->width = __format->width * bin;
> > + __crop->height = __format->height * bin;
> > + __crop->left = (IMX214_NATIVE_WIDTH - __crop->width) / 2;
> > + __crop->top = (IMX214_NATIVE_HEIGHT - __crop->height) / 2;
> >
> > if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > int exposure_max;
> > @@ -845,6 +844,71 @@ static int imx214_ctrls_init(struct imx214
> > *imx214)
> > return 0;
> > };
> >
> > +static int imx214_set_framefmt(struct imx214 *imx214,
> > + struct v4l2_subdev_state *state)
> > +{
> > + const struct v4l2_mbus_framefmt *format;
> > + const struct v4l2_rect *crop;
> > + unsigned int bpp;
> > + u64 bin_mode;
> > + u64 bin_type;
> > + int ret = 0;
> > +
> > + format = v4l2_subdev_state_get_format(state, 0);
> > + crop = v4l2_subdev_state_get_crop(state, 0);
> > +
>
> This code does not do anything, bpp is always 10.
> We can remove the switch and setting IMX214_REG_CSI_DATA_FORMAT
> IMX214_REG_OPPXCK_DIV programmatically
I'll simplify this.
Best regards,
André
>
>
> > + switch (format->code) {
> > + case MEDIA_BUS_FMT_SRGGB10_1X10:
> > + case MEDIA_BUS_FMT_SGRBG10_1X10:
> > + case MEDIA_BUS_FMT_SGBRG10_1X10:
> > + case MEDIA_BUS_FMT_SBGGR10_1X10:
> > + default:
> > + bpp = 10;
> > + break;
> > + }
>
>
>
> > +
> > + cci_write(imx214->regmap, IMX214_REG_X_ADD_STA,
> > + crop->left - IMX214_PIXEL_ARRAY_LEFT, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_X_ADD_END,
> > + crop->left - IMX214_PIXEL_ARRAY_LEFT + crop-
> > >width - 1, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_Y_ADD_STA,
> > + crop->top - IMX214_PIXEL_ARRAY_TOP, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_Y_ADD_END,
> > + crop->top - IMX214_PIXEL_ARRAY_TOP + crop->height
> > - 1, &ret);
> > +
> > + /* Proper setting is required even if cropping is not used
> > */
> > + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_WIDTH, crop-
> > >width, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_DIG_CROP_HEIGHT, crop-
> > >height, &ret);
> > +
> > + switch (crop->width / format->width) {
> > + case 1:
> > + default:
> > + bin_mode = IMX214_BINNING_NONE;
> > + bin_type = IMX214_BINNING_1X1;
> > + break;
> > + case 2:
> > + bin_mode = IMX214_BINNING_ENABLE;
> > + bin_type = IMX214_BINNING_2X2;
> > + break;
> > + case 4:
> > + bin_mode = IMX214_BINNING_ENABLE;
> > + bin_type = IMX214_BINNING_4X4;
> > + break;
> > + }
> > +
> > + cci_write(imx214->regmap, IMX214_REG_BINNING_MODE,
> > bin_mode, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_BINNING_TYPE,
> > bin_type, &ret);
> > +
> > + cci_write(imx214->regmap, IMX214_REG_X_OUTPUT_SIZE, format-
> > >width, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_Y_OUTPUT_SIZE, format-
> > >height, &ret);
> > +
> > + cci_write(imx214->regmap, IMX214_REG_CSI_DATA_FORMAT,
> > + (bpp << 8) | bpp, &ret);
> > + cci_write(imx214->regmap, IMX214_REG_OPPXCK_DIV, bpp,
> > &ret);
> > +
> > + return ret;
> > +};
> > +
> > static int imx214_configure_lanes(struct imx214 *imx214)
> > {
> > return cci_write(imx214->regmap, IMX214_REG_CSI_LANE_MODE,
> > @@ -852,7 +916,8 @@ static int imx214_configure_lanes(struct imx214
> > *imx214)
> > IMX214_CSI_4_LANE_MODE, NULL);
> > };
> >
> > -static int imx214_start_streaming(struct imx214 *imx214)
> > +static int imx214_start_streaming(struct imx214 *imx214,
> > + struct v4l2_subdev_state *state)
> > {
> > const struct imx214_mode *mode;
> > int ret;
> > @@ -871,6 +936,14 @@ static int imx214_start_streaming(struct
> > imx214 *imx214)
> > return ret;
> > }
> >
> > + /* Apply format and crop settings */
> > + ret = imx214_set_framefmt(imx214, state);
> > + if (ret) {
> > + dev_err(imx214->dev, "%s failed to set frame
> > format: %d\n",
> > + __func__, ret);
> > + return ret;
> > + }
> > +
> > mode = v4l2_find_nearest_size(imx214_modes,
> > ARRAY_SIZE(imx214_modes), width,
> > height,
> > imx214->fmt.width, imx214-
> > >fmt.height);
> > @@ -922,7 +995,7 @@ static int imx214_s_stream(struct v4l2_subdev
> > *subdev, int enable)
> > return ret;
> >
> > state =
> > v4l2_subdev_lock_and_get_active_state(subdev);
> > - ret = imx214_start_streaming(imx214);
> > + ret = imx214_start_streaming(imx214, state);
> > v4l2_subdev_unlock_state(state);
> > if (ret < 0)
> > goto err_rpm_put;
> >
> > --
> > 2.46.0
> >
> >
> >
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-09-13 17:40 ` Dave Stevenson
@ 2024-10-06 21:41 ` André
2024-10-07 17:29 ` Dave Stevenson
0 siblings, 1 reply; 35+ messages in thread
From: André @ 2024-10-06 21:41 UTC (permalink / raw)
To: Dave Stevenson, Ricardo Ribalda Delgado
Cc: Sakari Ailus, Mauro Carvalho Chehab, ~postmarketos/upstreaming,
phone-devel, linux-media, linux-kernel
Hi Dave,
Am Freitag, dem 13.09.2024 um 18:40 +0100 schrieb Dave Stevenson:
> On Thu, 12 Sept 2024 at 15:51, Dave Stevenson
> <dave.stevenson@raspberrypi.com> wrote:
> >
> > Hi André & Ricardo
> >
> > On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
> > <ribalda@kernel.org> wrote:
> > >
> > > Hi
> > >
> > > Arent you missing some chage in enum_frame_interval?
> >
> > Raw sensors shouldn't be using [enum|set|get]_frame_interval at all
> > https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
> >
> > The question now is how to handle the backwards compatibility for
> > any userspace app that might be using this driver and expecting to
> > use the frame_interval calls.
> > Seeing as it only ever allowed a fixed value of 30fps, leaving it
> > as is with a comment as to why it is there would be reasonable in
> > my view.
Should the comment be added in this commit?
And what exactly should the comment say?
> >
> > > On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> > > <devnull+git.apitzsch.eu@kernel.org> wrote:
> > > >
> > > > From: André Apitzsch <git@apitzsch.eu>
> > > >
> > > > Add vblank control to allow changing the framerate /
> > > > higher exposure values.
> > > >
> > > > The vblank and hblank controls are needed for libcamera
> > > > support.
> > > >
> > > > While at it, fix the minimal exposure time according to the
> > > > datasheet.
> > > >
> > > > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > > > ---
> > > > drivers/media/i2c/imx214.c | 112
> > > > ++++++++++++++++++++++++++++++++++++---------
> > > > 1 file changed, 91 insertions(+), 21 deletions(-)
> > > >
> > > > diff --git a/drivers/media/i2c/imx214.c
> > > > b/drivers/media/i2c/imx214.c
> > > > index 3b422cddbdce..9f5a57aebb86 100644
> > > > --- a/drivers/media/i2c/imx214.c
> > > > +++ b/drivers/media/i2c/imx214.c
> > > > @@ -34,11 +34,18 @@
> > > >
> > > > /* V-TIMING internal */
> > > > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > > > +#define IMX214_VTS_MAX 0xffff
> > > > +
> > > > +#define IMX214_VBLANK_MIN 4
> > > > +
> > > > +/* HBLANK control - read only */
> > > > +#define IMX214_PPL_DEFAULT 5008
> > > >
> > > > /* Exposure control */
> > > > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > > > -#define IMX214_EXPOSURE_MIN 0
> > > > -#define IMX214_EXPOSURE_MAX 3184
> > > > +#define IMX214_EXPOSURE_OFFSET 10
> > > > +#define IMX214_EXPOSURE_MIN 1
> > > > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX -
> > > > IMX214_EXPOSURE_OFFSET)
> > > > #define IMX214_EXPOSURE_STEP 1
> > > > #define IMX214_EXPOSURE_DEFAULT 3184
> > > > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > > > @@ -189,6 +196,8 @@ struct imx214 {
> > > > struct v4l2_ctrl_handler ctrls;
> > > > struct v4l2_ctrl *pixel_rate;
> > > > struct v4l2_ctrl *link_freq;
> > > > + struct v4l2_ctrl *vblank;
> > > > + struct v4l2_ctrl *hblank;
> > > > struct v4l2_ctrl *exposure;
> > > > struct v4l2_ctrl *unit_size;
> > > >
> > > > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence
> > > > mode_4096x2304[] = {
> > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > { IMX214_REG_X_ADD_STA, 56 },
> > > > { IMX214_REG_Y_ADD_STA, 408 },
> > > > { IMX214_REG_X_ADD_END, 4151 },
> > > > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence
> > > > mode_1920x1080[] = {
> > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > { IMX214_REG_X_ADD_STA, 1144 },
> > > > { IMX214_REG_Y_ADD_STA, 1020 },
> > > > { IMX214_REG_X_ADD_END, 3063 },
> > > > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence
> > > > mode_table_common[] = {
> > > > { IMX214_REG_ORIENTATION, 0 },
> > > > { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK
> > > > },
> > > > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > > > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > > > { CCI_REG8(0x4550), 0x02 },
> > > > { CCI_REG8(0x4601), 0x00 },
> > > > { CCI_REG8(0x4642), 0x05 },
> > > > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence
> > > > mode_table_common[] = {
> > > > static const struct imx214_mode {
> > > > u32 width;
> > > > u32 height;
> > > > +
> > > > + /* V-timing */
> > > > + unsigned int vts_def;
> > > > +
> > > > unsigned int num_of_regs;
> > > > const struct cci_reg_sequence *reg_table;
> > > > } imx214_modes[] = {
> > > > {
> > > > .width = 4096,
> > > > .height = 2304,
> > > > + .vts_def = 3194,
> > > > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > > > .reg_table = mode_4096x2304,
> > > > },
> > > > {
> > > > .width = 1920,
> > > > .height = 1080,
> > > > + .vts_def = 3194,
> > > > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > > > .reg_table = mode_1920x1080,
> > > > },
> > > > @@ -629,6 +641,37 @@ static int imx214_set_format(struct
> > > > v4l2_subdev *sd,
> > > > __crop->width = mode->width;
> > > > __crop->height = mode->height;
> > > >
> > > > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > > > + int exposure_max;
> > > > + int exposure_def;
> > > > + int hblank;
> > > > +
> > > > + /* Update limits and set FPS to default */
> > > > + __v4l2_ctrl_modify_range(imx214->vblank,
> > > > IMX214_VBLANK_MIN,
> > > > + IMX214_VTS_MAX - mode-
> > > > >height, 1,
> > > > + mode->vts_def - mode-
> > > > >height);
> > > > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > > > + mode->vts_def - mode-
> > > > >height);
> > > > +
> > > > + /* Update max exposure while meeting expected
> > > > vblanking */
> > > > + exposure_max = mode->vts_def -
> > > > IMX214_EXPOSURE_OFFSET;
> > > > + exposure_def = (exposure_max <
> > > > IMX214_EXPOSURE_DEFAULT) ?
> > > > + exposure_max : IMX214_EXPOSURE_DEFAULT;
> > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > + imx214->exposure-
> > > > >minimum,
> > > > + exposure_max, imx214-
> > > > >exposure->step,
> > > > + exposure_def);
> > > > +
> > > > + /*
> > > > + * Currently PPL is fixed to
> > > > IMX214_PPL_DEFAULT, so hblank
> > > > + * depends on mode->width only, and is not
> > > > changeble in any
> > > > + * way other than changing the mode.
> > > > + */
> > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > + __v4l2_ctrl_modify_range(imx214->hblank,
> > > > hblank, hblank, 1,
> > > > + hblank);
> > > > + }
> > > > +
> > > > return 0;
> > > > }
> > > >
> > > > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct
> > > > v4l2_ctrl *ctrl)
> > > > {
> > > > struct imx214 *imx214 = container_of(ctrl->handler,
> > > > struct imx214,
> > > > ctrls);
> > > > + const struct v4l2_mbus_framefmt *format;
> > > > + struct v4l2_subdev_state *state;
> > > > int ret;
> > > >
> > > > + state = v4l2_subdev_get_locked_active_state(&imx214-
> > > > >sd);
> > > > + format = v4l2_subdev_state_get_format(state, 0);
> > > > +
> > > > + if (ctrl->id == V4L2_CID_VBLANK) {
> > > > + int exposure_max, exposure_def;
> > > > +
> > > > + /* Update max exposure while meeting expected
> > > > vblanking */
> > > > + exposure_max = format->height + ctrl->val -
> > > > IMX214_EXPOSURE_OFFSET;
> > > > + exposure_def = min(exposure_max,
> > > > IMX214_EXPOSURE_DEFAULT);
> > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > + imx214->exposure-
> > > > >minimum,
> > > > + exposure_max, imx214-
> > > > >exposure->step,
> > > > + exposure_def);
> > > > + }
> > > > +
> > > > /*
> > > > * Applying V4L2 control value only happens
> > > > * when power is up for streaming
> > > > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct
> > > > v4l2_ctrl *ctrl)
> > > > case V4L2_CID_EXPOSURE:
> > > > cci_write(imx214->regmap, IMX214_REG_EXPOSURE,
> > > > ctrl->val, &ret);
> > > > break;
> > > > -
> > > > + case V4L2_CID_VBLANK:
> > > > + cci_write(imx214->regmap,
> > > > IMX214_REG_FRM_LENGTH_LINES,
> > > > + format->height + ctrl->val, &ret);
> >
> > My datasheet says this register is "set up in multiples of 2".
> > (LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
> >
> > I don't have one of these modules, but is that saying only
> > multiples
> > of 2 are permitted (in which case the step size for the control
> > needs
> > to reflect that), or that setting a value of N is interpreted by
> > the
> > hardware as 2N?
> > Do all the numbers with PIXEL_RATE work out correctly in the frame
> > rate calcs?
>
> Answering my own question, PIXEL_RATE looks dubious.
>
> The original code had LINE_LENGTH_PCK as 5008, and FRAME_LENGTH_LINES
> as 3194. If enum_frame_intervals is to be believed, then it delivered
> 30fps.
> 5008 * 3194 * 30 = 479,866,560 Pix/s.
>
> The driver defines IMX214_DEFAULT_LINK_FREQ 480000000, and then
> IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10),
> which works out as 384MPix/s. (Presumably the 8 is 4 lanes and DDR,
> but it's not obvious)
>
> Parsing the PLL registers with the defined 24MHz input. We're in
> single PLL mode, so MIPI frequency is directly linked to pixel rate.
> VTCK ends up being 1200MHz, and VTPXCK and OPPXCK both are 120MHz.
> Section 5.3 "Frame rate calculation formula" says "Pixel rate
> [pixels/s] = VTPXCK [MHz] * 4", so 120 * 4 = 480MPix/s, which
> basically agrees with my number above.
>
> 3.1.4. MIPI global timing setting says "Output bitrate = OPPXCK * reg
> 0x113[7:0]", so 120MHz * 10, or 1200Mbit/s. That would be a link
> frequency of 600MHz due to DDR.
> That also matches to 480MPix/s * 10bpp / 4 lanes / 2 for DDR
>
> Registers 0x0820-0823 are meant to define the target CSI2 bitrate,
> and are set to 0x12c00000, or 314,572,800 decimal. I can't get that
> to square with the above.
>
>
> So my conclusion is that both PIXEL_RATE and LINK_FREQUENCY are
> wrong, however the relationship used to define them looks to be
> correct.
> Correct IMX214_DEFAULT_LINK_FREQ to 600MHz, and all should be good.
Will do that. Should it be done in this commit or in a separat one?
> However you almost certainly want to set IMX214_VBLANK_MIN to
> something significantly greater than 4.
Any recommendation for the new IMX214_VBLANK_MIN value?
Best regards,
André
>
> Dave
>
> > Reading the spec sheet that 30fps is the max frame rate at full res
> > (4096x2304), and the driver was setting a value of 3194 to this
> > register, I don't see it being interpreted as 2N. Then again having
> > VBLANK at 890 seems pretty high.
> >
> > > > + break;
> > > > default:
> > > > ret = -EINVAL;
> > > > }
> > > > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214
> > > > *imx214)
> > > > .width = 1120,
> > > > .height = 1120,
> > > > };
> > > > + const struct imx214_mode *mode = &imx214_modes[0];
> > > > struct v4l2_fwnode_device_properties props;
> > > > struct v4l2_ctrl_handler *ctrl_hdlr;
> > > > + int exposure_max, exposure_def;
> > > > + int hblank;
> > > > int ret;
> > > >
> > > > ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> > > > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214
> > > > *imx214)
> > > > return ret;
> > > >
> > > > ctrl_hdlr = &imx214->ctrls;
> > > > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > > > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > > > if (ret)
> > > > return ret;
> > > >
> > > > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct
> > > > imx214 *imx214)
> > > > if (imx214->link_freq)
> > > > imx214->link_freq->flags |=
> > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > >
> > > > - /*
> > > > - * WARNING!
> > > > - * Values obtained reverse engineering blobs and/or
> > > > devices.
> > > > - * Ranges and functionality might be wrong.
> > > > - *
> > > > - * Sony, please release some register set documentation
> > > > for the
> > > > - * device.
> > > > - *
> > > > - * Yours sincerely, Ricardo.
> > > > - */
> > >
> > > I would like to keep this comment until there is a public
> > > document available.
> >
> > I suspect you'll be waiting forever for a document to be officially
> > released.
> >
> > I have a datasheet for IMX214, and I believe Kieran and Jacopo do
> > too.
> > Which specific values do you wish to be verified?
> >
> > >
> > > > + /* Initial vblank/hblank/exposure parameters based on
> > > > current mode */
> > > > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > &imx214_ctrl_ops,
> > > > + V4L2_CID_VBLANK,
> > > > IMX214_VBLANK_MIN,
> >
> > IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
> > I read the datasheet to say there are 4 embedded data lines per
> > image.
> > Seeing as you have STATS data output enabled as well that makes 5
> > lines of non-image data per frame, but you're only adding blanking
> > time for 4 lines.
> >
> > As noted above, I think you've also increased the max frame rate
> > significantly above that quoted by Sony. Has that been actually
> > exercised and confirmed to function correctly?
> >
> > Dave
> >
> > > > + IMX214_VTS_MAX -
> > > > mode->height, 1,
> > > > + mode->vts_def -
> > > > mode->height);
> > > > +
> > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > &imx214_ctrl_ops,
> > > > + V4L2_CID_HBLANK,
> > > > hblank, hblank,
> > > > + 1, hblank);
> > > > + if (imx214->hblank)
> > > > + imx214->hblank->flags |=
> > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > +
> > > > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > > > + exposure_def = min(exposure_max,
> > > > IMX214_EXPOSURE_DEFAULT);
> > > > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > &imx214_ctrl_ops,
> > > > V4L2_CID_EXPOSURE,
> > > > -
> > > > IMX214_EXPOSURE_MIN,
> > > > -
> > > > IMX214_EXPOSURE_MAX,
> > > > +
> > > > IMX214_EXPOSURE_MIN, exposure_max,
> > > >
> > > > IMX214_EXPOSURE_STEP,
> > > > -
> > > > IMX214_EXPOSURE_DEFAULT);
> > > > + exposure_def);
> > > >
> > > > imx214->unit_size =
> > > > v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > > > NULL,
> > > >
> > > > --
> > > > 2.46.0
> > > >
> > > >
> > >
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-10-06 21:41 ` André
@ 2024-10-07 17:29 ` Dave Stevenson
2024-10-12 21:45 ` André Apitzsch
0 siblings, 1 reply; 35+ messages in thread
From: Dave Stevenson @ 2024-10-07 17:29 UTC (permalink / raw)
To: André
Cc: Ricardo Ribalda Delgado, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
Hi Andre
On Sun, 6 Oct 2024 at 22:41, André <git@apitzsch.eu> wrote:
>
> Hi Dave,
>
> Am Freitag, dem 13.09.2024 um 18:40 +0100 schrieb Dave Stevenson:
> > On Thu, 12 Sept 2024 at 15:51, Dave Stevenson
> > <dave.stevenson@raspberrypi.com> wrote:
> > >
> > > Hi André & Ricardo
> > >
> > > On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
> > > <ribalda@kernel.org> wrote:
> > > >
> > > > Hi
> > > >
> > > > Arent you missing some chage in enum_frame_interval?
> > >
> > > Raw sensors shouldn't be using [enum|set|get]_frame_interval at all
> > > https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
> > >
> > > The question now is how to handle the backwards compatibility for
> > > any userspace app that might be using this driver and expecting to
> > > use the frame_interval calls.
> > > Seeing as it only ever allowed a fixed value of 30fps, leaving it
> > > as is with a comment as to why it is there would be reasonable in
> > > my view.
>
> Should the comment be added in this commit?
> And what exactly should the comment say?
Add it to imx214_enum_frame_interval.
Something along the lines of:
Raw sensors should be using the VBLANK and HBLANK controls to
determine the frame rate. However this driver was initially added
using the [S|G|ENUM]_FRAME_INTERVAL ioctls with a fixed rate of 30fps.
Retain the frame_interval ops for backwards compatibility, but they do nothing.
> > >
> > > > On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> > > > <devnull+git.apitzsch.eu@kernel.org> wrote:
> > > > >
> > > > > From: André Apitzsch <git@apitzsch.eu>
> > > > >
> > > > > Add vblank control to allow changing the framerate /
> > > > > higher exposure values.
> > > > >
> > > > > The vblank and hblank controls are needed for libcamera
> > > > > support.
> > > > >
> > > > > While at it, fix the minimal exposure time according to the
> > > > > datasheet.
> > > > >
> > > > > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > > > > ---
> > > > > drivers/media/i2c/imx214.c | 112
> > > > > ++++++++++++++++++++++++++++++++++++---------
> > > > > 1 file changed, 91 insertions(+), 21 deletions(-)
> > > > >
> > > > > diff --git a/drivers/media/i2c/imx214.c
> > > > > b/drivers/media/i2c/imx214.c
> > > > > index 3b422cddbdce..9f5a57aebb86 100644
> > > > > --- a/drivers/media/i2c/imx214.c
> > > > > +++ b/drivers/media/i2c/imx214.c
> > > > > @@ -34,11 +34,18 @@
> > > > >
> > > > > /* V-TIMING internal */
> > > > > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > > > > +#define IMX214_VTS_MAX 0xffff
> > > > > +
> > > > > +#define IMX214_VBLANK_MIN 4
> > > > > +
> > > > > +/* HBLANK control - read only */
> > > > > +#define IMX214_PPL_DEFAULT 5008
> > > > >
> > > > > /* Exposure control */
> > > > > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > > > > -#define IMX214_EXPOSURE_MIN 0
> > > > > -#define IMX214_EXPOSURE_MAX 3184
> > > > > +#define IMX214_EXPOSURE_OFFSET 10
> > > > > +#define IMX214_EXPOSURE_MIN 1
> > > > > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX -
> > > > > IMX214_EXPOSURE_OFFSET)
> > > > > #define IMX214_EXPOSURE_STEP 1
> > > > > #define IMX214_EXPOSURE_DEFAULT 3184
> > > > > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > > > > @@ -189,6 +196,8 @@ struct imx214 {
> > > > > struct v4l2_ctrl_handler ctrls;
> > > > > struct v4l2_ctrl *pixel_rate;
> > > > > struct v4l2_ctrl *link_freq;
> > > > > + struct v4l2_ctrl *vblank;
> > > > > + struct v4l2_ctrl *hblank;
> > > > > struct v4l2_ctrl *exposure;
> > > > > struct v4l2_ctrl *unit_size;
> > > > >
> > > > > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence
> > > > > mode_4096x2304[] = {
> > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > { IMX214_REG_X_ADD_STA, 56 },
> > > > > { IMX214_REG_Y_ADD_STA, 408 },
> > > > > { IMX214_REG_X_ADD_END, 4151 },
> > > > > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence
> > > > > mode_1920x1080[] = {
> > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > { IMX214_REG_X_ADD_STA, 1144 },
> > > > > { IMX214_REG_Y_ADD_STA, 1020 },
> > > > > { IMX214_REG_X_ADD_END, 3063 },
> > > > > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence
> > > > > mode_table_common[] = {
> > > > > { IMX214_REG_ORIENTATION, 0 },
> > > > > { IMX214_REG_MASK_CORR_FRAMES, IMX214_CORR_FRAMES_MASK
> > > > > },
> > > > > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > > > > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > > > > { CCI_REG8(0x4550), 0x02 },
> > > > > { CCI_REG8(0x4601), 0x00 },
> > > > > { CCI_REG8(0x4642), 0x05 },
> > > > > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence
> > > > > mode_table_common[] = {
> > > > > static const struct imx214_mode {
> > > > > u32 width;
> > > > > u32 height;
> > > > > +
> > > > > + /* V-timing */
> > > > > + unsigned int vts_def;
> > > > > +
> > > > > unsigned int num_of_regs;
> > > > > const struct cci_reg_sequence *reg_table;
> > > > > } imx214_modes[] = {
> > > > > {
> > > > > .width = 4096,
> > > > > .height = 2304,
> > > > > + .vts_def = 3194,
> > > > > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > > > > .reg_table = mode_4096x2304,
> > > > > },
> > > > > {
> > > > > .width = 1920,
> > > > > .height = 1080,
> > > > > + .vts_def = 3194,
> > > > > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > > > > .reg_table = mode_1920x1080,
> > > > > },
> > > > > @@ -629,6 +641,37 @@ static int imx214_set_format(struct
> > > > > v4l2_subdev *sd,
> > > > > __crop->width = mode->width;
> > > > > __crop->height = mode->height;
> > > > >
> > > > > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > > > > + int exposure_max;
> > > > > + int exposure_def;
> > > > > + int hblank;
> > > > > +
> > > > > + /* Update limits and set FPS to default */
> > > > > + __v4l2_ctrl_modify_range(imx214->vblank,
> > > > > IMX214_VBLANK_MIN,
> > > > > + IMX214_VTS_MAX - mode-
> > > > > >height, 1,
> > > > > + mode->vts_def - mode-
> > > > > >height);
> > > > > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > > > > + mode->vts_def - mode-
> > > > > >height);
> > > > > +
> > > > > + /* Update max exposure while meeting expected
> > > > > vblanking */
> > > > > + exposure_max = mode->vts_def -
> > > > > IMX214_EXPOSURE_OFFSET;
> > > > > + exposure_def = (exposure_max <
> > > > > IMX214_EXPOSURE_DEFAULT) ?
> > > > > + exposure_max : IMX214_EXPOSURE_DEFAULT;
> > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > + imx214->exposure-
> > > > > >minimum,
> > > > > + exposure_max, imx214-
> > > > > >exposure->step,
> > > > > + exposure_def);
> > > > > +
> > > > > + /*
> > > > > + * Currently PPL is fixed to
> > > > > IMX214_PPL_DEFAULT, so hblank
> > > > > + * depends on mode->width only, and is not
> > > > > changeble in any
> > > > > + * way other than changing the mode.
> > > > > + */
> > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > + __v4l2_ctrl_modify_range(imx214->hblank,
> > > > > hblank, hblank, 1,
> > > > > + hblank);
> > > > > + }
> > > > > +
> > > > > return 0;
> > > > > }
> > > > >
> > > > > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct
> > > > > v4l2_ctrl *ctrl)
> > > > > {
> > > > > struct imx214 *imx214 = container_of(ctrl->handler,
> > > > > struct imx214,
> > > > > ctrls);
> > > > > + const struct v4l2_mbus_framefmt *format;
> > > > > + struct v4l2_subdev_state *state;
> > > > > int ret;
> > > > >
> > > > > + state = v4l2_subdev_get_locked_active_state(&imx214-
> > > > > >sd);
> > > > > + format = v4l2_subdev_state_get_format(state, 0);
> > > > > +
> > > > > + if (ctrl->id == V4L2_CID_VBLANK) {
> > > > > + int exposure_max, exposure_def;
> > > > > +
> > > > > + /* Update max exposure while meeting expected
> > > > > vblanking */
> > > > > + exposure_max = format->height + ctrl->val -
> > > > > IMX214_EXPOSURE_OFFSET;
> > > > > + exposure_def = min(exposure_max,
> > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > + imx214->exposure-
> > > > > >minimum,
> > > > > + exposure_max, imx214-
> > > > > >exposure->step,
> > > > > + exposure_def);
> > > > > + }
> > > > > +
> > > > > /*
> > > > > * Applying V4L2 control value only happens
> > > > > * when power is up for streaming
> > > > > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct
> > > > > v4l2_ctrl *ctrl)
> > > > > case V4L2_CID_EXPOSURE:
> > > > > cci_write(imx214->regmap, IMX214_REG_EXPOSURE,
> > > > > ctrl->val, &ret);
> > > > > break;
> > > > > -
> > > > > + case V4L2_CID_VBLANK:
> > > > > + cci_write(imx214->regmap,
> > > > > IMX214_REG_FRM_LENGTH_LINES,
> > > > > + format->height + ctrl->val, &ret);
> > >
> > > My datasheet says this register is "set up in multiples of 2".
> > > (LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
> > >
> > > I don't have one of these modules, but is that saying only
> > > multiples
> > > of 2 are permitted (in which case the step size for the control
> > > needs
> > > to reflect that), or that setting a value of N is interpreted by
> > > the
> > > hardware as 2N?
> > > Do all the numbers with PIXEL_RATE work out correctly in the frame
> > > rate calcs?
> >
> > Answering my own question, PIXEL_RATE looks dubious.
> >
> > The original code had LINE_LENGTH_PCK as 5008, and FRAME_LENGTH_LINES
> > as 3194. If enum_frame_intervals is to be believed, then it delivered
> > 30fps.
> > 5008 * 3194 * 30 = 479,866,560 Pix/s.
> >
> > The driver defines IMX214_DEFAULT_LINK_FREQ 480000000, and then
> > IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10),
> > which works out as 384MPix/s. (Presumably the 8 is 4 lanes and DDR,
> > but it's not obvious)
> >
> > Parsing the PLL registers with the defined 24MHz input. We're in
> > single PLL mode, so MIPI frequency is directly linked to pixel rate.
> > VTCK ends up being 1200MHz, and VTPXCK and OPPXCK both are 120MHz.
> > Section 5.3 "Frame rate calculation formula" says "Pixel rate
> > [pixels/s] = VTPXCK [MHz] * 4", so 120 * 4 = 480MPix/s, which
> > basically agrees with my number above.
> >
> > 3.1.4. MIPI global timing setting says "Output bitrate = OPPXCK * reg
> > 0x113[7:0]", so 120MHz * 10, or 1200Mbit/s. That would be a link
> > frequency of 600MHz due to DDR.
> > That also matches to 480MPix/s * 10bpp / 4 lanes / 2 for DDR
> >
> > Registers 0x0820-0823 are meant to define the target CSI2 bitrate,
> > and are set to 0x12c00000, or 314,572,800 decimal. I can't get that
> > to square with the above.
> >
> >
> > So my conclusion is that both PIXEL_RATE and LINK_FREQUENCY are
> > wrong, however the relationship used to define them looks to be
> > correct.
> > Correct IMX214_DEFAULT_LINK_FREQ to 600MHz, and all should be good.
>
> Will do that. Should it be done in this commit or in a separat one?
A separate one as it is independent of adding VBLANK and HBLANK
controls. Ideally it should come before this patch as then hopefully
everything actually works correctly when you add them.
> > However you almost certainly want to set IMX214_VBLANK_MIN to
> > something significantly greater than 4.
>
> Any recommendation for the new IMX214_VBLANK_MIN value?
As my comment below, the datasheet lists 30fps as the max frame rate
for full res, therefore IMX214_VBLANK_MIN being correct for that seems
reasonable. 890 appears to be the value for that, but I haven't
verified that all the numbers do then work out.
Out of interest, what platform are you testing this on, and where are
you getting the sensor from? I'm always happy to tinker with sensors
that I can get working on a Pi, and I think the Arducam DepthAI Oak
module should work, but haven't picked one up yet.
Dave
> Best regards,
> André
>
> >
> > Dave
> >
> > > Reading the spec sheet that 30fps is the max frame rate at full res
> > > (4096x2304), and the driver was setting a value of 3194 to this
> > > register, I don't see it being interpreted as 2N. Then again having
> > > VBLANK at 890 seems pretty high.
> > >
> > > > > + break;
> > > > > default:
> > > > > ret = -EINVAL;
> > > > > }
> > > > > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct imx214
> > > > > *imx214)
> > > > > .width = 1120,
> > > > > .height = 1120,
> > > > > };
> > > > > + const struct imx214_mode *mode = &imx214_modes[0];
> > > > > struct v4l2_fwnode_device_properties props;
> > > > > struct v4l2_ctrl_handler *ctrl_hdlr;
> > > > > + int exposure_max, exposure_def;
> > > > > + int hblank;
> > > > > int ret;
> > > > >
> > > > > ret = v4l2_fwnode_device_parse(imx214->dev, &props);
> > > > > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct imx214
> > > > > *imx214)
> > > > > return ret;
> > > > >
> > > > > ctrl_hdlr = &imx214->ctrls;
> > > > > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > > > > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > > > > if (ret)
> > > > > return ret;
> > > > >
> > > > > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct
> > > > > imx214 *imx214)
> > > > > if (imx214->link_freq)
> > > > > imx214->link_freq->flags |=
> > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > >
> > > > > - /*
> > > > > - * WARNING!
> > > > > - * Values obtained reverse engineering blobs and/or
> > > > > devices.
> > > > > - * Ranges and functionality might be wrong.
> > > > > - *
> > > > > - * Sony, please release some register set documentation
> > > > > for the
> > > > > - * device.
> > > > > - *
> > > > > - * Yours sincerely, Ricardo.
> > > > > - */
> > > >
> > > > I would like to keep this comment until there is a public
> > > > document available.
> > >
> > > I suspect you'll be waiting forever for a document to be officially
> > > released.
> > >
> > > I have a datasheet for IMX214, and I believe Kieran and Jacopo do
> > > too.
> > > Which specific values do you wish to be verified?
> > >
> > > >
> > > > > + /* Initial vblank/hblank/exposure parameters based on
> > > > > current mode */
> > > > > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > &imx214_ctrl_ops,
> > > > > + V4L2_CID_VBLANK,
> > > > > IMX214_VBLANK_MIN,
> > >
> > > IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
> > > I read the datasheet to say there are 4 embedded data lines per
> > > image.
> > > Seeing as you have STATS data output enabled as well that makes 5
> > > lines of non-image data per frame, but you're only adding blanking
> > > time for 4 lines.
> > >
> > > As noted above, I think you've also increased the max frame rate
> > > significantly above that quoted by Sony. Has that been actually
> > > exercised and confirmed to function correctly?
> > >
> > > Dave
> > >
> > > > > + IMX214_VTS_MAX -
> > > > > mode->height, 1,
> > > > > + mode->vts_def -
> > > > > mode->height);
> > > > > +
> > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > &imx214_ctrl_ops,
> > > > > + V4L2_CID_HBLANK,
> > > > > hblank, hblank,
> > > > > + 1, hblank);
> > > > > + if (imx214->hblank)
> > > > > + imx214->hblank->flags |=
> > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > > +
> > > > > + exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET;
> > > > > + exposure_def = min(exposure_max,
> > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > &imx214_ctrl_ops,
> > > > > V4L2_CID_EXPOSURE,
> > > > > -
> > > > > IMX214_EXPOSURE_MIN,
> > > > > -
> > > > > IMX214_EXPOSURE_MAX,
> > > > > +
> > > > > IMX214_EXPOSURE_MIN, exposure_max,
> > > > >
> > > > > IMX214_EXPOSURE_STEP,
> > > > > -
> > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > + exposure_def);
> > > > >
> > > > > imx214->unit_size =
> > > > > v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > > > > NULL,
> > > > >
> > > > > --
> > > > > 2.46.0
> > > > >
> > > > >
> > > >
>
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-10-07 17:29 ` Dave Stevenson
@ 2024-10-12 21:45 ` André Apitzsch
2024-10-14 12:17 ` Dave Stevenson
0 siblings, 1 reply; 35+ messages in thread
From: André Apitzsch @ 2024-10-12 21:45 UTC (permalink / raw)
To: Dave Stevenson
Cc: Ricardo Ribalda Delgado, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
Hi Dave,
Am Montag, dem 07.10.2024 um 18:29 +0100 schrieb Dave Stevenson:
> Hi Andre
>
> On Sun, 6 Oct 2024 at 22:41, André <git@apitzsch.eu> wrote:
> >
> > Hi Dave,
> >
> > Am Freitag, dem 13.09.2024 um 18:40 +0100 schrieb Dave Stevenson:
> > > On Thu, 12 Sept 2024 at 15:51, Dave Stevenson
> > > <dave.stevenson@raspberrypi.com> wrote:
> > > >
> > > > Hi André & Ricardo
> > > >
> > > > On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
> > > > <ribalda@kernel.org> wrote:
> > > > >
> > > > > Hi
> > > > >
> > > > > Arent you missing some chage in enum_frame_interval?
> > > >
> > > > Raw sensors shouldn't be using [enum|set|get]_frame_interval at
> > > > all
> > > > https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
> > > >
> > > > The question now is how to handle the backwards compatibility
> > > > for
> > > > any userspace app that might be using this driver and expecting
> > > > to
> > > > use the frame_interval calls.
> > > > Seeing as it only ever allowed a fixed value of 30fps, leaving
> > > > it
> > > > as is with a comment as to why it is there would be reasonable
> > > > in
> > > > my view.
> >
> > Should the comment be added in this commit?
> > And what exactly should the comment say?
>
> Add it to imx214_enum_frame_interval.
> Something along the lines of:
> Raw sensors should be using the VBLANK and HBLANK controls to
> determine the frame rate. However this driver was initially added
> using the [S|G|ENUM]_FRAME_INTERVAL ioctls with a fixed rate of
> 30fps.
> Retain the frame_interval ops for backwards compatibility, but they
> do nothing.
>
> > > >
> > > > > On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> > > > > <devnull+git.apitzsch.eu@kernel.org> wrote:
> > > > > >
> > > > > > From: André Apitzsch <git@apitzsch.eu>
> > > > > >
> > > > > > Add vblank control to allow changing the framerate /
> > > > > > higher exposure values.
> > > > > >
> > > > > > The vblank and hblank controls are needed for libcamera
> > > > > > support.
> > > > > >
> > > > > > While at it, fix the minimal exposure time according to the
> > > > > > datasheet.
> > > > > >
> > > > > > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > > > > > ---
> > > > > > drivers/media/i2c/imx214.c | 112
> > > > > > ++++++++++++++++++++++++++++++++++++---------
> > > > > > 1 file changed, 91 insertions(+), 21 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/media/i2c/imx214.c
> > > > > > b/drivers/media/i2c/imx214.c
> > > > > > index 3b422cddbdce..9f5a57aebb86 100644
> > > > > > --- a/drivers/media/i2c/imx214.c
> > > > > > +++ b/drivers/media/i2c/imx214.c
> > > > > > @@ -34,11 +34,18 @@
> > > > > >
> > > > > > /* V-TIMING internal */
> > > > > > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > > > > > +#define IMX214_VTS_MAX 0xffff
> > > > > > +
> > > > > > +#define IMX214_VBLANK_MIN 4
> > > > > > +
> > > > > > +/* HBLANK control - read only */
> > > > > > +#define IMX214_PPL_DEFAULT 5008
> > > > > >
> > > > > > /* Exposure control */
> > > > > > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > > > > > -#define IMX214_EXPOSURE_MIN 0
> > > > > > -#define IMX214_EXPOSURE_MAX 3184
> > > > > > +#define IMX214_EXPOSURE_OFFSET 10
> > > > > > +#define IMX214_EXPOSURE_MIN 1
> > > > > > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX -
> > > > > > IMX214_EXPOSURE_OFFSET)
> > > > > > #define IMX214_EXPOSURE_STEP 1
> > > > > > #define IMX214_EXPOSURE_DEFAULT 3184
> > > > > > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > > > > > @@ -189,6 +196,8 @@ struct imx214 {
> > > > > > struct v4l2_ctrl_handler ctrls;
> > > > > > struct v4l2_ctrl *pixel_rate;
> > > > > > struct v4l2_ctrl *link_freq;
> > > > > > + struct v4l2_ctrl *vblank;
> > > > > > + struct v4l2_ctrl *hblank;
> > > > > > struct v4l2_ctrl *exposure;
> > > > > > struct v4l2_ctrl *unit_size;
> > > > > >
> > > > > > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence
> > > > > > mode_4096x2304[] = {
> > > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > > { IMX214_REG_X_ADD_STA, 56 },
> > > > > > { IMX214_REG_Y_ADD_STA, 408 },
> > > > > > { IMX214_REG_X_ADD_END, 4151 },
> > > > > > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence
> > > > > > mode_1920x1080[] = {
> > > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > > { IMX214_REG_X_ADD_STA, 1144 },
> > > > > > { IMX214_REG_Y_ADD_STA, 1020 },
> > > > > > { IMX214_REG_X_ADD_END, 3063 },
> > > > > > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence
> > > > > > mode_table_common[] = {
> > > > > > { IMX214_REG_ORIENTATION, 0 },
> > > > > > { IMX214_REG_MASK_CORR_FRAMES,
> > > > > > IMX214_CORR_FRAMES_MASK
> > > > > > },
> > > > > > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > > > > > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > > > > > { CCI_REG8(0x4550), 0x02 },
> > > > > > { CCI_REG8(0x4601), 0x00 },
> > > > > > { CCI_REG8(0x4642), 0x05 },
> > > > > > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence
> > > > > > mode_table_common[] = {
> > > > > > static const struct imx214_mode {
> > > > > > u32 width;
> > > > > > u32 height;
> > > > > > +
> > > > > > + /* V-timing */
> > > > > > + unsigned int vts_def;
> > > > > > +
> > > > > > unsigned int num_of_regs;
> > > > > > const struct cci_reg_sequence *reg_table;
> > > > > > } imx214_modes[] = {
> > > > > > {
> > > > > > .width = 4096,
> > > > > > .height = 2304,
> > > > > > + .vts_def = 3194,
> > > > > > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > > > > > .reg_table = mode_4096x2304,
> > > > > > },
> > > > > > {
> > > > > > .width = 1920,
> > > > > > .height = 1080,
> > > > > > + .vts_def = 3194,
> > > > > > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > > > > > .reg_table = mode_1920x1080,
> > > > > > },
> > > > > > @@ -629,6 +641,37 @@ static int imx214_set_format(struct
> > > > > > v4l2_subdev *sd,
> > > > > > __crop->width = mode->width;
> > > > > > __crop->height = mode->height;
> > > > > >
> > > > > > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > > > > > + int exposure_max;
> > > > > > + int exposure_def;
> > > > > > + int hblank;
> > > > > > +
> > > > > > + /* Update limits and set FPS to default */
> > > > > > + __v4l2_ctrl_modify_range(imx214->vblank,
> > > > > > IMX214_VBLANK_MIN,
> > > > > > + IMX214_VTS_MAX -
> > > > > > mode-
> > > > > > > height, 1,
> > > > > > + mode->vts_def -
> > > > > > mode-
> > > > > > > height);
> > > > > > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > > > > > + mode->vts_def - mode-
> > > > > > > height);
> > > > > > +
> > > > > > + /* Update max exposure while meeting
> > > > > > expected
> > > > > > vblanking */
> > > > > > + exposure_max = mode->vts_def -
> > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > + exposure_def = (exposure_max <
> > > > > > IMX214_EXPOSURE_DEFAULT) ?
> > > > > > + exposure_max :
> > > > > > IMX214_EXPOSURE_DEFAULT;
> > > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > > + imx214->exposure-
> > > > > > > minimum,
> > > > > > + exposure_max,
> > > > > > imx214-
> > > > > > > exposure->step,
> > > > > > + exposure_def);
> > > > > > +
> > > > > > + /*
> > > > > > + * Currently PPL is fixed to
> > > > > > IMX214_PPL_DEFAULT, so hblank
> > > > > > + * depends on mode->width only, and is not
> > > > > > changeble in any
> > > > > > + * way other than changing the mode.
> > > > > > + */
> > > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > > + __v4l2_ctrl_modify_range(imx214->hblank,
> > > > > > hblank, hblank, 1,
> > > > > > + hblank);
> > > > > > + }
> > > > > > +
> > > > > > return 0;
> > > > > > }
> > > > > >
> > > > > > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct
> > > > > > v4l2_ctrl *ctrl)
> > > > > > {
> > > > > > struct imx214 *imx214 = container_of(ctrl->handler,
> > > > > > struct imx214,
> > > > > > ctrls);
> > > > > > + const struct v4l2_mbus_framefmt *format;
> > > > > > + struct v4l2_subdev_state *state;
> > > > > > int ret;
> > > > > >
> > > > > > + state =
> > > > > > v4l2_subdev_get_locked_active_state(&imx214-
> > > > > > > sd);
> > > > > > + format = v4l2_subdev_state_get_format(state, 0);
> > > > > > +
> > > > > > + if (ctrl->id == V4L2_CID_VBLANK) {
> > > > > > + int exposure_max, exposure_def;
> > > > > > +
> > > > > > + /* Update max exposure while meeting
> > > > > > expected
> > > > > > vblanking */
> > > > > > + exposure_max = format->height + ctrl->val -
> > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > + exposure_def = min(exposure_max,
> > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > > + imx214->exposure-
> > > > > > > minimum,
> > > > > > + exposure_max,
> > > > > > imx214-
> > > > > > > exposure->step,
> > > > > > + exposure_def);
> > > > > > + }
> > > > > > +
> > > > > > /*
> > > > > > * Applying V4L2 control value only happens
> > > > > > * when power is up for streaming
> > > > > > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct
> > > > > > v4l2_ctrl *ctrl)
> > > > > > case V4L2_CID_EXPOSURE:
> > > > > > cci_write(imx214->regmap,
> > > > > > IMX214_REG_EXPOSURE,
> > > > > > ctrl->val, &ret);
> > > > > > break;
> > > > > > -
> > > > > > + case V4L2_CID_VBLANK:
> > > > > > + cci_write(imx214->regmap,
> > > > > > IMX214_REG_FRM_LENGTH_LINES,
> > > > > > + format->height + ctrl->val,
> > > > > > &ret);
> > > >
> > > > My datasheet says this register is "set up in multiples of 2".
> > > > (LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
> > > >
> > > > I don't have one of these modules, but is that saying only
> > > > multiples
> > > > of 2 are permitted (in which case the step size for the control
> > > > needs
> > > > to reflect that), or that setting a value of N is interpreted
> > > > by
> > > > the
> > > > hardware as 2N?
> > > > Do all the numbers with PIXEL_RATE work out correctly in the
> > > > frame
> > > > rate calcs?
> > >
> > > Answering my own question, PIXEL_RATE looks dubious.
> > >
> > > The original code had LINE_LENGTH_PCK as 5008, and
> > > FRAME_LENGTH_LINES as 3194. If enum_frame_intervals is to be
> > > believed, then it delivered 30fps.
> > > 5008 * 3194 * 30 = 479,866,560 Pix/s.
> > >
> > > The driver defines IMX214_DEFAULT_LINK_FREQ 480000000, and then
> > > IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) /
> > > 10), which works out as 384MPix/s. (Presumably the 8 is 4 lanes
> > > and DDR, but it's not obvious)
> > >
> > > Parsing the PLL registers with the defined 24MHz input. We're in
> > > single PLL mode, so MIPI frequency is directly linked to pixel
> > > rate.
> > > VTCK ends up being 1200MHz, and VTPXCK and OPPXCK both are
> > > 120MHz.
> > > Section 5.3 "Frame rate calculation formula" says "Pixel rate
> > > [pixels/s] = VTPXCK [MHz] * 4", so 120 * 4 = 480MPix/s, which
> > > basically agrees with my number above.
> > >
> > > 3.1.4. MIPI global timing setting says "Output bitrate = OPPXCK *
> > > reg 0x113[7:0]", so 120MHz * 10, or 1200Mbit/s. That would be a
> > > link frequency of 600MHz due to DDR.
> > > That also matches to 480MPix/s * 10bpp / 4 lanes / 2 for DDR
Is it okay, if I use the three sections above for the commit message of
the fix-link-frequency commit?
> > >
> > > Registers 0x0820-0823 are meant to define the target CSI2
> > > bitrate, and are set to 0x12c00000, or 314,572,800 decimal. I
> > > can't get that to square with the above.
> > >
According the manual, the registers 0x0820-0823 represent an unsigned
32-bit real, where the first 16 bit seem to represent the integer part
and the last 16 bit the fractional part. This means 0x12c00000 is
4800.0 Mbit/s, which is equal to 480MPix/s * 10bpp.
> > >
> > > So my conclusion is that both PIXEL_RATE and LINK_FREQUENCY are
> > > wrong, however the relationship used to define them looks to be
> > > correct.
> > > Correct IMX214_DEFAULT_LINK_FREQ to 600MHz, and all should be
> > > good.
> >
> > Will do that. Should it be done in this commit or in a separat one?
>
> A separate one as it is independent of adding VBLANK and HBLANK
> controls. Ideally it should come before this patch as then hopefully
> everything actually works correctly when you add them.
>
> > > However you almost certainly want to set IMX214_VBLANK_MIN to
> > > something significantly greater than 4.
> >
> > Any recommendation for the new IMX214_VBLANK_MIN value?
>
> As my comment below, the datasheet lists 30fps as the max frame rate
> for full res, therefore IMX214_VBLANK_MIN being correct for that
> seems reasonable. 890 appears to be the value for that, but I haven't
> verified that all the numbers do then work out.
>
> Out of interest, what platform are you testing this on, and where are
> you getting the sensor from? I'm always happy to tinker with sensors
> that I can get working on a Pi, and I think the Arducam DepthAI Oak
> module should work, but haven't picked one up yet.
The sensor is part of my mobile phone[1], which I use for testing.
By the way, do you (or anyone else) happen to have the documentation
for the Samsung s5k5e2?
André
[1] https://wiki.postmarketos.org/wiki/BQ_Aquaris_M5_(bq-piccolo)
>
> Dave
>
> > Best regards,
> > André
> >
> > >
> > > Dave
> > >
> > > > Reading the spec sheet that 30fps is the max frame rate at full
> > > > res
> > > > (4096x2304), and the driver was setting a value of 3194 to this
> > > > register, I don't see it being interpreted as 2N. Then again
> > > > having
> > > > VBLANK at 890 seems pretty high.
> > > >
> > > > > > + break;
> > > > > > default:
> > > > > > ret = -EINVAL;
> > > > > > }
> > > > > > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct
> > > > > > imx214
> > > > > > *imx214)
> > > > > > .width = 1120,
> > > > > > .height = 1120,
> > > > > > };
> > > > > > + const struct imx214_mode *mode = &imx214_modes[0];
> > > > > > struct v4l2_fwnode_device_properties props;
> > > > > > struct v4l2_ctrl_handler *ctrl_hdlr;
> > > > > > + int exposure_max, exposure_def;
> > > > > > + int hblank;
> > > > > > int ret;
> > > > > >
> > > > > > ret = v4l2_fwnode_device_parse(imx214->dev,
> > > > > > &props);
> > > > > > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct
> > > > > > imx214
> > > > > > *imx214)
> > > > > > return ret;
> > > > > >
> > > > > > ctrl_hdlr = &imx214->ctrls;
> > > > > > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > > > > > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > > > > > if (ret)
> > > > > > return ret;
> > > > > >
> > > > > > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct
> > > > > > imx214 *imx214)
> > > > > > if (imx214->link_freq)
> > > > > > imx214->link_freq->flags |=
> > > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > > >
> > > > > > - /*
> > > > > > - * WARNING!
> > > > > > - * Values obtained reverse engineering blobs and/or
> > > > > > devices.
> > > > > > - * Ranges and functionality might be wrong.
> > > > > > - *
> > > > > > - * Sony, please release some register set
> > > > > > documentation
> > > > > > for the
> > > > > > - * device.
> > > > > > - *
> > > > > > - * Yours sincerely, Ricardo.
> > > > > > - */
> > > > >
> > > > > I would like to keep this comment until there is a public
> > > > > document available.
> > > >
> > > > I suspect you'll be waiting forever for a document to be
> > > > officially
> > > > released.
> > > >
> > > > I have a datasheet for IMX214, and I believe Kieran and Jacopo
> > > > do
> > > > too.
> > > > Which specific values do you wish to be verified?
> > > >
> > > > >
> > > > > > + /* Initial vblank/hblank/exposure parameters based
> > > > > > on
> > > > > > current mode */
> > > > > > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > &imx214_ctrl_ops,
> > > > > > + V4L2_CID_VBLANK,
> > > > > > IMX214_VBLANK_MIN,
> > > >
> > > > IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
> > > > I read the datasheet to say there are 4 embedded data lines per
> > > > image.
> > > > Seeing as you have STATS data output enabled as well that makes
> > > > 5
> > > > lines of non-image data per frame, but you're only adding
> > > > blanking
> > > > time for 4 lines.
> > > >
> > > > As noted above, I think you've also increased the max frame
> > > > rate
> > > > significantly above that quoted by Sony. Has that been actually
> > > > exercised and confirmed to function correctly?
> > > >
> > > > Dave
> > > >
> > > > > > + IMX214_VTS_MAX -
> > > > > > mode->height, 1,
> > > > > > + mode->vts_def -
> > > > > > mode->height);
> > > > > > +
> > > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > &imx214_ctrl_ops,
> > > > > > + V4L2_CID_HBLANK,
> > > > > > hblank, hblank,
> > > > > > + 1, hblank);
> > > > > > + if (imx214->hblank)
> > > > > > + imx214->hblank->flags |=
> > > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > > > +
> > > > > > + exposure_max = mode->vts_def -
> > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > + exposure_def = min(exposure_max,
> > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > &imx214_ctrl_ops,
> > > > > >
> > > > > > V4L2_CID_EXPOSURE,
> > > > > > -
> > > > > > IMX214_EXPOSURE_MIN,
> > > > > > -
> > > > > > IMX214_EXPOSURE_MAX,
> > > > > > +
> > > > > > IMX214_EXPOSURE_MIN, exposure_max,
> > > > > >
> > > > > > IMX214_EXPOSURE_STEP,
> > > > > > -
> > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > + exposure_def);
> > > > > >
> > > > > > imx214->unit_size =
> > > > > > v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > > > > > NULL,
> > > > > >
> > > > > > --
> > > > > > 2.46.0
> > > > > >
> > > > > >
> > > > >
> >
^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls
2024-10-12 21:45 ` André Apitzsch
@ 2024-10-14 12:17 ` Dave Stevenson
0 siblings, 0 replies; 35+ messages in thread
From: Dave Stevenson @ 2024-10-14 12:17 UTC (permalink / raw)
To: André Apitzsch
Cc: Ricardo Ribalda Delgado, Sakari Ailus, Mauro Carvalho Chehab,
~postmarketos/upstreaming, phone-devel, linux-media, linux-kernel
Hi André
On Sat, 12 Oct 2024 at 22:46, André Apitzsch <git@apitzsch.eu> wrote:
>
> Hi Dave,
>
> Am Montag, dem 07.10.2024 um 18:29 +0100 schrieb Dave Stevenson:
> > Hi Andre
> >
> > On Sun, 6 Oct 2024 at 22:41, André <git@apitzsch.eu> wrote:
> > >
> > > Hi Dave,
> > >
> > > Am Freitag, dem 13.09.2024 um 18:40 +0100 schrieb Dave Stevenson:
> > > > On Thu, 12 Sept 2024 at 15:51, Dave Stevenson
> > > > <dave.stevenson@raspberrypi.com> wrote:
> > > > >
> > > > > Hi André & Ricardo
> > > > >
> > > > > On Thu, 12 Sept 2024 at 14:41, Ricardo Ribalda Delgado
> > > > > <ribalda@kernel.org> wrote:
> > > > > >
> > > > > > Hi
> > > > > >
> > > > > > Arent you missing some chage in enum_frame_interval?
> > > > >
> > > > > Raw sensors shouldn't be using [enum|set|get]_frame_interval at
> > > > > all
> > > > > https://www.kernel.org/doc/html/latest/userspace-api/media/drivers/camera-sensor.html#frame-interval-configuration
> > > > >
> > > > > The question now is how to handle the backwards compatibility
> > > > > for
> > > > > any userspace app that might be using this driver and expecting
> > > > > to
> > > > > use the frame_interval calls.
> > > > > Seeing as it only ever allowed a fixed value of 30fps, leaving
> > > > > it
> > > > > as is with a comment as to why it is there would be reasonable
> > > > > in
> > > > > my view.
> > >
> > > Should the comment be added in this commit?
> > > And what exactly should the comment say?
> >
> > Add it to imx214_enum_frame_interval.
> > Something along the lines of:
> > Raw sensors should be using the VBLANK and HBLANK controls to
> > determine the frame rate. However this driver was initially added
> > using the [S|G|ENUM]_FRAME_INTERVAL ioctls with a fixed rate of
> > 30fps.
> > Retain the frame_interval ops for backwards compatibility, but they
> > do nothing.
> >
> > > > >
> > > > > > On Mon, Sep 2, 2024 at 11:53 PM André Apitzsch via B4 Relay
> > > > > > <devnull+git.apitzsch.eu@kernel.org> wrote:
> > > > > > >
> > > > > > > From: André Apitzsch <git@apitzsch.eu>
> > > > > > >
> > > > > > > Add vblank control to allow changing the framerate /
> > > > > > > higher exposure values.
> > > > > > >
> > > > > > > The vblank and hblank controls are needed for libcamera
> > > > > > > support.
> > > > > > >
> > > > > > > While at it, fix the minimal exposure time according to the
> > > > > > > datasheet.
> > > > > > >
> > > > > > > Signed-off-by: André Apitzsch <git@apitzsch.eu>
> > > > > > > ---
> > > > > > > drivers/media/i2c/imx214.c | 112
> > > > > > > ++++++++++++++++++++++++++++++++++++---------
> > > > > > > 1 file changed, 91 insertions(+), 21 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/media/i2c/imx214.c
> > > > > > > b/drivers/media/i2c/imx214.c
> > > > > > > index 3b422cddbdce..9f5a57aebb86 100644
> > > > > > > --- a/drivers/media/i2c/imx214.c
> > > > > > > +++ b/drivers/media/i2c/imx214.c
> > > > > > > @@ -34,11 +34,18 @@
> > > > > > >
> > > > > > > /* V-TIMING internal */
> > > > > > > #define IMX214_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
> > > > > > > +#define IMX214_VTS_MAX 0xffff
> > > > > > > +
> > > > > > > +#define IMX214_VBLANK_MIN 4
> > > > > > > +
> > > > > > > +/* HBLANK control - read only */
> > > > > > > +#define IMX214_PPL_DEFAULT 5008
> > > > > > >
> > > > > > > /* Exposure control */
> > > > > > > #define IMX214_REG_EXPOSURE CCI_REG16(0x0202)
> > > > > > > -#define IMX214_EXPOSURE_MIN 0
> > > > > > > -#define IMX214_EXPOSURE_MAX 3184
> > > > > > > +#define IMX214_EXPOSURE_OFFSET 10
> > > > > > > +#define IMX214_EXPOSURE_MIN 1
> > > > > > > +#define IMX214_EXPOSURE_MAX (IMX214_VTS_MAX -
> > > > > > > IMX214_EXPOSURE_OFFSET)
> > > > > > > #define IMX214_EXPOSURE_STEP 1
> > > > > > > #define IMX214_EXPOSURE_DEFAULT 3184
> > > > > > > #define IMX214_REG_EXPOSURE_RATIO CCI_REG8(0x0222)
> > > > > > > @@ -189,6 +196,8 @@ struct imx214 {
> > > > > > > struct v4l2_ctrl_handler ctrls;
> > > > > > > struct v4l2_ctrl *pixel_rate;
> > > > > > > struct v4l2_ctrl *link_freq;
> > > > > > > + struct v4l2_ctrl *vblank;
> > > > > > > + struct v4l2_ctrl *hblank;
> > > > > > > struct v4l2_ctrl *exposure;
> > > > > > > struct v4l2_ctrl *unit_size;
> > > > > > >
> > > > > > > @@ -205,8 +214,6 @@ static const struct cci_reg_sequence
> > > > > > > mode_4096x2304[] = {
> > > > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > > > { IMX214_REG_X_ADD_STA, 56 },
> > > > > > > { IMX214_REG_Y_ADD_STA, 408 },
> > > > > > > { IMX214_REG_X_ADD_END, 4151 },
> > > > > > > @@ -277,8 +284,6 @@ static const struct cci_reg_sequence
> > > > > > > mode_1920x1080[] = {
> > > > > > > { IMX214_REG_HDR_MODE, IMX214_HDR_MODE_OFF },
> > > > > > > { IMX214_REG_HDR_RES_REDUCTION,
> > > > > > > IMX214_HDR_RES_REDU_THROUGH },
> > > > > > > { IMX214_REG_EXPOSURE_RATIO, 1 },
> > > > > > > - { IMX214_REG_FRM_LENGTH_LINES, 3194 },
> > > > > > > - { IMX214_REG_LINE_LENGTH_PCK, 5008 },
> > > > > > > { IMX214_REG_X_ADD_STA, 1144 },
> > > > > > > { IMX214_REG_Y_ADD_STA, 1020 },
> > > > > > > { IMX214_REG_X_ADD_END, 3063 },
> > > > > > > @@ -362,6 +367,7 @@ static const struct cci_reg_sequence
> > > > > > > mode_table_common[] = {
> > > > > > > { IMX214_REG_ORIENTATION, 0 },
> > > > > > > { IMX214_REG_MASK_CORR_FRAMES,
> > > > > > > IMX214_CORR_FRAMES_MASK
> > > > > > > },
> > > > > > > { IMX214_REG_FAST_STANDBY_CTRL, 1 },
> > > > > > > + { IMX214_REG_LINE_LENGTH_PCK, IMX214_PPL_DEFAULT },
> > > > > > > { CCI_REG8(0x4550), 0x02 },
> > > > > > > { CCI_REG8(0x4601), 0x00 },
> > > > > > > { CCI_REG8(0x4642), 0x05 },
> > > > > > > @@ -465,18 +471,24 @@ static const struct cci_reg_sequence
> > > > > > > mode_table_common[] = {
> > > > > > > static const struct imx214_mode {
> > > > > > > u32 width;
> > > > > > > u32 height;
> > > > > > > +
> > > > > > > + /* V-timing */
> > > > > > > + unsigned int vts_def;
> > > > > > > +
> > > > > > > unsigned int num_of_regs;
> > > > > > > const struct cci_reg_sequence *reg_table;
> > > > > > > } imx214_modes[] = {
> > > > > > > {
> > > > > > > .width = 4096,
> > > > > > > .height = 2304,
> > > > > > > + .vts_def = 3194,
> > > > > > > .num_of_regs = ARRAY_SIZE(mode_4096x2304),
> > > > > > > .reg_table = mode_4096x2304,
> > > > > > > },
> > > > > > > {
> > > > > > > .width = 1920,
> > > > > > > .height = 1080,
> > > > > > > + .vts_def = 3194,
> > > > > > > .num_of_regs = ARRAY_SIZE(mode_1920x1080),
> > > > > > > .reg_table = mode_1920x1080,
> > > > > > > },
> > > > > > > @@ -629,6 +641,37 @@ static int imx214_set_format(struct
> > > > > > > v4l2_subdev *sd,
> > > > > > > __crop->width = mode->width;
> > > > > > > __crop->height = mode->height;
> > > > > > >
> > > > > > > + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
> > > > > > > + int exposure_max;
> > > > > > > + int exposure_def;
> > > > > > > + int hblank;
> > > > > > > +
> > > > > > > + /* Update limits and set FPS to default */
> > > > > > > + __v4l2_ctrl_modify_range(imx214->vblank,
> > > > > > > IMX214_VBLANK_MIN,
> > > > > > > + IMX214_VTS_MAX -
> > > > > > > mode-
> > > > > > > > height, 1,
> > > > > > > + mode->vts_def -
> > > > > > > mode-
> > > > > > > > height);
> > > > > > > + __v4l2_ctrl_s_ctrl(imx214->vblank,
> > > > > > > + mode->vts_def - mode-
> > > > > > > > height);
> > > > > > > +
> > > > > > > + /* Update max exposure while meeting
> > > > > > > expected
> > > > > > > vblanking */
> > > > > > > + exposure_max = mode->vts_def -
> > > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > > + exposure_def = (exposure_max <
> > > > > > > IMX214_EXPOSURE_DEFAULT) ?
> > > > > > > + exposure_max :
> > > > > > > IMX214_EXPOSURE_DEFAULT;
> > > > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > > > + imx214->exposure-
> > > > > > > > minimum,
> > > > > > > + exposure_max,
> > > > > > > imx214-
> > > > > > > > exposure->step,
> > > > > > > + exposure_def);
> > > > > > > +
> > > > > > > + /*
> > > > > > > + * Currently PPL is fixed to
> > > > > > > IMX214_PPL_DEFAULT, so hblank
> > > > > > > + * depends on mode->width only, and is not
> > > > > > > changeble in any
> > > > > > > + * way other than changing the mode.
> > > > > > > + */
> > > > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > > > + __v4l2_ctrl_modify_range(imx214->hblank,
> > > > > > > hblank, hblank, 1,
> > > > > > > + hblank);
> > > > > > > + }
> > > > > > > +
> > > > > > > return 0;
> > > > > > > }
> > > > > > >
> > > > > > > @@ -678,8 +721,25 @@ static int imx214_set_ctrl(struct
> > > > > > > v4l2_ctrl *ctrl)
> > > > > > > {
> > > > > > > struct imx214 *imx214 = container_of(ctrl->handler,
> > > > > > > struct imx214,
> > > > > > > ctrls);
> > > > > > > + const struct v4l2_mbus_framefmt *format;
> > > > > > > + struct v4l2_subdev_state *state;
> > > > > > > int ret;
> > > > > > >
> > > > > > > + state =
> > > > > > > v4l2_subdev_get_locked_active_state(&imx214-
> > > > > > > > sd);
> > > > > > > + format = v4l2_subdev_state_get_format(state, 0);
> > > > > > > +
> > > > > > > + if (ctrl->id == V4L2_CID_VBLANK) {
> > > > > > > + int exposure_max, exposure_def;
> > > > > > > +
> > > > > > > + /* Update max exposure while meeting
> > > > > > > expected
> > > > > > > vblanking */
> > > > > > > + exposure_max = format->height + ctrl->val -
> > > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > > + exposure_def = min(exposure_max,
> > > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > > + __v4l2_ctrl_modify_range(imx214->exposure,
> > > > > > > + imx214->exposure-
> > > > > > > > minimum,
> > > > > > > + exposure_max,
> > > > > > > imx214-
> > > > > > > > exposure->step,
> > > > > > > + exposure_def);
> > > > > > > + }
> > > > > > > +
> > > > > > > /*
> > > > > > > * Applying V4L2 control value only happens
> > > > > > > * when power is up for streaming
> > > > > > > @@ -691,7 +751,10 @@ static int imx214_set_ctrl(struct
> > > > > > > v4l2_ctrl *ctrl)
> > > > > > > case V4L2_CID_EXPOSURE:
> > > > > > > cci_write(imx214->regmap,
> > > > > > > IMX214_REG_EXPOSURE,
> > > > > > > ctrl->val, &ret);
> > > > > > > break;
> > > > > > > -
> > > > > > > + case V4L2_CID_VBLANK:
> > > > > > > + cci_write(imx214->regmap,
> > > > > > > IMX214_REG_FRM_LENGTH_LINES,
> > > > > > > + format->height + ctrl->val,
> > > > > > > &ret);
> > > > >
> > > > > My datasheet says this register is "set up in multiples of 2".
> > > > > (LINE_LENGTH_PCK for HBLANK is "set in multiples of 8")
> > > > >
> > > > > I don't have one of these modules, but is that saying only
> > > > > multiples
> > > > > of 2 are permitted (in which case the step size for the control
> > > > > needs
> > > > > to reflect that), or that setting a value of N is interpreted
> > > > > by
> > > > > the
> > > > > hardware as 2N?
> > > > > Do all the numbers with PIXEL_RATE work out correctly in the
> > > > > frame
> > > > > rate calcs?
> > > >
> > > > Answering my own question, PIXEL_RATE looks dubious.
> > > >
> > > > The original code had LINE_LENGTH_PCK as 5008, and
> > > > FRAME_LENGTH_LINES as 3194. If enum_frame_intervals is to be
> > > > believed, then it delivered 30fps.
> > > > 5008 * 3194 * 30 = 479,866,560 Pix/s.
> > > >
> > > > The driver defines IMX214_DEFAULT_LINK_FREQ 480000000, and then
> > > > IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) /
> > > > 10), which works out as 384MPix/s. (Presumably the 8 is 4 lanes
> > > > and DDR, but it's not obvious)
> > > >
> > > > Parsing the PLL registers with the defined 24MHz input. We're in
> > > > single PLL mode, so MIPI frequency is directly linked to pixel
> > > > rate.
> > > > VTCK ends up being 1200MHz, and VTPXCK and OPPXCK both are
> > > > 120MHz.
> > > > Section 5.3 "Frame rate calculation formula" says "Pixel rate
> > > > [pixels/s] = VTPXCK [MHz] * 4", so 120 * 4 = 480MPix/s, which
> > > > basically agrees with my number above.
> > > >
> > > > 3.1.4. MIPI global timing setting says "Output bitrate = OPPXCK *
> > > > reg 0x113[7:0]", so 120MHz * 10, or 1200Mbit/s. That would be a
> > > > link frequency of 600MHz due to DDR.
> > > > That also matches to 480MPix/s * 10bpp / 4 lanes / 2 for DDR
>
> Is it okay, if I use the three sections above for the commit message of
> the fix-link-frequency commit?
Fine by me.
> > > >
> > > > Registers 0x0820-0823 are meant to define the target CSI2
> > > > bitrate, and are set to 0x12c00000, or 314,572,800 decimal. I
> > > > can't get that to square with the above.
> > > >
>
> According the manual, the registers 0x0820-0823 represent an unsigned
> 32-bit real, where the first 16 bit seem to represent the integer part
> and the last 16 bit the fractional part. This means 0x12c00000 is
> 4800.0 Mbit/s, which is equal to 480MPix/s * 10bpp.
My datasheet doesn't appear to have the clarification, just that it is
"Target frequency (32-bit unsigned Real)".
Your numbers work out perfectly though, which is always a good thing.
> > > >
> > > > So my conclusion is that both PIXEL_RATE and LINK_FREQUENCY are
> > > > wrong, however the relationship used to define them looks to be
> > > > correct.
> > > > Correct IMX214_DEFAULT_LINK_FREQ to 600MHz, and all should be
> > > > good.
> > >
> > > Will do that. Should it be done in this commit or in a separat one?
> >
> > A separate one as it is independent of adding VBLANK and HBLANK
> > controls. Ideally it should come before this patch as then hopefully
> > everything actually works correctly when you add them.
> >
> > > > However you almost certainly want to set IMX214_VBLANK_MIN to
> > > > something significantly greater than 4.
> > >
> > > Any recommendation for the new IMX214_VBLANK_MIN value?
> >
> > As my comment below, the datasheet lists 30fps as the max frame rate
> > for full res, therefore IMX214_VBLANK_MIN being correct for that
> > seems reasonable. 890 appears to be the value for that, but I haven't
> > verified that all the numbers do then work out.
> >
> > Out of interest, what platform are you testing this on, and where are
> > you getting the sensor from? I'm always happy to tinker with sensors
> > that I can get working on a Pi, and I think the Arducam DepthAI Oak
> > module should work, but haven't picked one up yet.
>
> The sensor is part of my mobile phone[1], which I use for testing.
Fair enough.
> By the way, do you (or anyone else) happen to have the documentation
> for the Samsung s5k5e2?
No, I rarely see any information on Samsung sensors these days.
I may be totally misremembering, but I seem to recall the ones I did
deal with 10 years ago followed the CCS spec, so it might be worth
dumping registers to see if they do follow.
Dave
> André
>
>
> [1] https://wiki.postmarketos.org/wiki/BQ_Aquaris_M5_(bq-piccolo)
>
> >
> > Dave
> >
> > > Best regards,
> > > André
> > >
> > > >
> > > > Dave
> > > >
> > > > > Reading the spec sheet that 30fps is the max frame rate at full
> > > > > res
> > > > > (4096x2304), and the driver was setting a value of 3194 to this
> > > > > register, I don't see it being interpreted as 2N. Then again
> > > > > having
> > > > > VBLANK at 890 seems pretty high.
> > > > >
> > > > > > > + break;
> > > > > > > default:
> > > > > > > ret = -EINVAL;
> > > > > > > }
> > > > > > > @@ -714,8 +777,11 @@ static int imx214_ctrls_init(struct
> > > > > > > imx214
> > > > > > > *imx214)
> > > > > > > .width = 1120,
> > > > > > > .height = 1120,
> > > > > > > };
> > > > > > > + const struct imx214_mode *mode = &imx214_modes[0];
> > > > > > > struct v4l2_fwnode_device_properties props;
> > > > > > > struct v4l2_ctrl_handler *ctrl_hdlr;
> > > > > > > + int exposure_max, exposure_def;
> > > > > > > + int hblank;
> > > > > > > int ret;
> > > > > > >
> > > > > > > ret = v4l2_fwnode_device_parse(imx214->dev,
> > > > > > > &props);
> > > > > > > @@ -723,7 +789,7 @@ static int imx214_ctrls_init(struct
> > > > > > > imx214
> > > > > > > *imx214)
> > > > > > > return ret;
> > > > > > >
> > > > > > > ctrl_hdlr = &imx214->ctrls;
> > > > > > > - ret = v4l2_ctrl_handler_init(&imx214->ctrls, 6);
> > > > > > > + ret = v4l2_ctrl_handler_init(&imx214->ctrls, 8);
> > > > > > > if (ret)
> > > > > > > return ret;
> > > > > > >
> > > > > > > @@ -739,22 +805,26 @@ static int imx214_ctrls_init(struct
> > > > > > > imx214 *imx214)
> > > > > > > if (imx214->link_freq)
> > > > > > > imx214->link_freq->flags |=
> > > > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > > > >
> > > > > > > - /*
> > > > > > > - * WARNING!
> > > > > > > - * Values obtained reverse engineering blobs and/or
> > > > > > > devices.
> > > > > > > - * Ranges and functionality might be wrong.
> > > > > > > - *
> > > > > > > - * Sony, please release some register set
> > > > > > > documentation
> > > > > > > for the
> > > > > > > - * device.
> > > > > > > - *
> > > > > > > - * Yours sincerely, Ricardo.
> > > > > > > - */
> > > > > >
> > > > > > I would like to keep this comment until there is a public
> > > > > > document available.
> > > > >
> > > > > I suspect you'll be waiting forever for a document to be
> > > > > officially
> > > > > released.
> > > > >
> > > > > I have a datasheet for IMX214, and I believe Kieran and Jacopo
> > > > > do
> > > > > too.
> > > > > Which specific values do you wish to be verified?
> > > > >
> > > > > >
> > > > > > > + /* Initial vblank/hblank/exposure parameters based
> > > > > > > on
> > > > > > > current mode */
> > > > > > > + imx214->vblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > > &imx214_ctrl_ops,
> > > > > > > + V4L2_CID_VBLANK,
> > > > > > > IMX214_VBLANK_MIN,
> > > > >
> > > > > IMX214_VBLANK_MIN being 4 feels plausible, but pretty low.
> > > > > I read the datasheet to say there are 4 embedded data lines per
> > > > > image.
> > > > > Seeing as you have STATS data output enabled as well that makes
> > > > > 5
> > > > > lines of non-image data per frame, but you're only adding
> > > > > blanking
> > > > > time for 4 lines.
> > > > >
> > > > > As noted above, I think you've also increased the max frame
> > > > > rate
> > > > > significantly above that quoted by Sony. Has that been actually
> > > > > exercised and confirmed to function correctly?
> > > > >
> > > > > Dave
> > > > >
> > > > > > > + IMX214_VTS_MAX -
> > > > > > > mode->height, 1,
> > > > > > > + mode->vts_def -
> > > > > > > mode->height);
> > > > > > > +
> > > > > > > + hblank = IMX214_PPL_DEFAULT - mode->width;
> > > > > > > + imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > > &imx214_ctrl_ops,
> > > > > > > + V4L2_CID_HBLANK,
> > > > > > > hblank, hblank,
> > > > > > > + 1, hblank);
> > > > > > > + if (imx214->hblank)
> > > > > > > + imx214->hblank->flags |=
> > > > > > > V4L2_CTRL_FLAG_READ_ONLY;
> > > > > > > +
> > > > > > > + exposure_max = mode->vts_def -
> > > > > > > IMX214_EXPOSURE_OFFSET;
> > > > > > > + exposure_def = min(exposure_max,
> > > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > > imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr,
> > > > > > > &imx214_ctrl_ops,
> > > > > > >
> > > > > > > V4L2_CID_EXPOSURE,
> > > > > > > -
> > > > > > > IMX214_EXPOSURE_MIN,
> > > > > > > -
> > > > > > > IMX214_EXPOSURE_MAX,
> > > > > > > +
> > > > > > > IMX214_EXPOSURE_MIN, exposure_max,
> > > > > > >
> > > > > > > IMX214_EXPOSURE_STEP,
> > > > > > > -
> > > > > > > IMX214_EXPOSURE_DEFAULT);
> > > > > > > + exposure_def);
> > > > > > >
> > > > > > > imx214->unit_size =
> > > > > > > v4l2_ctrl_new_std_compound(ctrl_hdlr,
> > > > > > > NULL,
> > > > > > >
> > > > > > > --
> > > > > > > 2.46.0
> > > > > > >
> > > > > > >
> > > > > >
> > >
>
^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2024-10-14 12:17 UTC | newest]
Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-02 21:54 [PATCH 00/13] media: i2c: imx214: Miscellaneous cleanups and improvements André Apitzsch via B4 Relay
2024-09-02 21:54 ` [PATCH 01/13] media: i2c: imx214: Use subdev active state André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 02/13] media: i2c: imx214: Remove unneeded goto André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 03/13] media: i2c: imx214: Simplify with dev_err_probe() André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 04/13] media: i2c: imx214: Convert to CCI register access helpers André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 05/13] media: i2c: imx214: Replace register addresses with macros André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 06/13] media: i2c: imx214: Drop IMX214_REG_EXPOSURE from mode reg arrays André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 07/13] media: i2c: imx214: Use number of lanes from device tree André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 08/13] media: i2c: imx214: Add vblank and hblank controls André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-12 14:51 ` Dave Stevenson
2024-09-13 17:40 ` Dave Stevenson
2024-10-06 21:41 ` André
2024-10-07 17:29 ` Dave Stevenson
2024-10-12 21:45 ` André Apitzsch
2024-10-14 12:17 ` Dave Stevenson
2024-09-02 21:54 ` [PATCH 09/13] media: i2c: imx214: Extract format and crop settings André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-10-06 21:28 ` André
2024-09-02 21:54 ` [PATCH 10/13] media: i2c: imx214: Implement vflip/hflip controls André Apitzsch via B4 Relay
2024-09-12 13:40 ` Ricardo Ribalda Delgado
2024-09-12 15:16 ` Dave Stevenson
2024-09-02 21:54 ` [PATCH 11/13] media: i2c: imx214: Add analogue/digital gain control André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 12/13] media: i2c: imx214: Verify chip ID André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
2024-09-02 21:54 ` [PATCH 13/13] media: i2c: imx214: Add test pattern control André Apitzsch via B4 Relay
2024-09-12 13:39 ` Ricardo Ribalda Delgado
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox