Commit d03dfb7d authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Hans Verkuil

media: i2c: imx219: Group functions by purpose

Move functions around to group them by purpose, in order to improve
readability. No functional change is intended.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarDave Stevenson <dave.stevenson@raspberrypi.com>
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
parent 5ebbdd7a
...@@ -385,6 +385,10 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code) ...@@ -385,6 +385,10 @@ static u32 imx219_get_format_code(struct imx219 *imx219, u32 code)
return imx219_mbus_formats[i]; return imx219_mbus_formats[i];
} }
/* -----------------------------------------------------------------------------
* Controls
*/
static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) static int imx219_set_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct imx219 *imx219 = struct imx219 *imx219 =
...@@ -476,129 +480,134 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = { ...@@ -476,129 +480,134 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = {
.s_ctrl = imx219_set_ctrl, .s_ctrl = imx219_set_ctrl,
}; };
static void imx219_update_pad_format(struct imx219 *imx219, static unsigned long imx219_get_pixel_rate(struct imx219 *imx219)
const struct imx219_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
{ {
/* Bayer order varies with flips */ return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE;
fmt->code = imx219_get_format_code(imx219, code);
fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_RAW;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
} }
static int imx219_init_cfg(struct v4l2_subdev *sd, /* Initialize control handlers */
struct v4l2_subdev_state *state) static int imx219_init_controls(struct imx219 *imx219)
{ {
struct imx219 *imx219 = to_imx219(sd); struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
struct v4l2_mbus_framefmt *format; const struct imx219_mode *mode = &supported_modes[0];
struct v4l2_rect *crop; struct v4l2_ctrl_handler *ctrl_hdlr;
struct v4l2_fwnode_device_properties props;
int exposure_max, exposure_def, hblank;
int i, ret;
/* Initialize the format. */ ctrl_hdlr = &imx219->ctrl_handler;
format = v4l2_subdev_get_pad_format(sd, state, 0); ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
imx219_update_pad_format(imx219, &supported_modes[0], format, if (ret)
MEDIA_BUS_FMT_SRGGB10_1X10); return ret;
/* Initialize the crop rectangle. */ /* By default, PIXEL_RATE is read only */
crop = v4l2_subdev_get_pad_crop(sd, state, 0); imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
crop->top = IMX219_PIXEL_ARRAY_TOP; V4L2_CID_PIXEL_RATE,
crop->left = IMX219_PIXEL_ARRAY_LEFT; imx219_get_pixel_rate(imx219),
crop->width = IMX219_PIXEL_ARRAY_WIDTH; imx219_get_pixel_rate(imx219), 1,
crop->height = IMX219_PIXEL_ARRAY_HEIGHT; imx219_get_pixel_rate(imx219));
return 0; imx219->link_freq =
} v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
(imx219->lanes == 2) ? imx219_link_freq_menu :
imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
static int imx219_enum_mbus_code(struct v4l2_subdev *sd, /* Initial vblank/hblank/exposure parameters based on current mode */
struct v4l2_subdev_state *sd_state, imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
struct v4l2_subdev_mbus_code_enum *code) V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
{ IMX219_VTS_MAX - mode->height, 1,
struct imx219 *imx219 = to_imx219(sd); mode->vts_def - mode->height);
hblank = IMX219_PPL_DEFAULT - mode->width;
imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HBLANK, hblank, hblank,
1, hblank);
if (imx219->hblank)
imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_EXPOSURE,
IMX219_EXPOSURE_MIN, exposure_max,
IMX219_EXPOSURE_STEP,
exposure_def);
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
return -EINVAL; IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
return 0; imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
} V4L2_CID_HFLIP, 0, 1, 1, 0);
if (imx219->hflip)
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
static int imx219_enum_frame_size(struct v4l2_subdev *sd, imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
struct v4l2_subdev_state *sd_state, V4L2_CID_VFLIP, 0, 1, 1, 0);
struct v4l2_subdev_frame_size_enum *fse) if (imx219->vflip)
{ imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
struct imx219 *imx219 = to_imx219(sd);
u32 code;
if (fse->index >= ARRAY_SIZE(supported_modes)) v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
return -EINVAL; V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(imx219_test_pattern_menu) - 1,
0, 0, imx219_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, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN_RED + i,
IMX219_TESTP_COLOUR_MIN,
IMX219_TESTP_COLOUR_MAX,
IMX219_TESTP_COLOUR_STEP,
IMX219_TESTP_COLOUR_MAX);
/* The "Solid color" pattern is white by default */
}
code = imx219_get_format_code(imx219, fse->code); if (ctrl_hdlr->error) {
if (fse->code != code) ret = ctrl_hdlr->error;
return -EINVAL; dev_err(&client->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
fse->min_width = supported_modes[fse->index].width; ret = v4l2_fwnode_device_parse(&client->dev, &props);
fse->max_width = fse->min_width; if (ret)
fse->min_height = supported_modes[fse->index].height; goto error;
fse->max_height = fse->min_height;
return 0; ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops,
} &props);
if (ret)
goto error;
static int imx219_set_pad_format(struct v4l2_subdev *sd, imx219->sd.ctrl_handler = ctrl_hdlr;
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
struct imx219 *imx219 = to_imx219(sd);
const struct imx219_mode *mode;
int exposure_max, exposure_def, hblank;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
mode = v4l2_find_nearest_size(supported_modes, return 0;
ARRAY_SIZE(supported_modes),
width, height,
fmt->format.width, fmt->format.height);
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); error:
v4l2_ctrl_handler_free(ctrl_hdlr);
format = v4l2_subdev_get_pad_format(sd, sd_state, 0); return ret;
crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); }
*format = fmt->format; static void imx219_free_controls(struct imx219 *imx219)
*crop = mode->crop; {
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
}
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* -----------------------------------------------------------------------------
/* Update limits and set FPS to default */ * Subdev operations
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
__v4l2_ctrl_s_ctrl(imx219->vblank,
mode->vts_def - mode->height);
/* Update max exposure while meeting expected vblanking */
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
__v4l2_ctrl_modify_range(imx219->exposure,
imx219->exposure->minimum,
exposure_max, imx219->exposure->step,
exposure_def);
/*
* Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
* depends on mode->width only, and is not changeble in any
* way other than changing the mode.
*/ */
hblank = IMX219_PPL_DEFAULT - mode->width;
__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
hblank);
}
return 0;
}
static int imx219_set_framefmt(struct imx219 *imx219, static int imx219_set_framefmt(struct imx219 *imx219,
struct v4l2_subdev_state *state) struct v4l2_subdev_state *state)
...@@ -664,37 +673,6 @@ static int imx219_set_framefmt(struct imx219 *imx219, ...@@ -664,37 +673,6 @@ static int imx219_set_framefmt(struct imx219 *imx219,
return ret; return ret;
} }
static int imx219_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
}
case V4L2_SEL_TGT_NATIVE_SIZE:
sel->r.top = 0;
sel->r.left = 0;
sel->r.width = IMX219_NATIVE_WIDTH;
sel->r.height = IMX219_NATIVE_HEIGHT;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r.top = IMX219_PIXEL_ARRAY_TOP;
sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0;
}
return -EINVAL;
}
static int imx219_configure_lanes(struct imx219 *imx219) static int imx219_configure_lanes(struct imx219 *imx219)
{ {
return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE, return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE,
...@@ -799,86 +777,159 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) ...@@ -799,86 +777,159 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable)
return ret; return ret;
} }
/* Power/clock management functions */ static void imx219_update_pad_format(struct imx219 *imx219,
static int imx219_power_on(struct device *dev) const struct imx219_mode *mode,
struct v4l2_mbus_framefmt *fmt, u32 code)
{ {
struct v4l2_subdev *sd = dev_get_drvdata(dev); /* Bayer order varies with flips */
struct imx219 *imx219 = to_imx219(sd); fmt->code = imx219_get_format_code(imx219, code);
int ret; fmt->width = mode->width;
fmt->height = mode->height;
fmt->field = V4L2_FIELD_NONE;
fmt->colorspace = V4L2_COLORSPACE_RAW;
fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_XFER_FUNC_NONE;
}
ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, static int imx219_init_cfg(struct v4l2_subdev *sd,
imx219->supplies); struct v4l2_subdev_state *state)
if (ret) { {
dev_err(dev, "%s: failed to enable regulators\n", struct imx219 *imx219 = to_imx219(sd);
__func__); struct v4l2_mbus_framefmt *format;
return ret; struct v4l2_rect *crop;
}
ret = clk_prepare_enable(imx219->xclk); /* Initialize the format. */
if (ret) { format = v4l2_subdev_get_pad_format(sd, state, 0);
dev_err(dev, "%s: failed to enable clock\n", imx219_update_pad_format(imx219, &supported_modes[0], format,
__func__); MEDIA_BUS_FMT_SRGGB10_1X10);
goto reg_off;
}
gpiod_set_value_cansleep(imx219->reset_gpio, 1); /* Initialize the crop rectangle. */
usleep_range(IMX219_XCLR_MIN_DELAY_US, crop = v4l2_subdev_get_pad_crop(sd, state, 0);
IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); crop->top = IMX219_PIXEL_ARRAY_TOP;
crop->left = IMX219_PIXEL_ARRAY_LEFT;
crop->width = IMX219_PIXEL_ARRAY_WIDTH;
crop->height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0; return 0;
reg_off:
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
return ret;
} }
static int imx219_power_off(struct device *dev) static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{ {
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd); struct imx219 *imx219 = to_imx219(sd);
gpiod_set_value_cansleep(imx219->reset_gpio, 0); if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); return -EINVAL;
clk_disable_unprepare(imx219->xclk);
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
return 0; return 0;
} }
static int imx219_get_regulators(struct imx219 *imx219) static int imx219_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); struct imx219 *imx219 = to_imx219(sd);
unsigned int i; u32 code;
for (i = 0; i < IMX219_NUM_SUPPLIES; i++) if (fse->index >= ARRAY_SIZE(supported_modes))
imx219->supplies[i].supply = imx219_supply_name[i]; return -EINVAL;
return devm_regulator_bulk_get(&client->dev, code = imx219_get_format_code(imx219, fse->code);
IMX219_NUM_SUPPLIES, if (fse->code != code)
imx219->supplies); return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
fse->max_width = fse->min_width;
fse->min_height = supported_modes[fse->index].height;
fse->max_height = fse->min_height;
return 0;
} }
/* Verify chip ID */ static int imx219_set_pad_format(struct v4l2_subdev *sd,
static int imx219_identify_module(struct imx219 *imx219) struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); struct imx219 *imx219 = to_imx219(sd);
int ret; const struct imx219_mode *mode;
u64 val; int exposure_max, exposure_def, hblank;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL); mode = v4l2_find_nearest_size(supported_modes,
if (ret) { ARRAY_SIZE(supported_modes),
dev_err(&client->dev, "failed to read chip id %x\n", width, height,
IMX219_CHIP_ID); fmt->format.width, fmt->format.height);
return ret;
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
format = v4l2_subdev_get_pad_format(sd, sd_state, 0);
crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0);
*format = fmt->format;
*crop = mode->crop;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Update limits and set FPS to default */
__v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN,
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
__v4l2_ctrl_s_ctrl(imx219->vblank,
mode->vts_def - mode->height);
/* Update max exposure while meeting expected vblanking */
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
__v4l2_ctrl_modify_range(imx219->exposure,
imx219->exposure->minimum,
exposure_max, imx219->exposure->step,
exposure_def);
/*
* Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank
* depends on mode->width only, and is not changeble in any
* way other than changing the mode.
*/
hblank = IMX219_PPL_DEFAULT - mode->width;
__v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1,
hblank);
} }
if (val != IMX219_CHIP_ID) { return 0;
dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", }
IMX219_CHIP_ID, val);
return -EIO; static int imx219_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
} }
case V4L2_SEL_TGT_NATIVE_SIZE:
sel->r.top = 0;
sel->r.left = 0;
sel->r.width = IMX219_NATIVE_WIDTH;
sel->r.height = IMX219_NATIVE_HEIGHT;
return 0;
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
sel->r.top = IMX219_PIXEL_ARRAY_TOP;
sel->r.left = IMX219_PIXEL_ARRAY_LEFT;
sel->r.width = IMX219_PIXEL_ARRAY_WIDTH;
sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT;
return 0; return 0;
}
return -EINVAL;
} }
static const struct v4l2_subdev_core_ops imx219_core_ops = { static const struct v4l2_subdev_core_ops imx219_core_ops = {
...@@ -906,129 +957,93 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = { ...@@ -906,129 +957,93 @@ static const struct v4l2_subdev_ops imx219_subdev_ops = {
}; };
static unsigned long imx219_get_pixel_rate(struct imx219 *imx219) /* -----------------------------------------------------------------------------
{ * Power management
return (imx219->lanes == 2) ? IMX219_PIXEL_RATE : IMX219_PIXEL_RATE_4LANE; */
}
/* Initialize control handlers */ static int imx219_power_on(struct device *dev)
static int imx219_init_controls(struct imx219 *imx219)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); struct v4l2_subdev *sd = dev_get_drvdata(dev);
const struct imx219_mode *mode = &supported_modes[0]; struct imx219 *imx219 = to_imx219(sd);
struct v4l2_ctrl_handler *ctrl_hdlr; int ret;
struct v4l2_fwnode_device_properties props;
int exposure_max, exposure_def, hblank;
int i, ret;
ctrl_hdlr = &imx219->ctrl_handler; ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES,
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); imx219->supplies);
if (ret) if (ret) {
dev_err(dev, "%s: failed to enable regulators\n",
__func__);
return ret; return ret;
}
/* By default, PIXEL_RATE is read only */ ret = clk_prepare_enable(imx219->xclk);
imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, if (ret) {
V4L2_CID_PIXEL_RATE, dev_err(dev, "%s: failed to enable clock\n",
imx219_get_pixel_rate(imx219), __func__);
imx219_get_pixel_rate(imx219), 1, goto reg_off;
imx219_get_pixel_rate(imx219)); }
imx219->link_freq =
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_LINK_FREQ,
ARRAY_SIZE(imx219_link_freq_menu) - 1, 0,
(imx219->lanes == 2) ? imx219_link_freq_menu :
imx219_link_freq_4lane_menu);
if (imx219->link_freq)
imx219->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* Initial vblank/hblank/exposure parameters based on current mode */ gpiod_set_value_cansleep(imx219->reset_gpio, 1);
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, usleep_range(IMX219_XCLR_MIN_DELAY_US,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN, IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
IMX219_VTS_MAX - mode->height, 1,
mode->vts_def - mode->height);
hblank = IMX219_PPL_DEFAULT - mode->width;
imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_HBLANK, hblank, hblank,
1, hblank);
if (imx219->hblank)
imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
exposure_max = mode->vts_def - 4;
exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ?
exposure_max : IMX219_EXPOSURE_DEFAULT;
imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_EXPOSURE,
IMX219_EXPOSURE_MIN, exposure_max,
IMX219_EXPOSURE_STEP,
exposure_def);
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, return 0;
IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, reg_off:
IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, return ret;
V4L2_CID_HFLIP, 0, 1, 1, 0); }
if (imx219->hflip)
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, static int imx219_power_off(struct device *dev)
V4L2_CID_VFLIP, 0, 1, 1, 0); {
if (imx219->vflip) struct v4l2_subdev *sd = dev_get_drvdata(dev);
imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; struct imx219 *imx219 = to_imx219(sd);
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, gpiod_set_value_cansleep(imx219->reset_gpio, 0);
V4L2_CID_TEST_PATTERN, regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
ARRAY_SIZE(imx219_test_pattern_menu) - 1, clk_disable_unprepare(imx219->xclk);
0, 0, imx219_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, &imx219_ctrl_ops,
V4L2_CID_TEST_PATTERN_RED + i,
IMX219_TESTP_COLOUR_MIN,
IMX219_TESTP_COLOUR_MAX,
IMX219_TESTP_COLOUR_STEP,
IMX219_TESTP_COLOUR_MAX);
/* The "Solid color" pattern is white by default */
}
if (ctrl_hdlr->error) { return 0;
ret = ctrl_hdlr->error; }
dev_err(&client->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
ret = v4l2_fwnode_device_parse(&client->dev, &props); /* -----------------------------------------------------------------------------
if (ret) * Probe & remove
goto error; */
ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, static int imx219_get_regulators(struct imx219 *imx219)
&props); {
if (ret) struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
goto error; unsigned int i;
imx219->sd.ctrl_handler = ctrl_hdlr; for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
imx219->supplies[i].supply = imx219_supply_name[i];
return 0; return devm_regulator_bulk_get(&client->dev,
IMX219_NUM_SUPPLIES,
imx219->supplies);
}
error: /* Verify chip ID */
v4l2_ctrl_handler_free(ctrl_hdlr); static int imx219_identify_module(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
int ret;
u64 val;
ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL);
if (ret) {
dev_err(&client->dev, "failed to read chip id %x\n",
IMX219_CHIP_ID);
return ret; return ret;
} }
static void imx219_free_controls(struct imx219 *imx219) if (val != IMX219_CHIP_ID) {
{ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); IMX219_CHIP_ID, val);
return -EIO;
}
return 0;
} }
static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219) static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
......
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