Commit cb7e1c8d authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

media: i2c: imx290: Group functions in sections

Move functions around to group them in logical sections, in order to
improve readability. As a result, the IMX290_NUM_SUPPLIES macro has to
be changed. No other code change is included, only moves.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarAlexander Stein <alexander.stein@ew.tq-group.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 68453b02
...@@ -152,13 +152,7 @@ ...@@ -152,13 +152,7 @@
#define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920 #define IMX290_PIXEL_ARRAY_RECORDING_WIDTH 1920
#define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080 #define IMX290_PIXEL_ARRAY_RECORDING_HEIGHT 1080
static const char * const imx290_supply_name[] = { #define IMX290_NUM_SUPPLIES 3
"vdda",
"vddd",
"vdddo",
};
#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name)
struct imx290_regval { struct imx290_regval {
u32 reg; u32 reg;
...@@ -199,31 +193,14 @@ struct imx290 { ...@@ -199,31 +193,14 @@ struct imx290 {
struct mutex lock; struct mutex lock;
}; };
struct imx290_pixfmt { static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd)
u32 code; {
u8 bpp; return container_of(_sd, struct imx290, sd);
}; }
static const struct imx290_pixfmt imx290_formats[] = {
{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
};
static const struct regmap_config imx290_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
};
static const char * const imx290_test_pattern_menu[] = { /* -----------------------------------------------------------------------------
"Disabled", * Modes and formats
"Sequence Pattern 1", */
"Horizontal Color-bar Chart",
"Vertical Color-bar Chart",
"Sequence Pattern 2",
"Gradation Pattern 1",
"Gradation Pattern 2",
"000/555h Toggle Pattern",
};
static const struct imx290_regval imx290_global_init_settings[] = { static const struct imx290_regval imx290_global_init_settings[] = {
{ IMX290_CTRL_07, IMX290_WINMODE_1080P }, { IMX290_CTRL_07, IMX290_WINMODE_1080P },
...@@ -438,10 +415,19 @@ static inline int imx290_modes_num(const struct imx290 *imx290) ...@@ -438,10 +415,19 @@ static inline int imx290_modes_num(const struct imx290 *imx290)
return ARRAY_SIZE(imx290_modes_4lanes); return ARRAY_SIZE(imx290_modes_4lanes);
} }
static inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) struct imx290_pixfmt {
{ u32 code;
return container_of(_sd, struct imx290, sd); u8 bpp;
} };
static const struct imx290_pixfmt imx290_formats[] = {
{ MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
{ MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
};
/* -----------------------------------------------------------------------------
* Register access
*/
static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value) static int __always_unused imx290_read(struct imx290 *imx290, u32 addr, u32 *value)
{ {
...@@ -501,18 +487,94 @@ static int imx290_set_register_array(struct imx290 *imx290, ...@@ -501,18 +487,94 @@ static int imx290_set_register_array(struct imx290 *imx290,
return 0; return 0;
} }
/* Stop streaming */ static int imx290_set_data_lanes(struct imx290 *imx290)
static int imx290_stop_streaming(struct imx290 *imx290)
{ {
int ret = 0; int ret = 0, laneval, frsel;
imx290_write(imx290, IMX290_STANDBY, 0x01, &ret); switch (imx290->nlanes) {
case 2:
laneval = 0x01;
frsel = 0x02;
break;
case 4:
laneval = 0x03;
frsel = 0x01;
break;
default:
/*
* We should never hit this since the data lane count is
* validated in probe itself
*/
dev_err(imx290->dev, "Lane configuration not supported\n");
return -EINVAL;
}
msleep(30); imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret);
imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret);
imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret); return ret;
}
static int imx290_write_current_format(struct imx290 *imx290)
{
int ret;
switch (imx290->current_format.code) {
case MEDIA_BUS_FMT_SRGGB10_1X10:
ret = imx290_set_register_array(imx290, imx290_10bit_settings,
ARRAY_SIZE(
imx290_10bit_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set format registers\n");
return ret;
}
break;
case MEDIA_BUS_FMT_SRGGB12_1X12:
ret = imx290_set_register_array(imx290, imx290_12bit_settings,
ARRAY_SIZE(
imx290_12bit_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set format registers\n");
return ret;
}
break;
default:
dev_err(imx290->dev, "Unknown pixel format\n");
return -EINVAL;
}
return 0;
}
static inline u8 imx290_get_link_freq_index(struct imx290 *imx290)
{
return imx290->current_mode->link_freq_index;
}
static s64 imx290_get_link_freq(struct imx290 *imx290)
{
u8 index = imx290_get_link_freq_index(imx290);
return *(imx290_link_freqs_ptr(imx290) + index);
}
static u64 imx290_calc_pixel_rate(struct imx290 *imx290)
{
s64 link_freq = imx290_get_link_freq(imx290);
u8 nlanes = imx290->nlanes;
u64 pixel_rate;
/* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
pixel_rate = link_freq * 2 * nlanes;
do_div(pixel_rate, imx290->bpp);
return pixel_rate;
} }
/* ----------------------------------------------------------------------------
* Controls
*/
static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) static int imx290_set_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct imx290 *imx290 = container_of(ctrl->handler, struct imx290 *imx290 = container_of(ctrl->handler,
...@@ -566,89 +628,246 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = { ...@@ -566,89 +628,246 @@ static const struct v4l2_ctrl_ops imx290_ctrl_ops = {
.s_ctrl = imx290_set_ctrl, .s_ctrl = imx290_set_ctrl,
}; };
static struct v4l2_mbus_framefmt * static const char * const imx290_test_pattern_menu[] = {
imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state, "Disabled",
u32 which) "Sequence Pattern 1",
{ "Horizontal Color-bar Chart",
if (which == V4L2_SUBDEV_FORMAT_ACTIVE) "Vertical Color-bar Chart",
return &imx290->current_format; "Sequence Pattern 2",
else "Gradation Pattern 1",
return v4l2_subdev_get_try_format(&imx290->sd, state, 0); "Gradation Pattern 2",
} "000/555h Toggle Pattern",
};
static int imx290_enum_mbus_code(struct v4l2_subdev *sd, static int imx290_ctrl_init(struct imx290 *imx290)
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{ {
if (code->index >= ARRAY_SIZE(imx290_formats)) struct v4l2_fwnode_device_properties props;
return -EINVAL; unsigned int blank;
int ret;
code->code = imx290_formats[code->index].code; ret = v4l2_fwnode_device_parse(imx290->dev, &props);
if (ret < 0)
return ret;
return 0; v4l2_ctrl_handler_init(&imx290->ctrls, 9);
} imx290->ctrls.lock = &imx290->lock;
static int imx290_enum_frame_size(struct v4l2_subdev *sd, /*
struct v4l2_subdev_state *sd_state, * The sensor has an analog gain and a digital gain, both controlled
struct v4l2_subdev_frame_size_enum *fse) * through a single gain value, expressed in 0.3dB increments. Values
{ * from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
const struct imx290 *imx290 = to_imx290(sd); * up to 72.0dB (240) add further digital gain. Limit the range to
const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); * analog gain only, support for digital gain can be added separately
* if needed.
*
* The IMX327 and IMX462 are largely compatible with the IMX290, but
* have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
* gain. When support for those sensors gets added to the driver, the
* gain control should be adjusted accordingly.
*/
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
if ((fse->code != imx290_formats[0].code) && v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
(fse->code != imx290_formats[1].code)) V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
return -EINVAL; IMX290_VMAX_DEFAULT - 2);
if (fse->index >= imx290_modes_num(imx290)) imx290->link_freq =
return -EINVAL; v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_LINK_FREQ,
imx290_link_freqs_num(imx290) - 1, 0,
imx290_link_freqs_ptr(imx290));
if (imx290->link_freq)
imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
fse->min_width = imx290_modes[fse->index].width; imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
fse->max_width = imx290_modes[fse->index].width; V4L2_CID_PIXEL_RATE,
fse->min_height = imx290_modes[fse->index].height; 1, INT_MAX, 1,
fse->max_height = imx290_modes[fse->index].height; imx290_calc_pixel_rate(imx290));
return 0; v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
} V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx290_test_pattern_menu) - 1,
0, 0, imx290_test_pattern_menu);
static int imx290_get_fmt(struct v4l2_subdev *sd, blank = imx290->current_mode->hmax - imx290->current_mode->width;
struct v4l2_subdev_state *sd_state, imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
struct v4l2_subdev_format *fmt) V4L2_CID_HBLANK, blank, blank, 1,
{ blank);
struct imx290 *imx290 = to_imx290(sd); if (imx290->hblank)
struct v4l2_mbus_framefmt *framefmt; imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
mutex_lock(&imx290->lock); blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height;
imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_VBLANK, blank, blank, 1,
blank);
if (imx290->vblank)
imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which); v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
fmt->format = *framefmt; &props);
mutex_unlock(&imx290->lock); imx290->sd.ctrl_handler = &imx290->ctrls;
if (imx290->ctrls.error) {
ret = imx290->ctrls.error;
v4l2_ctrl_handler_free(&imx290->ctrls);
return ret;
}
return 0; return 0;
} }
static inline u8 imx290_get_link_freq_index(struct imx290 *imx290) /* ----------------------------------------------------------------------------
{ * Subdev operations
return imx290->current_mode->link_freq_index; */
}
static s64 imx290_get_link_freq(struct imx290 *imx290) /* Start streaming */
static int imx290_start_streaming(struct imx290 *imx290)
{ {
u8 index = imx290_get_link_freq_index(imx290); int ret;
return *(imx290_link_freqs_ptr(imx290) + index); /* Set init register settings */
ret = imx290_set_register_array(imx290, imx290_global_init_settings,
ARRAY_SIZE(
imx290_global_init_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set init registers\n");
return ret;
}
/* Apply the register values related to current frame format */
ret = imx290_write_current_format(imx290);
if (ret < 0) {
dev_err(imx290->dev, "Could not set frame format\n");
return ret;
}
/* Apply default values of current mode */
ret = imx290_set_register_array(imx290, imx290->current_mode->data,
imx290->current_mode->data_size);
if (ret < 0) {
dev_err(imx290->dev, "Could not set current mode\n");
return ret;
}
ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
NULL);
if (ret)
return ret;
/* Apply customized values from user */
ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
if (ret) {
dev_err(imx290->dev, "Could not sync v4l2 controls\n");
return ret;
}
imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
msleep(30);
/* Start streaming */
return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
} }
static u64 imx290_calc_pixel_rate(struct imx290 *imx290) /* Stop streaming */
static int imx290_stop_streaming(struct imx290 *imx290)
{ {
s64 link_freq = imx290_get_link_freq(imx290); int ret = 0;
u8 nlanes = imx290->nlanes;
u64 pixel_rate;
/* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ imx290_write(imx290, IMX290_STANDBY, 0x01, &ret);
pixel_rate = link_freq * 2 * nlanes;
do_div(pixel_rate, imx290->bpp); msleep(30);
return pixel_rate;
return imx290_write(imx290, IMX290_XMSTA, 0x01, &ret);
}
static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
{
struct imx290 *imx290 = to_imx290(sd);
int ret = 0;
if (enable) {
ret = pm_runtime_resume_and_get(imx290->dev);
if (ret < 0)
goto unlock_and_return;
ret = imx290_start_streaming(imx290);
if (ret) {
dev_err(imx290->dev, "Start stream failed\n");
pm_runtime_put(imx290->dev);
goto unlock_and_return;
}
} else {
imx290_stop_streaming(imx290);
pm_runtime_put(imx290->dev);
}
unlock_and_return:
return ret;
}
static struct v4l2_mbus_framefmt *
imx290_get_pad_format(struct imx290 *imx290, struct v4l2_subdev_state *state,
u32 which)
{
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
return &imx290->current_format;
else
return v4l2_subdev_get_try_format(&imx290->sd, state, 0);
}
static int imx290_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
if (code->index >= ARRAY_SIZE(imx290_formats))
return -EINVAL;
code->code = imx290_formats[code->index].code;
return 0;
}
static int imx290_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
const struct imx290 *imx290 = to_imx290(sd);
const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290);
if ((fse->code != imx290_formats[0].code) &&
(fse->code != imx290_formats[1].code))
return -EINVAL;
if (fse->index >= imx290_modes_num(imx290))
return -EINVAL;
fse->min_width = imx290_modes[fse->index].width;
fse->max_width = imx290_modes[fse->index].width;
fse->min_height = imx290_modes[fse->index].height;
fse->max_height = imx290_modes[fse->index].height;
return 0;
}
static int imx290_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx290 *imx290 = to_imx290(sd);
struct v4l2_mbus_framefmt *framefmt;
mutex_lock(&imx290->lock);
framefmt = imx290_get_pad_format(imx290, sd_state, fmt->which);
fmt->format = *framefmt;
mutex_unlock(&imx290->lock);
return 0;
} }
static int imx290_set_fmt(struct v4l2_subdev *sd, static int imx290_set_fmt(struct v4l2_subdev *sd,
...@@ -774,151 +993,31 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev, ...@@ -774,151 +993,31 @@ static int imx290_entity_init_cfg(struct v4l2_subdev *subdev,
return 0; return 0;
} }
static int imx290_write_current_format(struct imx290 *imx290) static const struct v4l2_subdev_video_ops imx290_video_ops = {
{ .s_stream = imx290_set_stream,
int ret; };
switch (imx290->current_format.code) {
case MEDIA_BUS_FMT_SRGGB10_1X10:
ret = imx290_set_register_array(imx290, imx290_10bit_settings,
ARRAY_SIZE(
imx290_10bit_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set format registers\n");
return ret;
}
break;
case MEDIA_BUS_FMT_SRGGB12_1X12:
ret = imx290_set_register_array(imx290, imx290_12bit_settings,
ARRAY_SIZE(
imx290_12bit_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set format registers\n");
return ret;
}
break;
default:
dev_err(imx290->dev, "Unknown pixel format\n");
return -EINVAL;
}
return 0;
}
/* Start streaming */
static int imx290_start_streaming(struct imx290 *imx290)
{
int ret;
/* Set init register settings */
ret = imx290_set_register_array(imx290, imx290_global_init_settings,
ARRAY_SIZE(
imx290_global_init_settings));
if (ret < 0) {
dev_err(imx290->dev, "Could not set init registers\n");
return ret;
}
/* Apply the register values related to current frame format */
ret = imx290_write_current_format(imx290);
if (ret < 0) {
dev_err(imx290->dev, "Could not set frame format\n");
return ret;
}
/* Apply default values of current mode */
ret = imx290_set_register_array(imx290, imx290->current_mode->data,
imx290->current_mode->data_size);
if (ret < 0) {
dev_err(imx290->dev, "Could not set current mode\n");
return ret;
}
ret = imx290_write(imx290, IMX290_HMAX, imx290->current_mode->hmax,
NULL);
if (ret)
return ret;
/* Apply customized values from user */
ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler);
if (ret) {
dev_err(imx290->dev, "Could not sync v4l2 controls\n");
return ret;
}
imx290_write(imx290, IMX290_STANDBY, 0x00, &ret);
msleep(30);
/* Start streaming */
return imx290_write(imx290, IMX290_XMSTA, 0x00, &ret);
}
static int imx290_set_stream(struct v4l2_subdev *sd, int enable)
{
struct imx290 *imx290 = to_imx290(sd);
int ret = 0;
if (enable) {
ret = pm_runtime_resume_and_get(imx290->dev);
if (ret < 0)
goto unlock_and_return;
ret = imx290_start_streaming(imx290);
if (ret) {
dev_err(imx290->dev, "Start stream failed\n");
pm_runtime_put(imx290->dev);
goto unlock_and_return;
}
} else {
imx290_stop_streaming(imx290);
pm_runtime_put(imx290->dev);
}
unlock_and_return:
return ret;
}
static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++) static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
imx290->supplies[i].supply = imx290_supply_name[i]; .init_cfg = imx290_entity_init_cfg,
.enum_mbus_code = imx290_enum_mbus_code,
.enum_frame_size = imx290_enum_frame_size,
.get_fmt = imx290_get_fmt,
.set_fmt = imx290_set_fmt,
.get_selection = imx290_get_selection,
};
return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies), static const struct v4l2_subdev_ops imx290_subdev_ops = {
imx290->supplies); .video = &imx290_video_ops,
} .pad = &imx290_pad_ops,
};
static int imx290_set_data_lanes(struct imx290 *imx290) static const struct media_entity_operations imx290_subdev_entity_ops = {
{ .link_validate = v4l2_subdev_link_validate,
int ret = 0, laneval, frsel; };
switch (imx290->nlanes) { /* ----------------------------------------------------------------------------
case 2: * Power management
laneval = 0x01;
frsel = 0x02;
break;
case 4:
laneval = 0x03;
frsel = 0x01;
break;
default:
/*
* We should never hit this since the data lane count is
* validated in probe itself
*/ */
dev_err(imx290->dev, "Lane configuration not supported\n");
return -EINVAL;
}
imx290_write(imx290, IMX290_PHY_LANE_NUM, laneval, &ret);
imx290_write(imx290, IMX290_CSI_LANE_MODE, laneval, &ret);
imx290_write(imx290, IMX290_FR_FDG_SEL, frsel, &ret);
return ret;
}
static int imx290_power_on(struct device *dev) static int imx290_power_on(struct device *dev)
{ {
...@@ -966,105 +1065,30 @@ static const struct dev_pm_ops imx290_pm_ops = { ...@@ -966,105 +1065,30 @@ static const struct dev_pm_ops imx290_pm_ops = {
SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL)
}; };
static const struct v4l2_subdev_video_ops imx290_video_ops = { /* ----------------------------------------------------------------------------
.s_stream = imx290_set_stream, * Probe & remove
}; */
static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
.init_cfg = imx290_entity_init_cfg,
.enum_mbus_code = imx290_enum_mbus_code,
.enum_frame_size = imx290_enum_frame_size,
.get_fmt = imx290_get_fmt,
.set_fmt = imx290_set_fmt,
.get_selection = imx290_get_selection,
};
static const struct v4l2_subdev_ops imx290_subdev_ops = { static const struct regmap_config imx290_regmap_config = {
.video = &imx290_video_ops, .reg_bits = 16,
.pad = &imx290_pad_ops, .val_bits = 8,
}; };
static const struct media_entity_operations imx290_subdev_entity_ops = { static const char * const imx290_supply_name[IMX290_NUM_SUPPLIES] = {
.link_validate = v4l2_subdev_link_validate, "vdda",
"vddd",
"vdddo",
}; };
static int imx290_ctrl_init(struct imx290 *imx290) static int imx290_get_regulators(struct device *dev, struct imx290 *imx290)
{ {
struct v4l2_fwnode_device_properties props; unsigned int i;
unsigned int blank;
int ret;
ret = v4l2_fwnode_device_parse(imx290->dev, &props);
if (ret < 0)
return ret;
v4l2_ctrl_handler_init(&imx290->ctrls, 9);
imx290->ctrls.lock = &imx290->lock;
/*
* The sensor has an analog gain and a digital gain, both controlled
* through a single gain value, expressed in 0.3dB increments. Values
* from 0.0dB (0) to 30.0dB (100) apply analog gain only, higher values
* up to 72.0dB (240) add further digital gain. Limit the range to
* analog gain only, support for digital gain can be added separately
* if needed.
*
* The IMX327 and IMX462 are largely compatible with the IMX290, but
* have an analog gain range of 0.0dB to 29.4dB and 42dB of digital
* gain. When support for those sensors gets added to the driver, the
* gain control should be adjusted accordingly.
*/
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_ANALOGUE_GAIN, 0, 100, 1, 0);
v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_EXPOSURE, 1, IMX290_VMAX_DEFAULT - 2, 1,
IMX290_VMAX_DEFAULT - 2);
imx290->link_freq =
v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_LINK_FREQ,
imx290_link_freqs_num(imx290) - 1, 0,
imx290_link_freqs_ptr(imx290));
if (imx290->link_freq)
imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_PIXEL_RATE,
1, INT_MAX, 1,
imx290_calc_pixel_rate(imx290));
v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx290_test_pattern_menu) - 1,
0, 0, imx290_test_pattern_menu);
blank = imx290->current_mode->hmax - imx290->current_mode->width;
imx290->hblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_HBLANK, blank, blank, 1,
blank);
if (imx290->hblank)
imx290->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
blank = IMX290_VMAX_DEFAULT - imx290->current_mode->height;
imx290->vblank = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops,
V4L2_CID_VBLANK, blank, blank, 1,
blank);
if (imx290->vblank)
imx290->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
v4l2_ctrl_new_fwnode_properties(&imx290->ctrls, &imx290_ctrl_ops,
&props);
imx290->sd.ctrl_handler = &imx290->ctrls;
if (imx290->ctrls.error) { for (i = 0; i < ARRAY_SIZE(imx290->supplies); i++)
ret = imx290->ctrls.error; imx290->supplies[i].supply = imx290_supply_name[i];
v4l2_ctrl_handler_free(&imx290->ctrls);
return ret;
}
return 0; return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx290->supplies),
imx290->supplies);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment