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,130 +480,135 @@ static const struct v4l2_ctrl_ops imx219_ctrl_ops = { ...@@ -476,130 +480,135 @@ 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;
/* Initialize the format. */ int exposure_max, exposure_def, hblank;
format = v4l2_subdev_get_pad_format(sd, state, 0); int i, ret;
imx219_update_pad_format(imx219, &supported_modes[0], format,
MEDIA_BUS_FMT_SRGGB10_1X10);
/* Initialize the crop rectangle. */
crop = v4l2_subdev_get_pad_crop(sd, state, 0);
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; ctrl_hdlr = &imx219->ctrl_handler;
} ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
if (ret)
return ret;
static int imx219_enum_mbus_code(struct v4l2_subdev *sd, /* By default, PIXEL_RATE is read only */
struct v4l2_subdev_state *sd_state, imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
struct v4l2_subdev_mbus_code_enum *code) V4L2_CID_PIXEL_RATE,
{ imx219_get_pixel_rate(imx219),
struct imx219 *imx219 = to_imx219(sd); imx219_get_pixel_rate(imx219), 1,
imx219_get_pixel_rate(imx219));
if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4)) imx219->link_freq =
return -EINVAL; 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;
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]); /* Initial vblank/hblank/exposure parameters based on current mode */
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
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);
return 0; v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
} IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX,
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
static int imx219_enum_frame_size(struct v4l2_subdev *sd, v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
struct v4l2_subdev_state *sd_state, IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX,
struct v4l2_subdev_frame_size_enum *fse) IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
{
struct imx219 *imx219 = to_imx219(sd);
u32 code;
if (fse->index >= ARRAY_SIZE(supported_modes)) imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
return -EINVAL; V4L2_CID_HFLIP, 0, 1, 1, 0);
if (imx219->hflip)
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
code = imx219_get_format_code(imx219, fse->code); imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
if (fse->code != code) V4L2_CID_VFLIP, 0, 1, 1, 0);
return -EINVAL; if (imx219->vflip)
imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
fse->min_width = supported_modes[fse->index].width; v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops,
fse->max_width = fse->min_width; V4L2_CID_TEST_PATTERN,
fse->min_height = supported_modes[fse->index].height; ARRAY_SIZE(imx219_test_pattern_menu) - 1,
fse->max_height = fse->min_height; 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 */
}
return 0; if (ctrl_hdlr->error) {
} ret = ctrl_hdlr->error;
dev_err(&client->dev, "%s control init failed (%d)\n",
__func__, ret);
goto error;
}
static int imx219_set_pad_format(struct v4l2_subdev *sd, ret = v4l2_fwnode_device_parse(&client->dev, &props);
struct v4l2_subdev_state *sd_state, if (ret)
struct v4l2_subdev_format *fmt) goto error;
{
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, ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops,
ARRAY_SIZE(supported_modes), &props);
width, height, if (ret)
fmt->format.width, fmt->format.height); goto error;
imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); imx219->sd.ctrl_handler = ctrl_hdlr;
format = v4l2_subdev_get_pad_format(sd, sd_state, 0); return 0;
crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0);
*format = fmt->format; error:
*crop = mode->crop; v4l2_ctrl_handler_free(ctrl_hdlr);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { return ret;
/* 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);
}
return 0; static void imx219_free_controls(struct imx219 *imx219)
{
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
} }
/* -----------------------------------------------------------------------------
* Subdev operations
*/
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: static int imx219_enum_mbus_code(struct v4l2_subdev *sd,
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
struct imx219 *imx219 = to_imx219(sd);
return ret; if (code->index >= (ARRAY_SIZE(imx219_mbus_formats) / 4))
return -EINVAL;
code->code = imx219_get_format_code(imx219, imx219_mbus_formats[code->index * 4]);
return 0;
} }
static int imx219_power_off(struct device *dev) static int imx219_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{ {
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct imx219 *imx219 = to_imx219(sd); struct imx219 *imx219 = to_imx219(sd);
u32 code;
gpiod_set_value_cansleep(imx219->reset_gpio, 0); if (fse->index >= ARRAY_SIZE(supported_modes))
regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); return -EINVAL;
clk_disable_unprepare(imx219->xclk);
code = imx219_get_format_code(imx219, fse->code);
if (fse->code != code)
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; return 0;
} }
static int imx219_get_regulators(struct imx219 *imx219) static int imx219_set_pad_format(struct v4l2_subdev *sd,
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);
unsigned int i; const struct imx219_mode *mode;
int exposure_max, exposure_def, hblank;
struct v4l2_mbus_framefmt *format;
struct v4l2_rect *crop;
for (i = 0; i < IMX219_NUM_SUPPLIES; i++) mode = v4l2_find_nearest_size(supported_modes,
imx219->supplies[i].supply = imx219_supply_name[i]; ARRAY_SIZE(supported_modes),
width, height,
fmt->format.width, fmt->format.height);
return devm_regulator_bulk_get(&client->dev, imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code);
IMX219_NUM_SUPPLIES,
imx219->supplies); 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);
}
return 0;
} }
/* Verify chip ID */ static int imx219_get_selection(struct v4l2_subdev *sd,
static int imx219_identify_module(struct imx219 *imx219) struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); switch (sel->target) {
int ret; case V4L2_SEL_TGT_CROP: {
u64 val; sel->r = *v4l2_subdev_get_pad_crop(sd, sd_state, 0);
return 0;
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;
} }
if (val != IMX219_CHIP_ID) { case V4L2_SEL_TGT_NATIVE_SIZE:
dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", sel->r.top = 0;
IMX219_CHIP_ID, val); sel->r.left = 0;
return -EIO; 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 = gpiod_set_value_cansleep(imx219->reset_gpio, 1);
v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx219_ctrl_ops, usleep_range(IMX219_XCLR_MIN_DELAY_US,
V4L2_CID_LINK_FREQ, IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US);
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 */ return 0;
imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops,
V4L2_CID_VBLANK, IMX219_VBLANK_MIN,
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, reg_off:
IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT);
v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, return ret;
IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, }
IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT);
imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, static int imx219_power_off(struct device *dev)
V4L2_CID_HFLIP, 0, 1, 1, 0); {
if (imx219->hflip) struct v4l2_subdev *sd = dev_get_drvdata(dev);
imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; struct imx219 *imx219 = to_imx219(sd);
imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, gpiod_set_value_cansleep(imx219->reset_gpio, 0);
V4L2_CID_VFLIP, 0, 1, 1, 0); regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies);
if (imx219->vflip) clk_disable_unprepare(imx219->xclk);
imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, return 0;
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 */
}
if (ctrl_hdlr->error) { /* -----------------------------------------------------------------------------
ret = ctrl_hdlr->error; * Probe & remove
dev_err(&client->dev, "%s control init failed (%d)\n", */
__func__, ret);
goto error;
}
ret = v4l2_fwnode_device_parse(&client->dev, &props); static int imx219_get_regulators(struct imx219 *imx219)
if (ret) {
goto error; struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
unsigned int i;
ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, for (i = 0; i < IMX219_NUM_SUPPLIES; i++)
&props); imx219->supplies[i].supply = imx219_supply_name[i];
if (ret)
goto error;
imx219->sd.ctrl_handler = ctrl_hdlr; return devm_regulator_bulk_get(&client->dev,
IMX219_NUM_SUPPLIES,
imx219->supplies);
}
return 0; /* Verify chip ID */
static int imx219_identify_module(struct imx219 *imx219)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd);
int ret;
u64 val;
error: ret = cci_read(imx219->regmap, IMX219_REG_CHIP_ID, &val, NULL);
v4l2_ctrl_handler_free(ctrl_hdlr); if (ret) {
dev_err(&client->dev, "failed to read chip id %x\n",
IMX219_CHIP_ID);
return ret;
}
return ret; if (val != IMX219_CHIP_ID) {
} dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
IMX219_CHIP_ID, val);
return -EIO;
}
static void imx219_free_controls(struct imx219 *imx219) return 0;
{
v4l2_ctrl_handler_free(imx219->sd.ctrl_handler);
} }
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